diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d1ee5d8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + pull_request: + branches: + - main + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + env: + DATABASE_URL: ${{secrets.DATABASE_URL}} + NEXTAUTH_SECRET: ${{secrets.NEXTAUTH_SECRET}} + STACKBY_SECRET_KEY: ${{secrets.STACKBY_SECRET_KEY}} + STACKBY_BASE_URL: ${{secrets.STACKBY_BASE_URL}} + CACHE_ENABLED: ${{secrets.CACHE_ENABLED}} + CACHE_TTL: ${{secrets.CACHE_TTL}} + UPSTASH_REDIS_REST_URL: ${{secrets.UPSTASH_REDIS_REST_URL}} + UPSTASH_REDIS_REST_TOKEN: ${{secrets.UPSTASH_REDIS_REST_TOKEN}} + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + + + + + diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml deleted file mode 100644 index 0e88c88..0000000 --- a/.github/workflows/development.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: E-acelera - -on: - pull_request: - types: [opened, reopened] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Set up Node.js - uses: actions/setup-node@v2 - with: - node-version: 20 - - - name: Install dependencies - run: npm install - - - name: Build - run: npm run build - - - name: Lint - run: npm run lint diff --git a/.github/workflows/homolog-deploy.yml b/.github/workflows/homolog-deploy.yml new file mode 100644 index 0000000..fd240c6 --- /dev/null +++ b/.github/workflows/homolog-deploy.yml @@ -0,0 +1,40 @@ +name: Homolog Deploy + +on: + push: + branches: + - main + +concurrency: + group: homolog-deploy-${{ github.ref }} + cancel-in-progress: true + +jobs: + deploy: + runs-on: ubuntu-latest + environment: + name: homolog + url: https://homolog-e-acelera-back.vercel.app/ + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "20" + + - name: Install Dependencies + run: npm install --legacy-peer-deps + + - name: Build + run: npm run build + + - name: Deploy to Homolog + run: | + echo "Commit from main being deployed: $(git rev-parse origin/main)" + echo "Vercel will handle the build & deployment." + echo "Check Vercel dashboard for deployment status at: https://vercel.com/aceleradora-agils-projects/e-acelera-back/deployments?environment=preview" diff --git a/.github/workflows/prod-deploy.yml b/.github/workflows/prod-deploy.yml new file mode 100644 index 0000000..93a05cb --- /dev/null +++ b/.github/workflows/prod-deploy.yml @@ -0,0 +1,44 @@ +name: Production Deploy + +on: + workflow_dispatch: + +concurrency: + group: prod + cancel-in-progress: true + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Sync staging branch with main + run: | + git config user.name "eacelera-back-deploy-bot[bot]" + git config user.email "eacelera-back-deploy-bot[bot]@users.noreply.github.com" + + git fetch origin + + if git ls-remote --exit-code --heads origin staging; then + git checkout -B staging origin/staging + else + git checkout -B staging + fi + + git reset --hard origin/main + git push origin staging --force + env: + TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Deploy to production + run: | + echo "Starting production deploy..." + echo "Commit from main being deployed: $(git rev-parse origin/main)" + echo "Vercel will handle the build & deployment." + echo "Check Vercel dashboard for deployment status at: https://vercel.com/aceleradora-agils-projects/e-acelera-back/deployments?environment=production" + diff --git a/.gitignore b/.gitignore index fd3dbb5..e8bbd39 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +# See https:help.github.com/articles/ignoring-files/ for more about ignoring files. + # dependencies /node_modules @@ -15,6 +16,7 @@ # production /build +/dist # misc .DS_Store @@ -26,6 +28,7 @@ yarn-debug.log* yarn-error.log* # local env files +.env* .env*.local # vercel @@ -34,3 +37,6 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# editor +.vscode diff --git a/README.md b/README.md new file mode 100644 index 0000000..21fe0ce --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# Instruções de Configuração do Projeto + +### Passos iniciais: + +1. Execute o comando para instalar as dependências do projeto: + ```bash + npm install + ``` + +2. Crie um banco de dados PostgreSQL no DBeaver ou PgAdmin com o nome **eacelera-dev**. + +3. Na raiz do projeto, crie um arquivo `.env`. + +4. Adicione a seguinte variável de ambiente ao arquivo `.env` para configurar a conexão com o banco de dados: + ```env + DATABASE_URL=postgres://{seu_usuario}:{sua_senha}@localhost:5432/eacelera-dev + ``` + Substitua `{seu_usuario}` e `{sua_senha}` pelos seus dados de acesso ao banco no DBeaver ou PgAdmin. + +--- + +# Gerenciamento de Migrações + +### Aplicar migrações no ambiente local: + +- Para aplicar as migrações pendentes no banco de dados de desenvolvimento local, use o comando: + ```bash + npx prisma migrate dev + ``` + +### Aplicar migrações no ambiente de Staging: + +- Para aplicar migrações no banco de dados do ambiente de staging, utilize: + ```bash + npx prisma migrate deploy + ``` + +# Criar Migrações + +- Para gerar uma nova migração no ambiente local, use o seguinte comando, substituindo `{nome_da_migracao}` por uma descrição da migração: + ```bash + npx prisma migrate dev --name {nome_da_migracao} + ``` + + **Importante:** + - Sempre crie as migrações localmente, na sua branch de desenvolvimento. + - Nunca crie ou aplique migrações diretamente na branch de staging. + - Certifique-se de que o diretório `prisma/migrations` seja comitado no repositório Git após a criação das migrações. + +# Deploy BACKEND: (Vercel) +### Etapas: feature → main → staging + +1. Atualizar a branch main local +```bash +git checkout main +git pull origin main +``` +2. Criar PR da feature para main (no GitHub) + +- Vá até o GitHub > Pull Requests > New Pull Request. +- Base: main | Compare: feature/nome-da-sua-branch +- Escreva o título e descrição do que foi feito. +- Após aprovação do time, clique em Merge pull request > Confirm merge. + +### Obs: +Deploy no Vercel (automaticamente após merge na main): Vercel detecta mudanças na branch main e faz o deploy no ambiente configurado (staging). + +### Para acompanhar: +- Acesse: https://vercel.com/dashboard +- Clique no projeto e-acelera-back +- Veja a aba Deploys e abra o log se necessário + +3. Atualizar a branch staging com o código da main +```bash +git checkout staging +git pull origin staging +git merge main +git push origin staging +``` +### Obs: +Embora o Vercel use main para deploy, manter staging atualizado garante padronização e controle de histórico. + +4. Verificar se está no ar +- Acesse:https://e-acelera-back.vercel.app/ +- Teste endpoints e rotas. +- Valide se a funcionalidade foi publicada corretamente. +- Se tudo estiver ok, o card pode ser movido para PRONTO (não há produção separada). diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..e762f6c --- /dev/null +++ b/biome.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", + "assist": { + "actions": { + "recommended": true, + "source": { + "organizeImports": "on", + "useSortedKeys": "on" + } + } + }, + "files": { + "includes": ["./src/**/*.ts"] + }, + "formatter": { + "attributePosition": "auto", + "enabled": true, + "formatWithErrors": false, + "indentStyle": "tab", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 80 + }, + "javascript": { + "formatter": { + "arrowParentheses": "always", + "bracketSameLine": false, + "bracketSpacing": true, + "enabled": true, + "jsxQuoteStyle": "double", + "quoteProperties": "asNeeded", + "semicolons": "always", + "trailingCommas": "all" + }, + "linter": { + "enabled": true + } + }, + "json": { + "formatter": { + "enabled": true, + "trailingCommas": "none" + } + }, + "linter": { + "rules": { + "style": { + "useImportType": "on" + }, + "suspicious": "warn" + } + }, + "root": true +} diff --git a/client.ts b/client.ts new file mode 100644 index 0000000..63f8bbd --- /dev/null +++ b/client.ts @@ -0,0 +1,4 @@ +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); +export default prisma; diff --git a/env-example b/env-example new file mode 100644 index 0000000..a2e10cc --- /dev/null +++ b/env-example @@ -0,0 +1,19 @@ +DB_USER= +DB_PASSWORD= +DB_NAME= +DB_HOST= +DB_PORT= + +DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME} + +NEXTAUTH_SECRET= +STACKBY_SECRET_KEY= +STACKBY_BASE_URL= + +CACHE_ENABLED=FALSE +CACHE_TTL=28800 +UPSTASH_REDIS_REST_URL= +UPSTASH_REDIS_REST_TOKEN= + +FLAGSMITH_SERVER_KEY= +NODE_ENV=development \ No newline at end of file diff --git a/jest.config.cjs b/jest.config.cjs new file mode 100644 index 0000000..e0cc9e6 --- /dev/null +++ b/jest.config.cjs @@ -0,0 +1,21 @@ +// const { pathsToModuleNameMapper } = require('ts-jest'); +// const { compilerOptions } = require('./tsconfig.json'); + +/** @type {import("ts-jest").JestConfigWithTsJest} */ +module.exports = { + preset: "ts-jest/presets/default-esm", + testEnvironment: "node", + extensionsToTreatAsEsm: [".ts"], + transform: { + "^.+\\.ts?$": ["ts-jest", { + useESM: true, + diagnostics: { + ignoreCodes: [151002] + } + }], + }, + + moduleNameMapper: { + "^(\\.{1,2}/.*)\\.js$": "$1", + }, +}; \ No newline at end of file diff --git a/jest.setup.ts b/jest.setup.ts new file mode 100644 index 0000000..fded23a --- /dev/null +++ b/jest.setup.ts @@ -0,0 +1 @@ +import "reflect-metadata"; diff --git a/package-lock.json b/package-lock.json index 1d82a15..a1f9b3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,1591 +1,10226 @@ { - "name": "e-acelera-backend", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "e-acelera-backend", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "express": "^4.19.2", - "husky": "^9.0.11", - "nodemon": "^3.1.1" - }, - "devDependencies": { - "@types/express": "^4.17.21", - "tsx": "^4.11.0", - "typescript": "^5.4.5" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.1.tgz", - "integrity": "sha512-ej0phymbFLoCB26dbbq5PGScsf2JAJ4IJHjG10LalgUV36XKTmA4GdA+PVllKvRk0sEKt64X8975qFnkSi0hqA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", - "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", - "dev": true, - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/husky": { - "version": "9.0.11", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", - "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", - "license": "MIT", - "bin": { - "husky": "bin.mjs" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/nodemon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.1.tgz", - "integrity": "sha512-k43xGaDtaDIcufn0Fc6fTtsdKSkV/hQzoQFigNH//GaKta28yoKVYXCnV+KXRqfT/YzsFaQU9VdeEG+HEyxr6A==", - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/nodemon/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/touch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", - "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/tsx": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.11.0.tgz", - "integrity": "sha512-vzGGELOgAupsNVssAmZjbUDfdm/pWP4R+Kg8TVdsonxbXk0bEpE1qh0yV6/QxUVXaVlNemgcPajGdJJ82n3stg==", - "dev": true, - "dependencies": { - "esbuild": "~0.20.2", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - } - } + "name": "e-acelera-backend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "e-acelera-backend", + "version": "1.0.0", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "@fast-csv/parse": "^5.0.5", + "@prisma/client": "^6.19.0", + "@upstash/redis": "^1.35.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.2", + "connect-pg-simple": "^10.0.0", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.17.1", + "fast-csv": "^5.0.5", + "flagsmith-nodejs": "^6.1.0", + "husky": "^9.0.11", + "jose": "^5.9.6", + "jsonwebtoken": "^9.0.2", + "node-mocks-http": "^1.17.2", + "nodemon": "^3.1.1", + "pg": "^8.16.3", + "pg-hstore": "^2.3.4", + "prisma": "^6.19.0", + "reflect-metadata": "^0.2.2" + }, + "devDependencies": { + "@faker-js/faker": "^9.9.0", + "@jest-mock/express": "^3.0.0", + "@prisma/client": "^6.18.0", + "@types/connect-pg-simple": "^7.0.3", + "@types/cors": "^2.8.17", + "@types/express": "^5.0.3", + "@types/express-session": "^1.18.2", + "@types/jest": "^29.5.14", + "@types/jsonwebtoken": "^9.0.7", + "@types/mocha": "^10.0.10", + "@types/node": "^24.7.0", + "jest": "^29.7.0", + "jest-mock-extended": "^4.0.0-beta1", + "prisma": "^6.19.0", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2", + "tsx": "^4.11.0", + "typescript": "^5.4.5" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@faker-js/faker": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.9.0.tgz", + "integrity": "sha512-OEl393iCOoo/z8bMezRlJu+GlRGlsKbUAN7jKB6LhnKoqKve5DXRpalbItIIcwnCjs1k/FOPjFzcA6Qn+H+YbA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0.0", + "npm": ">=9.0.0" + } + }, + "node_modules/@fast-csv/format": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-5.0.5.tgz", + "integrity": "sha512-0P9SJXXnqKdmuWlLaTelqbrfdgN37Mvrb369J6eNmqL41IEIZQmV4sNM4GgAK2Dz3aH04J0HKGDMJFkYObThTw==", + "license": "MIT", + "dependencies": { + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + } + }, + "node_modules/@fast-csv/parse": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-5.0.5.tgz", + "integrity": "sha512-M0IbaXZDbxfOnpVE5Kps/a6FGlILLhtLsvWd9qNH3d2TxNnpbNkFf3KD26OmJX6MHq7PdQAl5htStDwnuwHx6w==", + "license": "MIT", + "dependencies": { + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest-mock/express": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@jest-mock/express/-/express-3.0.0.tgz", + "integrity": "sha512-omOl6bh4EOUbp9bvcPSBZKaG8nAtBlhVSUhLx0brHrNpEDn+fMtQp58NkhdY3OoUfXjb7go/EcSYwk+H1BVLdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "^5.0.0" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/console/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/core/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/core/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/core/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", + "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "expect": "30.2.0", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", + "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "30.2.0", + "@sinonjs/fake-timers": "^13.0.0", + "@types/node": "*", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", + "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/types": "30.2.0", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@jest/reporters/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/reporters/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", + "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/transform/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@jest/transform/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@prisma/client": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.19.0.tgz", + "integrity": "sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.0.tgz", + "integrity": "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.18.4", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.0.tgz", + "integrity": "sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.0.tgz", + "integrity": "sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/fetch-engine": "6.19.0", + "@prisma/get-platform": "6.19.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773.tgz", + "integrity": "sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.0.tgz", + "integrity": "sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0", + "@prisma/engines-version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773", + "@prisma/get-platform": "6.19.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.0.tgz", + "integrity": "sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.19.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-pg-simple": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/connect-pg-simple/-/connect-pg-simple-7.0.3.tgz", + "integrity": "sha512-NGCy9WBlW2bw+J/QlLnFZ9WjoGs6tMo3LAut6mY4kK+XHzue//lpNVpAvYRpIwM969vBRAM2Re0izUvV6kt+NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/express-session": "*", + "@types/pg": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.5.tgz", + "integrity": "sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", + "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express-session": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.18.2.tgz", + "integrity": "sha512-k+I0BxwVXsnEU2hV77cCobC08kIsn4y44C3gC0b46uxZVMaXA04lSPgRLR/bSL2w0t0ShJiG8o4jPzRG/nscFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jest/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@types/jest/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/pg": { + "version": "8.15.6", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.6.tgz", + "integrity": "sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/validator": { + "version": "13.15.10", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", + "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/@upstash/redis": { + "version": "1.35.6", + "resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.35.6.tgz", + "integrity": "sha512-aSEIGJgJ7XUfTYvhQcQbq835re7e/BXjs8Janq6Pvr6LlmTZnyqwT97RziZLO/8AVUL037RLXqqiQC6kCt+5pA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.29.tgz", + "integrity": "sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/c12/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001755", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz", + "integrity": "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", + "license": "MIT" + }, + "node_modules/class-validator": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.2.tgz", + "integrity": "sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw==", + "license": "MIT", + "dependencies": { + "@types/validator": "^13.11.8", + "libphonenumber-js": "^1.11.1", + "validator": "^13.9.0" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/connect-pg-simple": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/connect-pg-simple/-/connect-pg-simple-10.0.0.tgz", + "integrity": "sha512-pBGVazlqiMrackzCr0eKhn4LO5trJXsOX0nQoey9wCOayh80MYtThCbq8eoLsjpiWgiok/h+1/uti9/2/Una8A==", + "license": "MIT", + "dependencies": { + "pg": "^8.12.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=22.0.0" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-jest/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", + "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.255", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.255.tgz", + "integrity": "sha512-Z9oIp4HrFF/cZkDPMpz2XSuVpc1THDpT4dlmATFlJUIBVCy9Vap5/rIXsASP1CscBacBqhabwh8vLctqBwEerQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/express/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fast-csv": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-5.0.5.tgz", + "integrity": "sha512-9//QpogDIPln5Dc8e3Q3vbSSLXlTeU7z1JqsUOXZYOln8EIn/OOO8+NS2c3ukR6oYngDd3+P1HXSkby3kNV9KA==", + "license": "MIT", + "dependencies": { + "@fast-csv/format": "5.0.5", + "@fast-csv/parse": "5.0.5" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flagsmith-nodejs": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/flagsmith-nodejs/-/flagsmith-nodejs-6.1.0.tgz", + "integrity": "sha512-MCPsZajSvdJQBLJtxsMqkNbL1sfPDbG8jeZQQuOY9w6ov5BE7wCelBir7jNMu+CjhPY1NpdZfTp4PkQAFLISOg==", + "license": "MIT", + "dependencies": { + "pino": "^8.8.0", + "semver": "^7.3.7", + "undici-types": "^6.19.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/flagsmith-nodejs/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/flagsmith-nodejs/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "license": "ISC" + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-report/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-changed-files/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-circus/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/jest-circus/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-circus/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-circus/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-cli/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest-config/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-config/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-each/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-environment-node/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-environment-node/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-haste-map/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-haste-map/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock-extended": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jest-mock-extended/-/jest-mock-extended-4.0.0.tgz", + "integrity": "sha512-7BZpfuvLam+/HC+NxifIi9b+5VXj/utUDMPUqrDJehGWVuXPtLS9Jqlob2mJLrI/pg2k1S8DMfKDvEB88QNjaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-essentials": "^10.0.2" + }, + "peerDependencies": { + "@jest/globals": "^28.0.0 || ^29.0.0 || ^30.0.0", + "jest": "^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0 || ^30.0.0", + "typescript": "^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-resolve-dependencies/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-resolve-dependencies/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-resolve/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-resolve/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-runner/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-runner/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-runtime/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-runtime/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest-runtime/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-runtime/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-runtime/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", + "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "pretty-format": "30.2.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/transform": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", + "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-snapshot/node_modules/jest-haste-map": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", + "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "micromatch": "^4.0.8", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" + } + }, + "node_modules/jest-snapshot/node_modules/jest-worker": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", + "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.2.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-snapshot/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-watcher/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-worker/node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest/node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/libphonenumber-js": { + "version": "1.12.26", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.26.tgz", + "integrity": "sha512-MagMOuqEXB2Pa90cWE+BoCmcKJx+de5uBIicaUkQ+uiEslZ0OBMNOkSZT/36syXNHu68UeayTxPm3DYM2IHoLQ==", + "license": "MIT" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "license": "MIT" + }, + "node_modules/lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-mocks-http": { + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/node-mocks-http/-/node-mocks-http-1.17.2.tgz", + "integrity": "sha512-HVxSnjNzE9NzoWMx9T9z4MLqwMpLwVvA0oVZ+L+gXskYXEJ6tFn3Kx4LargoB6ie7ZlCLplv7QbWO6N+MysWGA==", + "license": "MIT", + "dependencies": { + "accepts": "^1.3.7", + "content-disposition": "^0.5.3", + "depd": "^1.1.0", + "fresh": "^0.5.2", + "merge-descriptors": "^1.0.1", + "methods": "^1.1.2", + "mime": "^1.3.4", + "parseurl": "^1.3.3", + "range-parser": "^1.2.0", + "type-is": "^1.6.18" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@types/express": "^4.17.21 || ^5.0.0", + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + }, + "@types/node": { + "optional": true + } + } + }, + "node_modules/node-mocks-http/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz", + "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nypm": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "dev": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/pg": { + "version": "8.16.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", + "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.9.1", + "pg-pool": "^3.10.1", + "pg-protocol": "^1.10.3", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.2.7" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz", + "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz", + "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==", + "license": "MIT" + }, + "node_modules/pg-hstore": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.4.tgz", + "integrity": "sha512-N3SGs/Rf+xA1M2/n0JBiXFDVMzdekwLZLAO0g7mpDY9ouX+fDI7jS6kTq3JujmYbtNSJ53TJ0q4G98KVZSM4EA==", + "license": "MIT", + "dependencies": { + "underscore": "^1.13.1" + }, + "engines": { + "node": ">= 0.8.x" + } + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz", + "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz", + "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz", + "integrity": "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.2.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.7.0", + "thread-stream": "^2.6.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "license": "MIT", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-abstract-transport/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", + "license": "MIT" + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prisma": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.0.tgz", + "integrity": "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.19.0", + "@prisma/engines": "6.19.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "license": "MIT" + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sonic-boom": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", + "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/thread-stream": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", + "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/ts-essentials": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-10.1.1.tgz", + "integrity": "sha512-4aTB7KLHKmUvkjNj8V+EdnmuVTiECzn3K+zIbRthumvHu+j44x3w63xpfs0JL3NGIzGXqoQ7AV591xHO+XrOTw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/ts-jest": { + "version": "29.4.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz", + "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "license": "MIT" + }, + "node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/validator": { + "version": "13.15.23", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.23.tgz", + "integrity": "sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } } diff --git a/package.json b/package.json index cebb357..f52c1b0 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,63 @@ { - "name": "e-acelera-backend", - "version": "1.0.0", - "description": "A backend repository for e-acelera project", - "type": "module", - "main": "src/index.ts", - "scripts": { - "start": "npx tsx src/index.ts", - "dev": "nodemon src/index.ts", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "daniellemadrid, barbaraanger, aceleradora-TW/teams/turma-25", - "license": "ISC", - "dependencies": { - "express": "^4.19.2", - "husky": "^9.0.11", - "nodemon": "^3.1.1" - }, - "devDependencies": { - "@types/express": "^4.17.21", - "tsx": "^4.11.0", - "typescript": "^5.4.5" - } -} + "name": "e-acelera-backend", + "version": "1.0.0", + "description": "A backend repository for e-acelera project", + "main": "src/index.ts", + "type": "module", + "scripts": { + "db:seed": "prisma db seed", + "start": "npx tsx src/index.ts", + "dev": "nodemon --watch src --exec tsx src/index.ts", + "build": "npx prisma@6 migrate deploy", + "test": "jest", + "test:coverage": "jest --coverage", + "postinstall": "npx prisma@6 generate" + }, + "prisma": { + "seed": "node prisma/seed.js" + }, + "author": "daniellemadrid, barbaraanger, aceleradora-TW/teams/turma-25", + "license": "ISC", + "dependencies": { + "@fast-csv/parse": "^5.0.5", + "@prisma/client": "^6.19.0", + "@upstash/redis": "^1.35.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.2", + "connect-pg-simple": "^10.0.0", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.17.1", + "fast-csv": "^5.0.5", + "flagsmith-nodejs": "^6.1.0", + "husky": "^9.0.11", + "jose": "^5.9.6", + "jsonwebtoken": "^9.0.2", + "node-mocks-http": "^1.17.2", + "nodemon": "^3.1.1", + "pg": "^8.16.3", + "pg-hstore": "^2.3.4", + "prisma": "^6.19.0", + "reflect-metadata": "^0.2.2" + }, + "devDependencies": { + "@faker-js/faker": "^9.9.0", + "@jest-mock/express": "^3.0.0", + "@prisma/client": "^6.18.0", + "@types/connect-pg-simple": "^7.0.3", + "@types/cors": "^2.8.17", + "@types/express": "^5.0.3", + "@types/express-session": "^1.18.2", + "@types/jest": "^29.5.14", + "@types/jsonwebtoken": "^9.0.7", + "@types/mocha": "^10.0.10", + "@types/node": "^24.7.0", + "jest": "^29.7.0", + "jest-mock-extended": "^4.0.0-beta1", + "prisma": "^6.19.0", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2", + "tsx": "^4.11.0", + "typescript": "^5.4.5" + } +} \ No newline at end of file diff --git a/prisma/data/exercises.csv b/prisma/data/exercises.csv new file mode 100644 index 0000000..3585949 --- /dev/null +++ b/prisma/data/exercises.csv @@ -0,0 +1,3340 @@ +title,cardDescription,description,topics,idExercises +Conversão de polegadas para centímetros,Quinto exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + + + +Implemente o método `tabelaConversao`, que gera uma tabela de conversão de polegadas para centímetros de 1 a 20. Considere que 1 polegada é igual a 2.54 centímetros. + + + +- O método deve gerar e exibir uma tabela de conversão. + + + +## Exemplos: + + + +- A tabela gerada para polegadas de 1 a 3 seria: + + - 1 pol = 2.54 cm + + - 2 pol = 5.08 cm + + - 3 pol = 7.62 cm + +- A tabela gerada para polegadas de 1 a 5 seria: + + - 1 pol = 2.54 cm + + - 2 pol = 5.08 cm + + - 3 pol = 7.62 cm + + - 4 pol = 10.16 cm + + - 5 pol = 12.7 cm + +",Repetição (Typescript: Lógica de Programação),rw1751554485263b2fea7 +Divisibilidade entre dois números,Sexto exercício da lista com o objetivo de aprofundar o aprendizado," **O problema:** + + + + Crie uma função chamada verificarDivisibilidade que receba dois números inteiros: a e b. A função deve verificar se o número a é divisível por b e retornar uma mensagem indicando o resultado. + + + +## Exemplos: + + + +verificarDivisibilidade(10, 2); + + + +Entrada: 10 e 2 → Saída: ""10 é divisível por 2"" + + + +verificarDivisibilidade(10, 3); + + + +Entrada: 10 e 3 → Saída: ""10 não é divisível por 3"" + + + +verificarDivisibilidade(20, 5); + + + +Entrada: 20 e 5 → Saída: ""20 é divisível por 5"" + + + +",Condicionais (Typescript: Lógica de Programação),rw175155278352465b47e +Exibir números ímpares entre M e N,Segundo exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + + + +Implemente o método `mostrarImparesEntreMeN`, que recebe dois valores numéricos inteiros M e N e exibe apenas os números ímpares no intervalo de M a N. + + + +- O método deve iterar de M até N e exibir apenas os números ímpares. + + + +## Exemplos: + + + +- Para a entrada `M = 3` e `N = 10`, a saída deve ser: `3, 5, 7, 9`. + +- Para a entrada `M = 15` e `N = 20`, a saída deve ser: `15, 17, 19`. + +- Para a entrada `M = 1` e `N = 5`, a saída deve ser: `1, 3, 5`. + + + +",Repetição (Typescript: Lógica de Programação),rw17515539124722dfb74 +Ordem descendente,Nono exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + + + + Crie uma função chamada ordenarDescendente que receba três números inteiros. A função deve retornar os três valores em ordem decrescente. + + + +## Exemplos: + + + +ordenarDescendente(3, 1, 2); + + + +Entrada: 3, 1, 2 → Saída: ""3, 2, 1"" + + + +ordenarDescendente(5, 8, 2); + + + +Entrada: 5, 8, 2 → Saída: ""8, 5, 2"" + +",Condicionais (Typescript: Lógica de Programação),rw1751552876958039585 +Vetor pares dobro e impares triplo,Primeiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Implemente um método que leia um vetor de 30 números inteiros e gere um segundo vetor. As posições pares devem ser o dobro do vetor original, e as ímpares, o triplo. + +- O método deve percorrer os 30 números inteiros do vetor. +- Se a posição for par, o valor será multiplicado por 2. +- Se a posição for ímpar, o valor será multiplicado por 3. + +### Exemplo: + +- Quando a entrada for `[1, 2, 3, 4, 5]`, a saída deve ser `[3, 4, 9, 8, 15]`. + +",Array Simples,rw1727886436829261856 +Vetores positivos negativos,Primeiro exercício da lista com o objetivo de aprofundar o aprendizado," **O problema:** + + + +Crie um método que preencha um vetor com 8 números inteiros e, a partir dele, separe os números em dois novos vetores: um para positivos e outro para negativos. (Zero deve ser considerado positivo). + + + +- O método deve percorrer os 8 números do vetor original. + +- Positivos e zero devem ser adicionados a um vetor. + +- Números negativos devem ser adicionados a outro vetor. + + + +### Exemplo: + + + +- Quando a entrada for `[-1, 0, 2, -3, 4, -5]`, a saída deve ser: + + - Positivos: `[0, 2, 4]` + + - Negativos: `[-1, -3, -5]`. + +"," Array simples (Typescript: Lógica de Programação)",rw1751553325597a32e1b +Adicionando Elementos Multimídia,Adicione imagens e vídeos à sua página. Torne seu conteúdo mais interativo e envolvente,"**Objetivo** + +Nesse exercício, você irá aprimorar sua página profissional criada anteriormente, incorporando elementos multimídia como imagens e vídeos. O objetivo é aprender a adicionar conteúdo multimídia de forma acessível e responsiva, tornando a página mais rica e interativa para os usuários. + +**Instruções** + +1. **Inserir Imagens com Acessibilidade** + + - Adicione imagens relevantes às diferentes seções da sua página, como: + - Uma foto de perfil na seção de biografia. + - Imagens de projetos na seção de portfólio. + - Gráficos ou ilustrações que complementem seu conteúdo. + - Certifique-se de que todas as imagens incluem uma descrição alternativa (atributo `alt`) que descreva o conteúdo da imagem de forma clara e concisa. + - Garanta que as imagens sejam responsivas, adaptando-se ao tamanho da tela do dispositivo usado pelo visitante. + +2. **Adicionar Vídeos** + + - Incorpore um vídeo que seja relevante para sua área de atuação ou que destaque um projeto específico. + - Inclua controles de reprodução para que o usuário possa iniciar, pausar ou ajustar o volume do vídeo. + - Forneça legendas ou transcrições para tornar o vídeo acessível a todos os usuários (opcional). + +3. **Acessibilidade e Responsividade** + + - Verifique se os elementos multimídia não comprometem a acessibilidade da sua página. + - Assegure-se de que o conteúdo multimídia seja responsivo e funcione bem em diferentes dispositivos e tamanhos de tela, como celulares, tablets e desktops. + +4. **Compatibilidade de Formatos** + + - Utilize formatos de arquivo amplamente suportados pelos navegadores: + - Para imagens, prefira formatos como JPEG ou PNG. + - Para gráficos vetoriais, considere usar SVG. + - Para vídeos, utilize formatos compatíveis como MP4. + - Teste sua página em diferentes navegadores para garantir que todos os elementos multimídia sejam exibidos corretamente. + +**Ao finalizar este exercício, você terá:** + +- Uma página profissional enriquecida com imagens e vídeos relevantes. +- Melhorado a experiência do usuário através de conteúdo interativo e visual. +- Aplicado práticas de acessibilidade, garantindo que sua página seja inclusiva para todos os visitantes. + +**Observação** + +- O foco deste exercício é a incorporação correta e acessível de elementos multimídia, não se preocupe com estilos avançados de design. +- Continue aprimorando sua página com base nos conhecimentos adquiridos, tornando-a cada vez mais completa e profissional.",Elementos Multimídia,rw1730914094155257784 +Adicionando Links,Neste exercício você adicionará links internos e externos para facilitar a navegação e tornar seu portfólio online mais completo,"Como já vimos no exercício anterior, você construiu a estrutura básica da sua página HTML e organizou as seções principais usando tags semânticas. Agora, vamos acrescentar links internos e externos para melhorar a navegação e tornar sua página mais completa. + +1. **Links Internos (Âncoras)** + + Para facilitar a navegação entre as seções da página, adicione links internos na barra de navegação utilizando o atributo `href=""#id-da-secao""`. O `#` antes do nome do id indica um link âncora, direcionando o usuário para uma parte específica da página. + + Lembre-se de definir o atributo `id` em cada seção correspondente. + +2. **Links Externos** + + Inclua links externos para suas redes sociais ou portfólios online na seção de contato. Utilize o atributo `target=""_blank""` para abrir o link em uma nova aba. + +3. **Validação dos Links** + + Após incluir os links, teste a navegação interna e externa para garantir que todos funcionam corretamente. + + + +",Estrutura de Páginas Web e Links,rw173091287683887ea99 +Aplicando Design Responsivo na Página,Aprenda a adaptar sua página para qualquer dispositivo criando um design responsivo e intuitivo," +**Objetivo** + +Praticar o design responsivo, aplicando ajustes no layout, fontes e imagens para melhorar a visualização em diferentes dispositivos. + +**Instruções** + +1. **Configuração da Viewport** + + Comece configurando o viewport no HTML para que o site se adapte ao tamanho da tela do dispositivo. Isso ajudará a ajustar o conteúdo e a melhorar a navegação em telas menores. + +2. **Uso de Media Queries** + + Adicione media queries no CSS para definir estilos específicos para diferentes tamanhos de tela. Experimente ajustes em elementos como o tamanho das fontes, largura de contêineres e organização dos blocos de conteúdo. + +3. **Imagens Adaptáveis** + + Adapte as imagens da sua página para diferentes resoluções, configurando tamanhos flexíveis ou utilizando imagens de diferentes tamanhos conforme o dispositivo. Isso otimizará o carregamento e garantirá que as imagens se ajustem ao layout responsivo. + +4. **Unidades Flexíveis** + + Experimente utilizar unidades flexíveis como `%`, `em`, e `vw/vh` em vez de valores fixos para largura, altura e espaçamento. Isso fará com que os elementos da página se ajustem automaticamente à tela do usuário, criando um layout fluido. + +**Resultado Esperado** + +Sua página deve se ajustar de forma harmoniosa a diferentes tamanhos de tela, com elementos reorganizados e adaptados para uma melhor usabilidade em qualquer dispositivo. + +**Dicas Adicionais** + +- Teste a página em diferentes dispositivos ou use as ferramentas do navegador para visualizar o layout responsivo. +- Mantenha a consistência visual entre os dispositivos, mas aproveite para ajustar pequenos detalhes que melhorem a experiência em cada tamanho de tela. +- Lembre-se de revisar o layout final para garantir uma navegação confortável e uma apresentação visual clara e organizada.",Design responsivo,rw1731004790634193480 +Aplicando diferentes tipos de CSS,Aprenda a aplicar diferentes tipos de CSS para transformar e organizar o visual da sua página de forma prática e fácil,"**Objetivo** + +Aplicar estilos CSS na sua página de portfólio ou currículo online, melhorando a aparência visual e a organização de elementos. O foco é entender e experimentar os diferentes tipos de CSS, usando cada um deles para situações específicas, conforme necessário. + +**Instruções** + +1. **Aplicação do CSS Inline** + + Comece aplicando estilos diretamente nos elementos da sua página com CSS Inline. Esse tipo de CSS é ótimo para ajustes rápidos e específicos, então escolha alguns elementos para estilizar diretamente. Por exemplo, altere a cor e o tamanho do texto de um título ou destaque uma frase especial aplicando uma cor diferente ou um estilo de fonte exclusivo. Lembre-se de usar o atributo `style` diretamente nos elementos HTML para definir essas propriedades. + +2. **Aplicação do CSS Interno** + + Agora, vamos adicionar o CSS Interno. Insira o CSS no cabeçalho da página, dentro da tag `` no `` do seu documento HTML. Este tipo de CSS permite aplicar estilos a vários elementos da mesma página. + + Por exemplo, defina um estilo para todos os parágrafos da página, alterando a cor do texto, o tamanho da fonte ou o espaçamento entre as linhas. Adicione estilos também para títulos e seções, ajustando margens, alinhamentos ou cores para melhorar a estrutura visual da página. + +3. **Criação e Vinculação de um Arquivo CSS Externo** + + Depois de experimentar os estilos Inline e Interno, é hora de criar um arquivo CSS externo. Crie um novo arquivo com a extensão `.css`, por exemplo, `styles.css`. Esse arquivo irá centralizar todos os estilos que você deseja aplicar em toda a sua página. Assim, o HTML ficará mais limpo e organizado, e você poderá reutilizar esses estilos em várias páginas no futuro. + + No seu arquivo CSS externo, defina o estilo padrão para elementos como o corpo da página, títulos, parágrafos e botões. Você pode, por exemplo, definir a fonte padrão, a cor de fundo e o espaçamento dos elementos principais. Depois, vincule o arquivo CSS ao seu HTML usando a tag `` dentro da seção ``. Dessa forma, os estilos do arquivo externo serão aplicados automaticamente à sua página. + +4. **Prática de Consistência e Reutilização** + + Após aplicar esses três tipos de CSS, compare e veja quais estilos se repetem ou são mais adequados para o CSS Externo. Lembre-se que o CSS Externo é ideal para manter estilos consistentes e reutilizáveis. Deixe no CSS Interno apenas estilos específicos para essa página, que não serão utilizados em outras. E utilize CSS Inline somente em casos muito pontuais, para ajustes de última hora ou para personalizações únicas. + +**Resultado Esperado** + +Com este exercício, sua página terá um visual mais organizado e profissional. Ao experimentar os três tipos de CSS, você terá uma noção prática de quando usar cada um deles e entenderá como aplicar estilos de forma eficiente e estratégica. + +**Dicas Adicionais** + +- Ao finalizar, revise sua página para garantir que todos os estilos foram aplicados corretamente. +- Tente manter o CSS Externo bem organizado, agrupando estilos semelhantes, o que facilitará a manutenção no futuro. +- Use sua criatividade para estilizar a página do jeito que preferir! +- Embora manter os estilos em um arquivo externo seja uma boa prática, o objetivo aqui é explorar as diferentes formas de aplicar CSS. +",Estilos.css,rw17309852666022c4de8 +Aplicando Flexbox e Grid no Layout do Projeto,Explore Flexbox e Grid para criar layouts dinâmicos e responsivos que valorizam seu conteúdo,"**O problema** +​ +​ +Considerando que uma pessoa pode ter nome, sobrenome e/ou apelido, crie um código que imprima o nome da pessoa no console, seguindo esta ordem de prioridade: + +- Apelido: Se a variável apelido estiver preenchida, imprima apenas o seu valor. +- Nome e Sobrenome: Se a variável apelido não estiver preenchida, verifique se o sobrenome existe. +- Se o sobrenome estiver preenchido, imprima o primeiroNome seguido de um espaço e o sobrenome. +- Se o sobrenome não estiver preenchido, imprima apenas o primeiroNome. + +Lembre-se que o primeiroNome é sempre obrigatório e estará preenchido. + +**Exemplos** + + 1. Apelido preenchido +​```javascript + const primeiroNome = ""Mario""; + const sobrenome = """"; + const apelido = ""Bros""; + // Saída esperada: Bros +​​``` + 2. Sobrenome preenchido +​```javascript + const primeiroNome = ""Mario""; + const sobrenome = ""Bros""; + const apelido = """"; + // Saída esperada: Mario Bros +​​``` + 3. Apenas o primeiro nome +​```javascript + const primeiroNome = ""Mario""; + const sobrenome = """"; + const apelido = """"; + // Seu código aqui + // Saída esperada: Mario +​​``` +",Flexbox e Grid,rw1731069503143b838b6 +Aplicando posicionamento no CSS,Explore o poder do CSS para posicionar elementos e criar layouts organizados e modernos em sua página!,"**Objetivo** + +Explorar as propriedades de posicionamento em CSS para ajustar a localização dos elementos da sua página de forma prática. + +**Instruções** + +1. **Posicionamento Estático** + Aplique o posicionamento padrão para manter alguns elementos no fluxo natural da página. + +2. **Posicionamento Relativo** + Desloque levemente alguns elementos, como um título ou imagem, em relação à sua posição original. + +3. **Posicionamento Absoluto** + Posicione um elemento sobre outros, ajustando-o em relação ao contêiner mais próximo com um posicionamento específico. + +4. **Posicionamento Fixo** + Fixe um cabeçalho ou rodapé para que permaneça visível enquanto a página é rolada. + +5. **Posicionamento Sticky** + Aplique o posicionamento sticky a um menu de navegação ou título, fixando-o no topo ao rolar a página. + +**Resultado Esperado** + +Sua página deve refletir o uso correto de cada tipo de posicionamento, criando uma estrutura organizada e visualmente atraente. + +**Dicas Adicionais** + +- Fique a vontade para usar os posicionamentos que quiser, não é necessário utilizar todos obrigatoriamente, mas a intenção nesse exercício é usar a criatividade e testar os diferentes tipos.",Posicionamento,rw17309888120468a6f1a +Aprendendo o Glossário do GitHub,Leia o glossário abaixo e procure entender cada um dos termos,"Este glossário abaixo apresenta os termos mais utilizados no Git, porque é fundamental entender o significado das palavras que fará uso no seu dia a dia, pois isso facilitará sua navegação e colaboração nos projetos. + +- **Repositório**: Local onde o código e os arquivos do projeto são armazenados. + +- **Commit**: Registro de uma mudança no código, como um ponto de verificação no histórico do projeto. + +- **Branch**: Ramificação do código onde novas funcionalidades podem ser desenvolvidas ou erros podem ser corrigidos, sem afetar a versão principal. + +- **Pull Request**: Solicitação para mesclar as mudanças de uma branch no projeto principal, permitindo que outras pessoas revisem as alterações antes da integração. + +- **Fork**: Cópia de um repositório, permitindo que você faça suas próprias modificações antes de sugerir melhorias ao projeto original. + +- **Clone**: Cópia de um repositório em sua máquina local, permitindo que você trabalhe offline. + +- **Merge**: Ato de combinar as mudanças de uma branch com outra, geralmente a branch principal. + +- **Conflict**: Ocorre quando duas ou mais mudanças feitas em uma branch não podem ser automaticamente mescladas devido a alterações conflitantes. + +- **Tag**: Um marcador usado para identificar versões específicas de um repositório, geralmente usado para releases. + +- **Issue**: Um item ou tarefa a ser resolvida ou discutida, geralmente usado para rastrear bugs ou solicitar novas funcionalidades. + +- **Wiki**: Um espaço no repositório onde a documentação do projeto pode ser escrita e editada de forma colaborativa. + +- **Action**: Uma automação que executa um processo em resposta a eventos em um repositório, permitindo integração contínua e entrega contínua (CI/CD). + +- **CI/CD**: Práticas de Integração Contínua e Entrega Contínua que automatizam o desenvolvimento e a implantação de software. + +- **Collaborator**: Uma pessoa usuária que tem permissão para contribuir diretamente em um repositório. + +- **Blame**: Comando que permite visualizar quem fez alterações específicas em uma linha de código e quando isso foi feito. + +- **Pull**: Ato de baixar as mudanças mais recentes de um repositório remoto para sua máquina local. + +- **Push**: Ato de enviar suas mudanças locais para o repositório remoto. + +- **Upstream**: O repositório original do qual um fork foi criado. + +- **Downstream**: Um repositório que foi feito a partir de um fork, que pode ter suas próprias alterações. + +- **Marketplace**: Um lugar no GitHub onde você pode encontrar aplicativos e serviços que podem ser integrados aos seus repositórios. + +- **Repository Template**: Um repositório configurado que pode ser usado como base para criar novos repositórios, já com estrutura e arquivos pré-definidos. + +## Bons estudos! + +",Como utilizar o GitHub e Git,rw172796579826251b1dd +Apurar Votação,Terceiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Implemente o método apuraVotacao, que recebe como argumento um array com os votos de uma certa eleição, em valores numéricos, podendo ser 1, 2 ou 3. + +- Caso haja mais votos 1, retorne a string Vencedor: 1. + +- Caso haja mais votos 2, retorne a string Vencedor: 2. + +- Caso haja mais votos 3, retorne a string Vencedor: 3. + +- Caso haja empate, retorne a string Empate. + +# Casos de teste + +- Quando a entrada for ""[1, 1, 1, 2, 3, 3, 2]"", a saida deve ser ""Vencedor: 1"" +- Quando a entrada for ""[2, 2, 2, 2, 1]"", a saida deve ser ""Vencedor: 2"" +- Quando a entrada for ""[2, 2, 3, 3, 3, 3]"", a saida deve ser ""Vencedor: 1"" +- Quando a entrada for ""[1, 2, 2, 2, 3, 3, 3]"", a saida deve ser ""Empate""",Fundamentos,rw172564217048038aaf4 +Backend - Construindo a Base de Dados,Configure o backend com Node.js TypeORM e PostgreSQL Teste a API e adicione um filme Explore migrations e prepare para produção no Heroku,"Olá, Aluna! Nesta atividade, você começará a trabalhar com Node.js e explorará as seguintes tecnologias: JavaScript / TypeScript, Express e TypeORM. O objetivo é aprender a configurar um ambiente de desenvolvimento backend, entender como criar e rodar uma aplicação utilizando essas tecnologias e também trabalhar com banco de dados e rotas RESTful. + +Durante a atividade, você terá a oportunidade de implementar funcionalidades práticas, consolidar seus conhecimentos em desenvolvimento backend e preparar uma base sólida para aplicações mais complexas no futuro. + + + +**Pré requisitos** + + - [Entendendo linhas de comando](https://tutorial.djangogirls.org/pt/intro_to_command_line/) - É importante entender o que é um terminal e o que são linhas de comando. + +**Preparando o ambiente de desenvolvimento** + + +- [Instalar o Git](https://git-scm.com/downloads) +- [Instalar Oh my zsh](https://ohmyz.sh/) +- [Instalar NodeJS](https://nodejs.org/en/) +- Instalar o **Yarn** + + Abra o terminal do seu sistema operacional e digite o seguinte comando: + + ```bash + npm install -g yarn + ``` + +- [Instalar Postgres](https://www.postgresql.org/download/) +- [Instalar Beekeeper](https://www.beekeeperstudio.io/get) +- [Instalar Visual Studio Code](https://code.visualstudio.com/) + - [Configuração do editor - Rocketseat](https://www.youtube.com/watch?v=c7P03kkrEG8) - *GraphQL e **Live Server** não são necessários serem instalados* +- Clonar repositório + + Abra o terminal do seu sistema operacional e digite o seguinte comando: + + ```bash + git clone + ``` + +- Iniciando a aplicação + + Após clonar esse repositório para sua maquina, ainda no terminal digite e aguarde a insstalação ser concluída: + + ```bash + cd backend-nodejs + yarn install + ``` + + Após a instalação, digite o comando: + + ```bash + yarn dev + ``` + + você deverá notar uma mensagem no terminal ao final: + + ```bash + Server's running in http://localhost:9000 + ``` + +- Rodar testes End to End + + + Subir aplicação após criar a modificação e o testes na pasta ./e2eTest + + ```bash + yarn dev + ``` + + Rodar todos os testes e2e + + ```bash + yarn run test:e2e + ``` + +**TypeORM** + +- Criando Migration + + + ```bash + yarn typeorm migration:create -n + ``` + +**Preparando ambiente de teste** + +- Criar uma conta no [Heroku](https://signup.heroku.com/) +- [Criar uma App no Heroku](https://www.youtube.com/watch?v=RNQ5XsGADdg) +- Adicionar o **postgres** na App +- Configurar as **variaveis de ambiente** na App +- [Fazer deploy da branch main](https://www.youtube.com/watch?v=DMPJNe8PqnU) + +**Variáveis de ambiente** + +Essas são as variaveis de ambiente que essa aplicação precisa para funcionar em qualquer ambiente. +Os valores que devem ser atribuidos a elas vão depender dos ambientes. + +Para caso de ambiente **local** (sua máquina) deve ser criado um arquivo `.env` na raiz do projeto + + ```bash +NODE_ENV= +PGSSLMODE=no-verify +``` + +**Objetivo Final** + +Backend funcional com pelo menos 1 filme cadastrado. +Frontend integrado com o backend e estilizado de acordo com sua preferência. +Deploy completo na Vercel e, opcionalmente, no Heroku para o backend.",Projeto Acelera Movies,rw173262818047403e05d +Calculando o IMC,Crie uma função que calcule o IMC com base no peso e na altura e descubra a classificação correspondente,"**Crie uma função que calcule o Índice de Massa Corporal (IMC) e exiba o resultado na página Home, localizada em:** +`app > page.tsx` (ou `app > page.jsx` se estiver usando JavaScript). + +**Fórmula do IMC:** +`IMC = peso / (altura x altura)` + +**Classificações do IMC:** +- **Abaixo do peso:** IMC < 18,5 +- **Peso normal:** IMC entre 18,5 e 24,9 +- **Sobrepeso:** IMC entre 25 e 29,9 +- **Obesidade:** IMC > 30 + +--- + +**Instruções:** +1. No início do arquivo `page.tsx` ou `page.jsx`, crie uma função chamada `calcularIMC` que: + - Receba dois parâmetros: **peso** e **altura**. + - Retorne o valor do **IMC** (com duas casas decimais) e a sua **classificação**. + +2. Na página: + - Declare variáveis para o peso e a altura. + - Use a função `calcularIMC` para calcular o IMC com os valores fornecidos. + - Exiba o resultado do IMC dentro de uma tag HTML, como ` +`. + +**Extra:** +Se preferir, adicione uma validação para evitar divisões por zero ou valores inválidos.",Variáveis e Constantes,rw1732544420430568ad9 +Calcular média de alunos,Quinto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Implemente o método `mediaNotas`, que recebe as notas de 3 alunos diferentes, referente a 3 provas realizadas por eles. Calcule a média de cada aluno, retornando para cada um deles se o aluno foi aprovado, reprovado ou está em recuperação. Considere os seguintes parâmetros para as respectivas saídas: + +- Aprovado: nota maior ou igual a 7. +- Recuperação: nota maior que 4 e menor que 7. +- Reprovado: nota menor ou igual a 4. + +## Exemplos: + +- Para a entrada `[8, 7, 9], [5, 6, 5], [3, 4, 2]`, a saída deve ser: + - Aluno 1: Passou + - Aluno 2: Recuperação + - Aluno 3: Reprovado +- Para a entrada `[9, 8, 7], [6, 5, 4], [2, 3, 2]`, a saída deve ser: + - Aluno 1: Passou + - Aluno 2: Recuperação + - Aluno 3: Reprovado +- Para a entrada `[7, 7, 7], [4, 4, 4], [10, 9, 8]`, a saída deve ser: + - Aluno 1: Passou + - Aluno 2: Recuperação + - Aluno 3: Passou +",Repetição,rw172788889829812e9e6 +Clonando um Repositório e Fazendo um Fork,Clonar um repositório existente e fazer um fork para praticar a colaboração,"1. **Escolha um repositório público no GitHub:** + - Navegue até o [GitHub](https://github.com/) e procure por um repositório de seu interesse. Pode ser um projeto de código aberto ou qualquer repositório que você gostaria de explorar. + +2. **Fazendo um Fork:** + - Na página do repositório escolhido, localize o botão “Fork” no canto superior direito da tela. Clique nele. Isso criará uma cópia do repositório em sua conta do GitHub. + +3. **Clonando o repositório:** + - Após fazer o fork, você será redirecionado para a sua cópia do repositório. Na parte superior da página, clique no botão verde ""Code"" e copie a URL do repositório. + - Abra o terminal no seu computador e navegue até o diretório onde você deseja clonar o repositório. + - Execute o comando: + ```bash + git clone [URL] + ``` + Substitua `[URL]` pela URL que você copiou. + +4. **Navegando até o diretório:** + - Após o clone, navegue até o diretório do repositório usando: + ```bash + cd [nome-do-repositorio] + ``` + Substitua `[nome-do-repositorio]` pelo nome do repositório clonado. + +## Bons Estudos!",Como utilizar o GitHub e Git,rw1727976078726bee9ab +Compra com Desconto,Sexto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +A Loja do Juninho está com uma super promoção. Na compra de qualquer produto você ganha desconto conforme a forma de pagamento seguindo a tabela seguinte. +​ +| Forma de Pagamento | Desconto | +|:-------------------:|:--------:| +| Débito | 5% | +| Crédito | 3% | +| Pix ou Dinheiro | 10% | + +Faça um programa que verifica o tipo de desconto, calcule o valor do produto com o desconto e imprima o resultado. O valor final do produto após o desconto pode ser encontrado com a fórmula: + +```javascript +​ valorFinal = valorDoProduto - (valorDoProduto * desconto) +``` + +​ +​Ao imprimir o valor, limite as casas decimais a apenas duas casas (ex: 12.50) + +```javascript +//tipo de pagamento (dinheiro, credito, debito, pix) +const tipoDePagamento = ""credito""; +//valor da mercadoria (centavos) +const valorDoProduto = 13000; +``` + +Para o exemplo acima, o valor final é: + + +```javascript +​valorFinal = 13000 - (13000\*0.05) +valorFinal = 12350 +``` + +O programa deve exibir na tela: +​ + +```javascript +Valor a ser pago: R$123.50 +``` + +Teste seu programa para outras entradas. +",Condicionais,rw1755277654851e10ef1 +Compreendendo a Especificidade no CSS,Explore como a hierarquia de seletores no CSS afeta a aplicação de estilos e aprenda a usá-los de forma eficaz," **Objetivo:** +Compreender como a hierarquia de seletores no CSS influencia a aplicação de estilos, e como aplicar diferentes tipos de seletores (ID, classes, e tags) de maneira eficaz, garantindo que o design de uma página seja coeso e sem conflitos. + +**Instruções:** + +1. **Entenda a Hierarquia de Especificidade no CSS:** +- O CSS aplica estilos de acordo com a **especificidade** de seus seletores. Isso significa que, dependendo do tipo de seletor utilizado, alguns estilos podem ""sobrescrever"" outros. +- Selecione um elemento em sua página e analise os diferentes tipos de seletores que podem ser aplicados. Pense sobre como os estilos se combinam para determinar qual será aplicado. + +2. **Ordem de Aplicação dos Estilos:** +- Imagine que um mesmo elemento tenha múltiplos seletores aplicados, como uma tag, uma classe e um ID. Tente determinar a ordem de aplicação desses estilos. +- Lembre-se de que os seletores **ID** têm mais peso que as **classes**, que por sua vez têm mais peso que as **tags**. Isso significa que, se você usar uma tag, uma classe e um ID no mesmo elemento, o estilo do **ID** será o que prevalecerá. + +3. **Examine o Impacto do Seletor Inline:** + + O estilo **inline** é geralmente o mais forte, pois é aplicado diretamente ao elemento HTML. Pense em um caso onde você aplica um estilo inline e também usa um seletor de ID ou classe para o mesmo elemento. Como isso afetará a renderização? + +4. **Use o `!important` com Cuidado:** + + O `!important` pode ser utilizado para forçar um estilo, independentemente da hierarquia. Mas deve ser utilizado com cautela, pois pode dificultar a manutenção do código. + + +5. **Reflexão sobre Pseudo-Elementos e Pseudo-Classes:** +- Pense na diferença entre **pseudo-classes** (como `:hover`) e **pseudo-elementos** (como `::before` e `::after`). +- Qual deles tem maior prioridade quando ambos são aplicados ao mesmo elemento? Como você pode usar essas ferramentas de maneira eficaz em seu código? + +6. **Aplicação Prática:** + + Escolha um elemento da sua página para aplicar diferentes tipos de seletores e veja como a hierarquia de especificidade se reflete na prática. Aplique um estilo utilizando inline, um utilizando classe e outro com ID, e observe qual estilo prevalece. + +**Resultado Esperado:** + +Ao final deste exercício, você será capaz de: +- Entender como a especificidade no CSS afeta a aplicação de estilos. +- Aplicar seletivamente diferentes tipos de seletores para garantir a organização e a consistência visual da sua página. +- Tomar decisões conscientes sobre quando usar o `!important` e como lidar com pseudo-elementos e pseudo-classes em seu CSS. + +**Observações:** + +- Não se preocupe com a sintaxe exata dos seletores neste momento; se concentre inicialmente nos conceitos fundamentais da hierarquia de especificidade no CSS. +- Experimente o exercício em diferentes tipos de elementos e use o raciocínio para entender o comportamento dos estilos em diversos cenários. + +",Hierarquia no CSS,rw1730990599513cf847b +Conectando a aplicação com o banco de dados,Utilizando Node.js com TyperORM e um banco da escolha da aluna,"Neste exercício, você irá criar uma aplicação Node.js que se conectará a um banco de dados usando TypeORM. A aplicação permitirá realizar operações básicas de CRUD (Create, Read, Update, Delete) em entidades que você definir. + +--- + +**Objetivos** + +- Configurar uma conexão entre a aplicação Node.js e um banco de dados utilizando TypeORM. +- Implementar operações CRUD para gerenciar entidades no banco de dados escolhido. +- Compreender como o TypeORM facilita a interação com bancos de dados relacionais. + +**Pré-requisitos:** + +- Conhecimentos básicos de JavaScript e Node.js. +- Instalar o Node.js e o npm em sua máquina. +- Familiaridade com conceitos de bancos de dados e SQL. + + +**Dicas:** + +- Utilize **TypeORM** para gerenciar a conexão e as operações no banco de dados. +- Escolha um banco de dados que você já conheça, como MySQL, PostgreSQL ou SQLite, para facilitar a implementação. +- Consulte a [documentação do TypeORM](https://typeorm.io) para entender as opções de configuração e uso. + + +**Configuração Inicial** + +1. Inicie um projeto Node.js: Abra seu terminal e crie uma pasta para o projeto. Em seguida, execute: + +```bash +npm init -y +``` + +- Isso criará um arquivo package.json com configurações padrão. + +2. Instale as dependências necessárias, incluindo **TypeORM** e um driver para o banco de dados que você escolheu. Por exemplo, para MySQL, execute: + +```bash +npm install typeorm mysql +``` + +3. Configure a conexão com o banco de dados: Crie um arquivo de configuração ''ormconfig.json'' na raiz do projeto com as credenciais do seu banco de dados, como abaixo: + +```json +{ + ""type"": ""mysql"", + ""host"": ""localhost"", + ""port"": 3306, + ""username"": ""seu_usuario"", + ""password"": ""sua_senha"", + ""database"": ""nome_do_banco"", + ""synchronize"": true, + ""entities"": [""src/entity/*.ts""] +} +``` + +- Certifique-se de substituir os valores pelos seus dados reais. + + +Bom trabalho! 🚀",TypeORM,rw17304802690217eb318 +Construindo e Testando um Sistema de Carrinho de Compras,O desafio consiste em testar um sistema simples de carrinho de compras.,"**Primeiros passos** + +Para clonar o repositório base + +```bash +git clone https://github.com/aceleradora-TW/exercicios-mocks-spies.git +``` + +Para instalar as dependências + +```bash +npm install +``` + +Para rodar os testes uma única vez + +```bash +npm run test +``` + +Para rodar os testes no modo observação + +```bash + +npm run test:watch + +``` + +**Descrição** + +Este exercício propõe que você desenvolva testes unitários para uma classe de Carrinho de Compras (Cart) em TypeScript. O objetivo é que a pessoa desenvolvedora exercite a criação de mocks e o uso de spies no Jest, garantindo que o NotificationService seja chamado quando um produto for adicionado, que produtos possam ser removidos corretamente, que o cálculo de total utilize o método reduce e que o carrinho possa ser limpo. + + + +**O que você deve implementar** + +1. Testes para adicionar um produto ao carrinho: + + - Validar se o produto foi adicionado corretamente + + - Garantir que o serviço de notificação foi chamado ao adicionar o produto + + + +2. Testes para remover um produto do carrinho: + + - Confirmar que o produto foi removido corretamente após a chamada ao método de remoção + + + +3. Testes para o cálculo do total de itens: + + - Adicionar múltiplos produtos e verificar se o total calculado está correto + + - Criar um spy para garantir que o método reduce foi utilizado no cálculo + + + +4. Testes para limpar o carrinho: + + - Certificar-se de que ao limpar o carrinho não restem produtos na lista + + + +Para completar a atividade, é necessário criar mocks para o NotificationService e aplicar spies sobre métodos internos usando as funcionalidades do Jest. + + + +**Dica importante** + +Lembre-se de restaurar qualquer spy criado após a execução do teste evitando que ele afete outros testes no mesmo arquivo. +https://github.com/aceleradora-TW/exercicios-mocks-spies.git",Mocking e Espiões,rw1732814508508e8129b +Contador ocorrência,Segundo exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + +Implemente um algoritmo que receba duas entradas: texto e busca. Este algoritmo deve retornar quantas vezes o valor da busca aparece dentro do conteúdo de texto. Implemente esta lógica dentro do método contadorDeOcorrencia. Veja alguns exemplos de entrada e saída: + +# Cenários de teste +- Ao receber o texto ""bolo"" e a busca ""o"", o contador deve retornar ""2"" +- Ao receber o texto ""batata"" e a busca ""a"", o contador deve retornar ""3"" +- Ao receber o texto ""Alejandro"" e a busca ""a"", o contador deve retornar ""1"" +- Ao receber o texto ""Uma Escola"" e a busca ""e"", o contador deve retornar ""0"" + + + +",Fundamentos(typescript Fundamentos),rw1751550527376edcf02 +Contar múltiplos de 2 e 3 e múltiplos de 2 e 5,Quarto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Implemente o método `analiseMultiplos`, que recebe vários números positivos até que o valor `-1` seja digitado e, ao final, informa quantos números são múltiplos de 2 e 5, e quantos são múltiplos de 2 e 3. + +- O método deve iterar sobre os números e contar os múltiplos de cada condição. + +## Exemplos: + +- Para a entrada `[10, 15, 30, -1]`, a saída deve ser: + - Múltiplos de 2 e 5: 2 (valores: 10, 30) + - Múltiplos de 2 e 3: 1 (valor: 30) +- Para a entrada `[6, 12, 20, 25, -1]`, a saída deve ser: + - Múltiplos de 2 e 5: 1 (valor: 20) + - Múltiplos de 2 e 3: 2 (valores: 6, 12) +- Para a entrada `[15, 30, -1]`, a saída deve ser: + - Múltiplos de 2 e 5: 1 (valor: 30) + - Múltiplos de 2 e 3: 1 (valor: 30) +",Repetição,rw1727888842484d0b855 +Criando componente UserInfo com Props,Personalize o componente UserInfo para exibir informações de diferentes usuários utilizando props,"**Instruções:** +1. **No componente `UserInfo`:** + - Ajuste a implementação para que ele receba as seguintes informações como **props**: + - **nome** (string). + - **sobrenome** (string). + - **idade** (número). + - **estaNaFaculdade** (booleano). + - Utilize **desestruturação** para acessar as props dentro do componente. + + Exemplo: + ```javascript + function UserInfo({ nome, sobrenome, idade, estaNaFaculdade }) { + return ( + + Nome: {nome} + Sobrenome: {sobrenome} + Idade: {idade} + Está na faculdade? {estaNaFaculdade ? ""Sim"" : ""Não""} + + ); + } +",Componentes + props,rw1732552610168bb1015 +Criando componentes,Organize seu projeto criando um componente para exibir informações pessoais e use-o na página Home,"**Instruções:** +1. **Crie um diretório chamado `components` dentro da pasta `app`.** + +2. **Dentro de `components`, crie um arquivo chamado:** + `UserInfo.tsx` (ou `UserInfo.jsx` se estiver usando JavaScript). + +3. **Nesse arquivo:** + - Utilize as variáveis criadas no exercício **""Criando Variáveis""**: + - **Seu nome** (string). + - **Seu sobrenome** (string). + - **Sua idade** (número). + - **Se você está na faculdade** (booleano). + - Retorne essas informações formatadas em tags HTML (como `` ou ``). + +4. **Na página `app > page.tsx` (ou `app > page.jsx`):** + - Importe o componente `UserInfo`. + - Utilize o componente na **Home** para exibir as informações no navegador. + +**Dica:** +- Para criar componentes reutilizáveis, utilize boas práticas de organização de arquivos, mantendo-os em uma pasta como **`components`**. +- Lembre-se de exportar o componente de `UserInfo.tsx` para poder utilizá-lo em outros arquivos. +",Componentes + Next.js,rw173255101957441e7dd +Criando minha primeira página,Este exercício ensina a criar a estrutura básica de uma página HTML5," +**Objetivo** + +Aprender a criar uma página HTML simples e profissional utilizando a estrutura básica do HTML5 e aplicando tags semânticas para organizar o conteúdo de forma clara e acessível. O propósito é desenvolver uma página profissional que possa servir como um portfólio ou currículo online, onde você pode apresentar sua biografia, formação, experiências, projetos e informações de contato. + +**Instruções** + +Siga os passos abaixo para criar sua página: + +**1. Estrutura Básica do Documento** + +- **Declaração do Tipo de Documento**: Comece seu arquivo com `` para indicar que está utilizando HTML5. +- **Tag ``**: Envolva todo o conteúdo da sua página dentro da tag ``. + +**2. Seção ``** + +Dentro da tag ``, inclua: + +- **Metadados**: + - Utilize `` para definir a codificação de caracteres e garantir que caracteres especiais sejam exibidos corretamente. +- **Título da Página**: + - Utilize `` para definir o título que aparecerá na aba do navegador. + +**3. Seção ``** + +Esta é a área onde o conteúdo visível da sua página será colocado. + +**a) Cabeçalho da Página** + +- Utilize a tag semântica `` para o cabeçalho. +- Inclua um título principal com seu nome ou o nome da página. +- Adicione uma frase que te inspira ou um slogan. + +**b) Barra de Navegação** + +- Se quiser adicionar links para diferentes partes da sua página, utilize a tag `` para criar uma barra de navegação. +- Crie apenas a tag `` pois na próxima atividade iremos adicionar os links. + +**c) Conteúdo Principal** + +- Envolva o conteúdo principal dentro da tag ``. + +Dentro de ``, organize as seguintes seções: + +- **i) Biografia** + - Use a tag `` para esta parte. + - Inclua: + - Seu **nome**. + - Sua **área de interesse** (exemplo: Desenvolvimento Web, Design Gráfico). + - Uma breve descrição sobre você. + +- **ii) Formação** + - Crie outra `` para listar sua formação acadêmica ou cursos relevantes que você já fez. + +- **iii) Experiência** + - Utilize `` para detalhar suas experiências profissionais ou projetos nos quais você já trabalhou. + +- **iv) Portfólio** + - Outra `` onde você pode mostrar trabalhos ou projetos realizados. + +- **v) Hobbies** + - Use a tag `` se quiser destacar esta seção como conteúdo complementar. + - Liste seus hobbies ou atividades que gosta de fazer no tempo livre. + +**d) Contato** + +- Crie uma `` para informações de contato. +- Inclua seu e-mail, telefone ou links para redes sociais. + +**e) Rodapé da Página** + +- Utilize a tag `` para o rodapé. +- Adicione informações adicionais, como direitos autorais ou notas finais. + +**Dicas Adicionais** + +- **Organização Semântica**: O uso de tags semânticas como ``, ``, ``, ``, ``, `` e `` ajuda na acessibilidade e na otimização para motores de busca. +- **Comentários**: Caso seja necessário utilize comentários `` para se orientar durante a construção da página. +- **Validação**: Após terminar, valide seu código HTML para verificar se há erros de sintaxe. + +**Resultado Esperado** + +Ao finalizar este exercício, você terá: + +- Uma página HTML estruturada corretamente com a sintaxe básica do HTML5. +- Utilizado tags semânticas para melhorar a organização e acessibilidade do conteúdo. +- Praticado a criação de conteúdo pessoal que pode ser expandido para um portfólio ou currículo online. + +**Observação** + +- Não se preocupe com estilos ou design neste momento; o foco é compreender a estrutura HTML. +- Este exercício é adequado para todos os níveis, então sinta-se à vontade para adicionar mais detalhes ou se manter no básico, conforme seu conforto. +",Estrutura Básica,rw1730385185255d8d1fc +Criando o primeiro CRUD com PrismaORM,"A partir de agora você vai aprenderá como realizar as quatro operações fundamentais de banco de dados CRUD: Create (Criar), Read (Ler), Update (Atualizar) e Delete (Deletar) utilizando o Prisma ORM","Seguindo o exercício anterior, você criará um novo usuário no banco de dados. O Prisma torna isso incrivelmente poderoso, permitindo criar registros em tabelas relacionadas em uma única chamada. + +**Passo 1: Edite o arquivo prisma/client: Criar o schema do banco de dados** +```bash +generator client { + provider = ""prisma-client-js"" +} + +datasource db { + provider = ""sqlite"" + url = ""file:./dev.db"" +} +​ +model User { + id Int *id *default(autoincrement()) + name String + email String unique + posts Post[] + createdAt DateTime *default(now()) + updatedAt DateTime *updatedAt +} + +model Post { + id Int *id *default(autoincrement()) + title String + content String? + published Boolean *default(false) + authorId Int + author User relation(fields: [authorId], references: [id], onDelete: Cascade) + createdAt DateTime *default(now()) + updatedAt DateTime *updatedAt +} + +``` + +--- + +**Passo 2: Gerar o Prisma Client** + +```bash +​npx prisma generate +``` + +--- +​ +**Passo 3: Aplicar as mudanças no banco de dados** + +```bash +npx prisma db push +``` + +--- + + +**Passo 4: ​Criar o script CRUD completo:** +Crie crud-simple.ts na raiz + + + +```ts +import prisma from './lib/prisma' + +async function main() { + console.log(' CRUD Simples com Prisma\n') + + try { + // Limpar dados + await prisma.post.deleteMany() + await prisma.user.deleteMany() + console.log(' Dados limpos') + + // CREATE + const user = await prisma.user.create({ + data: { + name: 'João', + email: 'joao test.com', + posts: { + create: { title: 'Meu Post' } + } + }, + include: { posts: true } + }) + console.log(' Criado:', user.name) + + // READ + const users = await prisma.user.findMany({ + include: { posts: true } + }) + console.log(' Total usuários:', users.length) + + // UPDATE + const updated = await prisma.user.update({ + where: { id: user.id }, + data: { name: 'João Silva' } + }) + console.log(' Atualizado:', updated.name) + + // DELETE + await prisma.user.delete({ + where: { id: user.id } + }) + console.log(' Deletado com sucesso') + + } catch (error) { + console.error(' Erro:', error) + } finally { + await prisma.$disconnect() + console.log(' Finalizado') + } +} + +main() +``` + + +​Execute o teste: + + +```bash +npx tsx crud-simple.ts +``` + + +",PrismaORM,rw17507690657455f92cf +Criando sua primeira API REST,Criando API REST com Node.js Express e bodyParser,"Neste exercício, você irá construir uma API RESTful simples usando Node.js e Express. A API será capaz de realizar operações de CRUD (Create, Read, Update, Delete) em um arquivo JSON que armazenará dados de usuários. + +--- + +**Objetivos** + +- Criar uma API RESTful básica com operações CRUD. +- Ler, escrever, atualizar e excluir dados de um arquivo JSON. +- Compreender a estrutura de uma API e como ela se comunica usando métodos HTTP. + +**Pré-requisitos:** + +- Conhecimentos básicos de JavaScript e Node.js. +- Instalar o Node.js e o npm em sua máquina. + +**Dicas:** + +- **Express** para criar o servidor e manipular rotas HTTP de maneira simplificada. +- **fs(file system)** que é um módulo nativo do Node.js usado para manipular arquivos. +- **bodyParser** que serve para analisar o corpo das requisições HTTP, permitindo que o servidor receba dados no formato JSON ou como dados de formulário. + + + +**Configuração Inicial** + +1. Inicie um projeto Node.js: Abra seu terminal e crie uma pasta para o projeto. Em seguida, execute: + +```bash +npm init -y +``` + +- Isso criará um arquivo package.json com configurações padrão. + +2. Instale o **Express** e o **Body-Parser**: Execute o comando abaixo para instalar as dependências necessárias: + +```bash +npm install express body-parser +``` + +3. Configuração do JSON de Dados: Crie um arquivo chamado users.json na raiz do projeto com o seguinte conteúdo: + +```json +{ + ""user1"": { ""id"": 1, ""name"": ""Alice"", ""age"": 28, ""email"": ""alice@example.com"" }, + ""user2"": { ""id"": 2, ""name"": ""Bob"", ""age"": 34, ""email"": ""bob@example.com"" }, + ""user3"": { ""id"": 3, ""name"": ""Charlie"", ""age"": 25, ""email"": ""charlie@example.com"" } +} +``` + +- Esse arquivo armazenará dados dos usuários e será manipulado pelas rotas da API. + +Bom trabalho! 🚀",REST API,rw1730469197801db3259 +Criando tabelas e também formulários e listas,Neste exercício você aprenderá sobre formulários e também tabelas e listas,"**Objetivo** + +Neste exercício, você desenvolverá habilidades para criar e estruturar formulários, tabelas e listas em HTML, tornando sua página de portfólio mais completa e interativa. Essa prática permite coletar dados de visitantes e exibir informações de forma organizada, valorizando o design e a funcionalidade do seu portfólio online. + +**Instruções** + +1. **Formulários para Contato** + + Adicione um formulário de contato para facilitar a comunicação com visitantes interessados em seu trabalho. Inclua campos como nome, e-mail e mensagem. Finalize com um botão de envio (obs: por hora o botão não irá funcionar). + +2. **Tabelas para Dados Estruturados** + + Insira uma tabela para apresentar informações organizadas, como experiências de trabalho, qualificações ou dados relevantes sobre projetos. Estruture a tabela de forma a melhorar a legibilidade e tornar seu portfólio mais profissional. + +3. **Listas para Apresentação de Conteúdos** + + Utilize listas ordenadas e não ordenadas para exibir tópicos como habilidades, interesses ou etapas de um processo de trabalho. As listas ajudam a destacar informações e tornam o portfólio visualmente mais dinâmico. + +**Resultado Esperado** + +Ao final deste exercício, sua página de portfólio terá formulários funcionais para coleta de dados, tabelas organizadas para exibição de informações e listas claras para destacar conteúdos importantes. Essa estrutura torna seu portfólio mais atrativo e útil para visitantes. + +**Observação** + +- Mantenha o foco na organização e estruturação dos elementos; o estilo e a lógica de programação será aprimorado em etapas futuras.",Formulários - Tabelas - Listas,rw17309152597892989ce +Criando uma conta no GitHub,Nesta atividade você irá criar uma conta no GitHub para conseguir criar repositórios e contribuir em projetos,"## Passo 1: Acesse o Site do GitHub +- Abra o seu navegador de internet. +- Vá para o site oficial do GitHub: [github.com](https://github.com). + +## Passo 2: Inicie o Processo de Registro +- Clique no botão **Sign up** (Cadastrar-se) no canto superior direito da página. + +## Passo 3: Preencha os Dados +1. **Username** (Nome de Usuário): + - Escolha um nome de usuário que você deseja usar. Ele será visível para outros usuários. + +2. **Email Address** (Endereço de Email): + - Digite um endereço de email válido. Este será usado para a verificação da conta e para receber notificações. + +3. **Password** (Senha): + - Crie uma senha segura que tenha pelo menos 8 caracteres. + +## Passo 4: Complete o Captcha +- Siga as instruções na tela para completar o CAPTCHA e provar que você não é um robô. + +## Passo 5: Clique em **Create Account** (Criar Conta) +- Após preencher todos os campos e completar o CAPTCHA, clique no botão **Create Account**. + +## Passo 6: Verifique Seu Email +- Acesse sua caixa de entrada e procure um email do GitHub. +- Clique no link de verificação contido no email para ativar sua conta. + +## Passo 7: Personalize Sua Conta (Opcional) +- Após a verificação, você pode ser solicitado a personalizar sua conta, adicionando informações adicionais ou seguindo alguns usuários. Isso é opcional. + +## Passo 8: Explore o GitHub +- Após concluir a configuração, você pode começar a explorar repositórios, criar seus próprios projetos e colaborar com outros usuários. + +## Dicas Finais +- Mantenha suas informações de login seguras. +- Explore a documentação do GitHub para aprender mais sobre como usar a plataforma. + +**Pronto! Você agora tem uma conta no GitHub.** +",GitHub,rw17279767069844c209b +Criando Variáveis,Aprendendo a criar variáveis e exibir nas Tags,"**Crie uma variável para armazenar cada uma das seguintes informações:** +- **Seu nome** (string) +- **Seu sobrenome** (string) +- **Sua idade** (número) +- **Se você está na faculdade** (booleano) + +--- + +**Essas variáveis devem ser criadas na página Home, localizada em:** +`app > page.tsx` (ou `app > page.jsx` se estiver usando JavaScript) no projeto Next.js. + +**Instruções:** +- Declare as variáveis no início do arquivo, utilizando boas práticas de nomenclatura. +- Exiba os valores dessas variáveis como conteúdo dentro de tags HTML (como ` +` ou ` +`) no JSX ou TSX. +- Utilize o retorno do componente padrão da página para exibir os valores. + +**Dica:** +No JSX ou TSX, utilize chaves `{}` para retornar valores de variáveis ou expressões JavaScript/TypeScript dentro das tags HTML. Isso permite que você misture JavaScript com HTML facilmente. +",Variáveis e Constantes,rw1732543930047f3166d +Crie uma Página Web sobre Pokémons,Desafie-se a criar uma aplicação incrível que analisa as fraquezas dos Pokémons com base nos tipos e conectando backend com frontend para uma experiência interativa,"Neste exercício, você vai desenvolver uma aplicação web completa, onde seu objetivo será consumir uma API que fornece dados de Pokémons e, com base nesses dados, aplicar uma lógica para descobrir as fraquezas de cada um deles. + + + +**Você irá praticar:** + + + +- Conexão entre backend e frontend + +- Criação e consumo de endpoints locais ou online (como preferir) + +- Requisições HTTP (GET) + +- Manipulação de objetos e arrays em TypeScript + +- Organização de código em aplicações fullstack (Next.js ou similar) + + + +**Sobre a API** + + + +A API já está pronta e disponível no GitHub caso deseje usar. Ela fornece uma lista de Pokémons em formato JSON, contendo informações como nome, ID e tipos da primeira geração. + + + +**Você pode:** + + + +- Clonar o repositório e rodar localmente; + +- Usar o link da API local como fonte de dados no frontend; + +- Ou ainda usar uma API online como a [https://pokeapi.co/](https://pokeapi.co/), [https://pokedexapi.com/](https://pokedexapi.com/) ou [https://pogoapi.net/](https://pogoapi.net/) + + + +**Exemplo de dados da API (entrada):** + + + +```json + +[ + + { ""id"": 1, ""name"": ""pikachu"", ""types"": [""electric""] }, + + { ""id"": 2, ""name"": ""gabite"", ""types"": [""dragon"", ""ground""] } + +] + +``` + + + +**Sua Tarefa** + + + +Crie uma aplicação web que: + + + +- Consuma os dados da API local (endpoint `GET /api/pokemons`) + +- Para cada Pokémon, calcule suas fraquezas com base nos seus tipos + +- Exiba na tela: nome, tipos e fraquezas + +- Permita filtrar os Pokémons por: + + - Nome (input de busca) + + - Tipo (select/dropdown) + + - Fraqueza (select/dropdown) + + + +**Exemplo de saída esperada no frontend:** + + + +```json + +{ + + ""name"": ""pikachu"", + + ""types"": [""electric""], + + ""weakness"": [""ground""] + +} + +``` + + + +## Clone o repositório + + + +Navegue até o diretório onde você deseja clonar o repositório: + + + +```bash + +cd /caminho/para/seu/diretorio + +``` + + + +Execute o comando `git clone` com o URL do repositório: + + + +```bash + +git clone https://github.com/Wander06/exercicio-pokemon-types.git + +``` + + + +Isso criará uma cópia local do repositório no seu computador. + + + +Depois de clonar o repositório, entre no diretório do projeto: + + + +```bash + +cd exercicio-pokemon-types + +``` + + + +Lembre-se de usar o comando: + + + +```bash + +npm install + +``` + + + +Para instalar as dependências necessárias, e: + + + +```bash + +npm run start + +``` + + + +Para inicializar a aplicação. + + +",Projeto Pokémon,rw17325466486388a37ea +Dando nome as pedras,Terceiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Fazendo uso do código criado no exercício anterior, modifique-o para que, quando a pedra retirada do dominó for uma **bucha** (uma pedra com dois lados iguais), o código informe o nome da bucha. + +Utilize o glossário abaixo para nomear as pedras: + +| Bucha | Nome | +| :------: | :--------| +| 0 | Branca | +| 1 | Ás | +| 2 | Duque | +| 3 | Terno | +| 4 | Quadra | +| 5 | Quina | +| 6 | Sena | + +**Exemplo:** + +Caso a bucha retirada tenha os dois lados com o número **3**, deverá ser impresso na tela: + +",Condicionais,rw1726148778374f4a37c +Dominó,Segundo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +No jogo de dominó, as peças são divididas em dois lados, cada um com um número. Uma peça especial, chamada de bucha, tem o mesmo número nos dois lados. + +Você deve criar um código que, dadas duas variáveis representando os lados de uma peça de dominó, verifique se ela é uma bucha. Se for, imprima ""SIM"". Caso contrário, imprima ""NÃO"". + + + +**Exemplo:** + +- const ladoA = 3; + +- const ladoB = 3; + + + +A resposta esperada para este exemplo é ""SIM"". + + + + +",Condicionais,rw172614877687962c399 +Entendendo Box Model e Box Sizing com Desafio Visual,Experimente ajustar padding border e margin para ver o impacto no tamanho e no layout de uma caixa,"**Objetivo** + +Compreender como cada camada do Box Model afeta o tamanho e o posicionamento dos elementos na página. + +**Instruções** + +**1. Entenda o Box Model** + Visualize um elemento HTML como uma série de ""caixas"" empilhadas ao redor do conteúdo. Essas caixas são: `content`, `padding`, `border` e `margin`. + +**2. Experimente o Padding** + Pense em um elemento como um botão ou uma imagem. Imagine o `padding` como o espaço que ""afasta"" o conteúdo das bordas internas. Pergunte-se: o que acontece com o tamanho do elemento ao adicionar mais `padding`? + +**3. Experimente o Border** + Visualize o `border` como a linha ao redor do padding do elemento. Imagine variar a espessura e a cor do `border`. Pergunte-se: como um border fino ou grosso pode mudar a aparência e o foco do elemento na página? + +**4. Experimente o Margin** + Considere o `margin` como o espaço externo, que separa o elemento de outros ao seu redor. Imagine um card ou uma imagem com `margin` de diferentes tamanhos. Pergunte-se: qual impacto visual o `margin` tem no espaçamento entre os elementos? + +**5. Teste o Box Sizing** + Use o `box-sizing: border-box` para manter o tamanho total do elemento fixo ao adicionar padding ou border. Imagine se o tamanho visual do elemento se mantém o mesmo quando `border-box` é aplicado, em vez de `content-box`. + +**Dicas** + +- Ao usar `border-box`, observe como o `padding` e o `border` são incluídos no tamanho total do elemento, mantendo um layout mais estável. +- Imagine situações onde o ajuste de `margin`, `padding` ou `border` pode ajudar a manter o alinhamento dos elementos e evitar sobreposições. + +",Box model e Box sizing,rw17310686110054613c9 +Exibir números de 0 a 40,Primeiro exercício da lista com o objetivo de aprofundar o aprendizado," **O problema:** + +Implemente o método `mostrarNumeros`, que exibe todos os números de 0 a 40. + +- O método deve iterar de 0 a 40 e exibir cada número na sequência. + +## Exemplos: + +- Quando o método for chamado, a saída deve ser: `0, 1, 2, 3, ..., 40`. + + +",Repetição (Typescript: Lógica de Programação),rw1751553822823df99a1 +Exibir números de 0 a N,Primeiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Implemente o método `mostrarNumerosAteN`, que recebe um número N e exibe todos os números de 0 até N. + +- O método deve iterar de 0 até o valor de N e exibir cada número. + +## Exemplos: + +- Para a entrada `N = 5`, a saída deve ser: `0, 1, 2, 3, 4, 5`. +- Para a entrada `N = 10`, a saída deve ser: `0, 1, 2, 3, ..., 10`. +- Para a entrada `N = 3`, a saída deve ser: `0, 1, 2, 3`. +",Repetição,rw172788849370372c4a4 +Exibir números entre M e N,Segundo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Implemente o método `mostrarNumerosEntreMeN`, que recebe dois valores numéricos inteiros M e N e exibe todos os números entre M e N, incluindo M e N. + +- O método deve garantir que M seja menor que N e iterar de M até N. + +## Exemplos: + +- Para a entrada `M = 3` e `N = 7`, a saída deve ser: `3, 4, 5, 6, 7`. +- Para a entrada `M = 10` e `N = 15`, a saída deve ser: `10, 11, 12, 13, 14, 15`. +- Para a entrada `M = 1` e `N = 3`, a saída deve ser: `1, 2, 3`. +",Repetição,rw1727888616227ba1cbc +Explorando Seletores CSS para Estilos Personalizados,Aprenda a aplicar estilos específicos aos elementos da página usando diferentes seletores CSS e experimente sua funcionalidade,"**Objetivo** + +Aprender a selecionar e aplicar estilos a elementos específicos na sua página usando diferentes tipos de seletores CSS. Isso permitirá uma maior customização do design e maior controle sobre quais elementos recebem determinadas características visuais. + +**Instruções** + +Para este exercício, explore as ideias abaixo para entender melhor como cada seletor funciona e em quais contextos ele pode ser aplicado. Teste suas próprias hipóteses e veja os resultados na sua página. + +1. **Seletores Básicos**: +- Pense em elementos que você gostaria de estilizar de maneira única, como um título principal, parágrafos, ou uma caixa de destaque. +- Imagine: qual diferença visual faria entre aplicar uma classe versus um ID nesses elementos? Reflita sobre quando usar cada um. + +2. **Seletores Combinadores**: +- Visualize o uso de um seletor descendente: quais elementos filhos você gostaria que herdassem estilos do elemento pai? +- Tente entender como escolher entre os combinadores `>`, `+`, e `~` dependendo da estrutura de hierarquia dos elementos. Pergunte-se: como o layout mudaria ao aplicar um estilo apenas ao próximo elemento imediato em vez de todos os elementos subsequentes? + +3. **Seletores de Atributo**: +- Selecione elementos específicos baseando-se em atributos. Por exemplo, como você diferenciaria um campo de entrada para email de um para número? +- Experimente imaginar usos do seletor por prefixo ou sufixo de atributo para aplicar estilos a vários elementos com uma característica comum (ex.: classes que começam com ""btn-"" para botões). + +4. **Pseudo-Classes e Pseudo-Elementos**: +- Pense em um elemento que deve mudar de cor ou de estilo ao ser clicado ou quando o mouse passar sobre ele. Como o seletor `:hover` ajuda a criar essa interação? +- Para os pseudo-elementos `::before` e `::after`, imagine o que pode ser adicionado antes ou depois de um texto importante. Qual seria o efeito visual e a funcionalidade desse uso? + +5. **Seletores de Grupo**: +- Identifique elementos que podem compartilhar o mesmo estilo e considere agrupá-los em um único seletor. Pergunte-se: quais elementos da página podem manter a coesão visual ao compartilharem as mesmas cores ou tamanhos de fonte? + +**Dicas Adicionais**: +- Fique a vontade para usar os seletores que quiser, não é necessário utilizar todos obrigatoriamente, mas a intenção nesse exercício é usar a criatividade e testar os diferentes tipos. +- Para cada tipo de seletor, pergunte-se qual é o impacto visual e de usabilidade no design. Esteja atento a como pequenas mudanças afetam o conjunto e garantem uma página acessível e consistente. + +",Seletores CSS,rw1731003577211cc4820 +Fizz Buzz,Primeiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +- Se o número for divisível somente por `3`, o método retorna `Fizz` +- Se o número for divisível somente por `5`, o método retorna `Buzz` +- Se o número for divisível por ambos `3` e `5`, o método retorna `FizzBuzz` +- Se o número não for divisível por nenhum dos dois, o método retorna o próprio número em formato de String + +__Dicas:__ + +Utilize o operador `%` para saber se um número é divisível por outro. Para saber se um número é divisível por 2, por exemplo, podemos usar o seguinte: + +```javascript +int numero = 4; + +if (numero % 2 === 0) { + console.log(""O numero eh divisivel por 2""); +} else { + console.log(""O numero nao eh divisivel por 2""); +} +``` + +Para converter um número inteiro para String, pode-se utilizar os métodos `String()` + +```javascript +const numero = String(2); // numero == ""2"" + +``` + +## Traduz numeros divisiveis por 3 para Fizz + +- Ao receber ""3"" deve retornar ""Fizz"" +- Ao receber ""6"" deve retornar ""Fizz"" +- Ao receber ""12"" deve retornar ""Fizz"" + +## Traduz números divisíveis por 5 para Buzz + +- Ao receber ""5"" deve retornar ""Buzz"" + +## Traduz números divisíveis por 3 e por 5 para FizzBuzz + +- Ao receber ""15"" deve retornar ""FizzBuzz"" +- Ao receber ""30"" deve retornar ""FizzBuzz"" +- Ao receber ""45"" deve retornar ""FizzBuzz"" + +## Traduz números que não são diviseis para o próprio numero em forma de String + +- Ao receber ""7"" deve retornar ""7"" +- Ao receber ""2"" deve retornar ""2""",Fundamentos,rw1716905602727ecf72e +Frontend - Desenvolvendo a Interface,Crie o frontend com Next.js conecte ao backend personalize o layout e implante na Vercel,"Olá, Aluna! Nesta atividade, você começará a trabalhar com Next.js, um framework React para construção de interfaces de usuário, e explorará as seguintes tecnologias: Node.js, NPM e Vercel. O objetivo é aprender a configurar um ambiente de desenvolvimento, entender como criar e rodar uma aplicação Next.js e também aprender sobre deploy em Vercel. + +**Configuração Inicial** + +Vamos começar com um repositório base como template. A primeira etapa será clonar esse repositório para sua máquina local. + +1. Clonando o repositório + +```bash +git clone https://github.com/aceleradora-TW/acelera-movies-front-next +``` + +2. Abrir pasta do projeto + +```bash +cd acelera-movies-front-next +``` + + +**Rodando o Projeto** + +1. Abra a pasta no Visual Studio Code + +2. Abra um terminal com o comando (Crtl + `) + +3. Instale as dependências com o comando abaixo + +```bash +npm install +``` + +4. Inicie o servidor de desenvolvimento + +```bash +npm run dev +``` + +O frontend deve estar disponível em http://localhost:3000/ + + + +**Dicas** + +- Edite o arquivo app/page.tsx para modificar a aparência da página inicial. +- Utilize bibliotecas como Tailwind CSS ou Material-UI para estilizar o layout conforme suas preferências. +- Deploy na Vercel +- Configure sua conta na Vercel. +- Clique em ""New Project"" e conecte o repositório do frontend. +- Configure as variáveis de ambiente se necessário. +- Finalize o deploy e acesse o link gerado para visualizar sua aplicação. + +Bons estudos, aluna! ",Projeto Acelera Movies,rw1732628187155dfa078 +Iniciando aplicação em Next.js,Como configurar um projeto Next.js,"Vamos começar a criar aplicação Next.js, para construir aplicações modernas, rápidas e escaláveis. Durante a configuração inicial, você será guiado por uma série de perguntas para personalizar o ambiente de desenvolvimento. + +--- + +**1. Abra o Terminal** + +O terminal é a ferramenta que você usará para executar os comandos. Aqui está como abrir o terminal no seu sistema: + +- Windows: Pressione Win + R, digite cmd e pressione Enter. Você também pode usar o PowerShell ou o Windows Terminal. +- Mac: Pressione Command + Espaço, digite Terminal e pressione Enter. +- Linux: Pressione Ctrl + Alt + T ou procure por ""Terminal"" no menu de aplicativos + +**2. Iniciando a aplicação** + +Na documentação do Next.js é recomendado usar create-next-app para criar um nova aplicação, pois com esse comando os processos de instalação são automaticamente configurados. Então digitamos o seguinte comando no terminal: + +```bash +npx create-next-app@latest +``` + +**3. No momento da instalação, vão aparecer as seguintes perguntas que podem ser:** + +Na opção abaixo, você pode escolher como quer nomear sua aplicação. Por padrão, o nome vem como my-app. + +```bash +What is your project named? my-app +``` + +A seguir, vão aparecer diversas opções que podemos marcar com sim ou não: + +Nessa opção você pode escolher se quer usar TypeScript, se sim marque com a opção **Yes**.Caso contrário, vai ser utilizado o JavaScript. + +```bash +Would you like to use TypeScript? No / Yes +``` + +O ESLint permite definir um conjunto de regras e padrões que devem ser seguidas no código. + +```bash +Would you like to use ESLint? No / Yes +``` + +O Tailwind CSS é um framework com classes de CSS utilitárias. + +```bash +Would you like to use Tailwind CSS? No / Yes +``` + +Nessa opção podemos escolher se queremos usar o src como um diretório raiz. Se a opção for marcada como não, a pasta app vai ficar na raiz do projeto. + +```bash +Would you like your code inside a `src/` directory? No / Yes +``` + +É o modelo recomendado no Next que usa server components. Também organiza rotas de maneira mais moderna e modular. + +```bash +Would you like to use App Router? (recommended) No / Yes +``` + +O **Turbopack** é um empacotador experimental, mais rápido que o Webpack. Caso marque não, por padrão é usado o Webpack. + +```bash +Would you like to use Turbopack for `next dev`? No / Yes +``` + +Um alias de importação permite usar um ""apelido""(alias) para se referir a arquivos ou pastas no seu projeto, em vez de usar caminhos relativos longos. Exemplos: + +- Sem alias: `import Button from '../../../components/Button';` + + +- Com alias padrão (@/*): `import Button from '@/components/Button';` + +```bash +Would you like to customize the import alias (`@/*` by default)? No / Yes) +``` + +Se você escolheu personalizar o alias de importação na pergunta anterior, define o novo alias aqui. + +```bash +What import alias would you like configured? @/* +``` + +Após responder estas perguntas, ele vai baixar e instalar tudo que é necessário para ter um projeto Next. Para rodar o projeto, basta executar o comando abaixo na pasta do mesmo. + +```bash +npm run dev +``` + +Bom trabalho! 🚀 +",Fundamentos Next.js,rw173228144037772ee84 +Instruções importantes,Guia com os passos necessários para realizar as atividades corretamente,"**Uso obrigatório de Arrays:** +Todos os exercícios desta lista devem obrigatoriamente utilizar arrays para manipulação de dados. Evite ao máximo o uso de métodos prontos do JavaScript, como `.map()`, `.filter()`, `.reduce()`, `.reverse()`, entre outros. O objetivo é que você implemente a lógica de manipulação de arrays manualmente. + +**Tipagem:** +Lembre-se de sempre tipar corretamente todas as variáveis, parâmetros e retornos das funções. + +**Funções para cada exercício:** +Cada exercício deve ser implementado dentro de uma função. Essa função deve receber os parâmetros necessários e retornar os resultados adequados. A estrutura e a lógica de cada exercício devem estar contidas exclusivamente dentro dessas funções. + +**Respeito às boas práticas de código:** +Procure manter o código limpo e organizado, utilizando nomes de variáveis e funções claros e expressivos. Evite duplicação de código e siga uma lógica clara em suas implementações. + +## Instalação + +- Acesse o repositório: [Exercícios de Arrays](https://github.com/aceleradora-TW/Exercicios-arrays.git) +- Em seguida, faça um fork dele. +- Clone na sua máquina. +- Instale as dependências usando o comando `npm install`. + +## Como usar + +- Leia com atenção os exercícios dentro da pasta `enunciados`. +- Crie a lógica de cada exercício dentro da pasta `implementacao`. +- Para rodar um exercício específico dentro da pasta `implementacao`, é necessário usar o comando `npm run start -- nome-do-arquivo.ts`. + +**Bons estudos!** +",Array Simples,rw17278857951789628d4 +Instruções Importantes,Guia com os passos necessários para realizar as atividades corretamente,"**Uso obrigatório de laços de repetição:** + Todos os exercícios desta lista devem obrigatoriamente utilizar laços de repetição (for, while, do while etc). Evite ao máximo o uso de métodos prontos do JavaScript. O objetivo é que você implemente a lógica de repetição manualmente. + +**Tipagem:** + Lembre-se de sempre tipar corretamente todas as variáveis, parâmetros e retornos das funções. + +**Funções para cada exercício:** + Cada exercício deve ser implementado dentro de uma função. Essa função deve receber os parâmetros necessários e retornar os resultados adequados. A estrutura e a lógica de cada exercício devem estar contidas exclusivamente dentro dessas funções. + +**Respeito às boas práticas de código:** + Procure manter o código limpo e organizado, utilizando nomes de variáveis e funções claros e expressivos. Evite duplicação de código e siga uma lógica clara em suas implementações. + +## Instalação + +- Acesse o repositório: [Interacao-For-While](https://github.com/aceleradora-TW/Interacao-For-While/tree/main) +- Em seguida, faça um fork dele +- Clone na sua máquina +- Instale as dependências usando o comando `npm install` + +## Como usar + +- Leia com atenção os exercícios dentro da pasta `enunciados` +- Crie a lógica de cada exercício dentro da pasta `implementacao` +- Para rodar um exercício específico dentro da pasta `implementacao`, é necessário usar o comando `npm run start -- nome-do-arquivo.ts` + +**Bons estudos!** +",Repetição,rw172788824375369b7de +Instruções importantes,Guia com os passos necessários para realizar as atividades corretamente,"**Uso obrigatório de laços de condicionais:** + Todos os exercícios desta lista devem obrigatoriamente utilizar condicionais (if, if-else, else-if etc). +​Atenção: Não utilize bibliotecas ou métodos prontos. Construa a lógica usando apenas estruturas básicas da linguagem. +​ +​ + +**Tipagem:** + Lembre-se de sempre tipar corretamente todas as variáveis, parâmetros e retornos das funções. + +**Funções para cada exercício:** + Cada exercício deve ser implementado dentro de uma função. Essa função deve receber os parâmetros necessários e retornar os resultados adequados. A estrutura e a lógica de cada exercício devem estar contidas exclusivamente dentro dessas funções. + +**Respeito às boas práticas de código:** + Procure manter o código limpo e organizado, utilizando nomes de variáveis e funções claros e expressivos. Evite duplicação de código e siga uma lógica clara em suas implementações. + +**Instalação** + +- Acesse o repositório: [Condicionais-IF-ELSE](https://github.com/aceleradora-TW/Condicionais-IF-ELSE) +- Em seguida faça um fork dele +- Clone na sua máquina +- Instale as dependências usando o comando `npm install` + +**Como usar** + +- Leia com atenção os exercícios dentro da pasta enunciados +- Crie a lógica de cada exercício dentro da pasta implementação +- Para rodar um exercício especifico dentro da pasta implementação é necessário usar o comando `npm run start -- nome-do-arquivo.ts` + +**Bons estudos!**",Condicionais,rw1725638686995f335f2 +Instruções importantes,Guia com os passos necessários para realizar as atividades corretamente,"**O problema:** + +Uso obrigatório de laços de repetição: Todos os exercícios desta lista devem obrigatoriamente utilizar métodos prontos do JavaScript(map, filter, sort, find, etc). Evite ao máximo o uso de laços de repetição (for, while, do while etc). O objetivo é que você implemente a lógica utilizando metodos typescript. + +Tipagem: Lembre-se de sempre tipar corretamente todas as variáveis, parâmetros e retornos das funções. + +Funções para cada exercício: Cada exercício deve ser implementado dentro de uma função. Essa função deve receber os parâmetros necessários e retornar os resultados adequados. A estrutura e a lógica de cada exercício devem estar contidas exclusivamente dentro dessas funções. + +Respeito às boas práticas de código: Procure manter o código limpo e organizado, utilizando nomes de variáveis e funções claros e expressivos. Evite duplicação de código e siga uma lógica clara em suas implementações. + +**Instalação** + +- Acesse o repositório: https://github.com/aceleradora-TW/exercicio-map-filter-sort +- Em seguida faça um fork dele +- Clone na sua máquina +- Instale as dependências usando o comando ``npm install`` + +**Como usar** + +- Leia com atenção os exercicios dentro da pasta enunciados +- Crie a lógica de cada exercicio dentro da pasta implementacao + +- Utilize os arquivos JSON da pasta db caso precise de listas pré-prontas para suas implementações. + +- Para verificar se suas implementações passaram, execute os testes pelo botão de Play (Code Runner) no VS Code. +Abra um arquivo de exercício ou um arquivo de teste. + +- Clique no ícone ▶ no canto superior direito do editor. + +O script custom-test-results-processor.js exibirá no terminal uma mensagem de sucesso, caso passe no teste ou uma mensagem de insucesso, caso falhe. + + +**Observações** +1) as notas devem ter apenas 1 numero após a virgula +2) para estar aprovada a aluna tem que ter media igual ou acima de 7 +3) Para esse exercicio voces não poderão usar o `for`, `while` ou `do while` +4) Formula da média: `(a + b + c) / 3` +5) Para rodar os testes, é necessário que a extensão Code Runner esteja instalada no VS Code. +6) Verifique so o seu VS Code está atualizado, pois a execução pode não acontecer, caso existam atualizações pendentes. +7) o arquivo ""ClassData.json"", que está dentro da pasta db, contem um array pronto para ser utilizado durante os exercicios, lembrem-se de importar o array e tipo para cada arquivo de exercicio. +8) Se quiser vizualizar a saída dos exercícios no terminal, rode o exercício específico dentro da pasta implementação, usando o comando ``npm run start -- nome-do-arquivo.ts``. + + +",Métodos map filter e sort,rw175208044431077ed1e +Intercalação vetores,Segundo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Implemente um método que preencha dois vetores de 10 elementos numéricos cada um e retorne um vetor com a intercalação deles. + +- O método deve percorrer dois vetores de 10 elementos. +- O novo vetor deve alternar os elementos dos dois vetores de entrada. + +### Exemplo: + +- Quando a entrada for: + - Vetor 1: `[1, 3, 5]` + - Vetor 2: `[2, 4, 6]` +- A saída deve ser `[1, 2, 3, 4, 5, 6]`. +",Array Simples,rw1727886940271b774a5 +Isenção de impostos,Quarto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Todos os anos os cidadãos brasileiros e pessoas com residência permanente devem declarar o Imposto de Renda. Segundo a Receita Federal, algumas pessoas estão isentas do pagamento de imposto de renda (IR). Abaixo segue uma lista simplificada das pessoas isentas: + + + +- Pessoas com renda mensal menor ou igual a R$ 3.036,00 reais + +- Pessoas com rendimentos tributáveis de até R$ 33.888,00 reais ao ano; + +- Aposentados e pensionistas com doenças graves previstas em lei. + + + +Faça um programa que determine, com base nos critérios acima, se a pessoa está ou não isenta de pagar o imposto de renda. Caso a pessoa pertença ao grupo de isenção o programa deve imprimir na tela: **ISENTA**, caso a pessoa deva pegar IR imprima na tela: **PEGA LEAO** + + +```javascript + const aposentada = false; + + const portadoraDeDoenca = false; + + const totalDeRendimentos = 34000; + + //seu código aqui +``` +​ +Neste exemplo a resposta correta é **PEGA LEAO** + +Teste seu programa para outras variações da entrada. + + + +",Condicionais,rw1726149090018cb2662 +Loja de artesanato vendas,Quarto exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + +Uma loja de artesanato possui um vendedor que recebe R$400,00 mais 5% do valor total de suas vendas. Crie um método que leia o código, preço unitário e quantidade vendida de 10 produtos. O método deve retornar: + +- Um relatório com código, quantidade, valor unitário e total vendido para cada objeto. +- O valor geral das vendas e a comissão do vendedor. +- O código do objeto mais vendido. + +### Exemplo: + +- Quando a entrada for: + - Código: `001` + - Quantidade vendida: `10` + - Preço unitário: `R$20,00` +- A saída deve ser: + - Relatório: `Código: 001, Quantidade: 10, Valor unitário: R$20,00, Total vendido: R$200,00` + - Total das vendas: `R$200,00` + - Comissão: `R$10,00` + - Objeto mais vendido: `001`. +"," Array simples (Typescript: Lógica de Programação)",rw17515535995444bdcb3 +Maior e menor valor de quatro números,Oitavo exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + + Crie uma função chamada maiorEMenorEntreQuatro que receba quatro números inteiros. A função deve identificar o maior e o menor valor entre os quatro. + +O que você deve fazer: + +Receber quatro números inteiros como entrada. + +Comparar os quatro valores para encontrar: + +O maior entre eles. + +O menor entre eles. + +Retornar ambos os valores. + +## Exemplos: + +maiorEMenorEntreQuatro(1, 2, 3, 4); + +Entrada: 1, 2, 3, 4 → Saída: ""Maior: 4, Menor: 1"" + +maiorEMenorEntreQuatro(-1, 0, -10, 20); + +Entrada: -1, 0, -10, 20 → Saída: ""Maior: 20, Menor: -10"" + + +",Condicionais (Typescript: Lógica de Programação),rw1751552848491ebd141 +Medindo a Cobertura de Código,O objetivo desta atividade é explorar como o Jest mede a cobertura de código em um projeto simples,"Nesta atividade, você vai medir a cobertura de código de um projeto simples. +O objetivo é entender como o Jest mede a cobertura e como gerar relatórios. + +--- + +**Objetivo** + +Escrever algumas funções simples, como uma função de soma e subtração. +Rodar os testes com cobertura para garantir que o código está bem testado. + +--- + +**Exemplo de código:** + +```javascript +// calculator.js +function add(a, b) { + return a + b; +} + +function subtract(a, b) { + return a - b; +} + +module.exports = { add, subtract }; +``` + +```javascript +// calculator.test.js +const { add, subtract } = require('./calculator'); + +test('soma dois números', () => { + expect(add(1, 2)).toBe(3); +}); + +test('subtrai dois números', () => { + expect(subtract(5, 3)).toBe(2); +}); +``` + +--- + +**Rodando os Testes com Cobertura** + +```bash +npx jest --coverage +``` + +--- + + +**Critérios de Aceitação** + +O relatório de cobertura deve mostrar que todas as linhas do código foram cobertas pelos testes. + +--- + +**Recursos** + +- Use Jest para medir a cobertura de código. + +--- + +**Tecnologias Recomendadas** + +- Jest para testes unitários. +​ +"," Cobertura de Código",rw1732811211638964415 +Menor e maior valor,Terceiro exercício da lista com o objetivo de aprofundar o aprendizado," **O problema:** + + Crie uma função chamada compararDoisNumeros que receba dois números inteiros. A função deve identificar e retornar qual é o maior e qual é o menor valor. + +## Exemplos: + +compararDoisNumeros(5, 10); + +Entrada: 5 e 10 → Saída: ""Maior: 10, Menor: 5"" + +compararDoisNumeros(7, 7); + +Entrada: 7 e 7 → Saída: ""Maior: 7, Menor: 7"" + + +",Condicionais (Typescript: Lógica de Programação),rw1751552688513b36111 +Modelagem do banco,"Como Configurar a Conexão com o Banco, Gerar o Cliente e Modelar os Dados da Aplicação","Nesta atividade você vai instalar e configurar o **Prisma Client** seguindo o padrão **Singleton**. + +--- + +**Objetivo** + +​O objetivo é garantir uma configuração eficiente e segura para evitar problemas de performance e conexões duplicadas com o banco de dados. +​ +- Instalar o Prisma CLI e o Prisma Client. +- Configurar o Prisma Client com o padrão Singleton. +- Gerar o Prisma Client a partir do `schema.prisma`. +- Criar um script para inserir e listar tarefas usando o Prisma Client. + +--- + +**Instruções Passo a Passo** + + +**Passo 1: Verificar e Instalar Dependências** + +```bash +npm install prisma --save-dev +npm install *prisma/client +npm install --save-dev ts-node typescript *types/node +``` + +​ +**Passo 2: Inicializar o Prisma** + +```bash +npx prisma init +``` + +**Passo 3: Configurar o Schema** + +Edite o arquivo ` prisma/client`: + +````prisma +generator client { + provider = ""prisma-client-js"" +} + +datasource db { + provider = ""sqlite"" + url = env(""DATABASE_URL"") +} + +model Task { + id Int *id *default(autoincrement()) + title String + completed Boolean *default(false) + createdAt DateTime *default(now()) +} +```` + +**Passo 4: Configurar o arquivo .env** + +Crie ou edite `.env` na raiz: + +````env +DATABASE_URL=""file:./dev.db"" +```` + +**Passo 5: Criar a pasta `lib` e o arquivo `prisma.ts`** + +```bash +mkdir lib +``` + +Crie o arquivo `lib/prisma.ts`: + +````typescript +// lib/prisma.ts +import { PrismaClient } from '*prisma/client' + +declare global { + var prisma: PrismaClient | undefined +} + +const client = globalThis.prisma || new PrismaClient() + +if (process.env.NODE_ENV !== 'production') { + globalThis.prisma = client +} + +export default client +```` + +**Passo 6: Configurar o TypeScript** + +Crie `tsconfig.json` na raiz do projeto: + +````json +{ + ""compilerOptions"": { + ""target"": ""ES2020"", + ""module"": ""commonjs"", + ""lib"": [""ES2020""], + ""outDir"": ""./dist"", + ""rootDir"": ""./"", + ""strict"": true, + ""esModuleInterop"": true, + ""skipLibCheck"": true, + ""forceConsistentCasingInFileNames"": true, + ""resolveJsonModule"": true, + ""moduleResolution"": ""node"", + ""allowSyntheticDefaultImports"": true, + ""declaration"": true, + ""sourceMap"": true + }, + ""ts-node"": { + ""esm"": false, + ""experimentalSpecifierResolution"": ""node"", + ""transpileOnly"": true, + ""files"": true, + ""compilerOptions"": { + ""module"": ""commonjs"" + } + }, + ""include"": [""**/*.ts""], + ""exclude"": [""node_modules"", ""dist""] +} +```` + +**Passo 7: Criar ou Corrigir o arquivo `script.ts`** + +````typescript +// script.ts +import prisma from './lib/prisma' + +async function main() { + console.log(' Iniciando script...') + + const novaTarefa = await prisma.task.create({ + data: { + title: 'Aprender a usar o Prisma Client', + }, + }) + console.log(' Nova tarefa criada:', novaTarefa) + const todasAsTarefas = await prisma.task.findMany() + console.log(' Todas as tarefas no banco:') + console.dir(todasAsTarefas, { depth: null }) +} + +main() + .catch((e) => { + console.error(e) + process.exit(1) + }) + .finally(async () => { + await prisma.$disconnect() + console.log(' Script finalizado.') + }) +```` + +**Passo 8: Gerar o Prisma Client e Criar o Banco** + +```bash +npx prisma generate +npx prisma db push +``` + +**Passo 9: Executar o script** + +```bash +npx tsx script.ts +``` + + + + + +",PrismaORM,rw1749913231498b36ede +Montanha Russa Muito Assustadora,Quinto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Você está desenvolvendo o sistema de acesso para a **Montanha Russa Muito Assustadora**. As regras para permitir ou negar a entrada de usuários são as seguintes: + +**Requisitos de Acesso:** + +- Idade: Pessoas entre 12 e 65 anos (inclusive). + +- Saúde: Não podem ter patologias cardíacas. + +- Altura: Devem ter no mínimo 150cm. + +Se a pessoa não cumprir qualquer um desses requisitos, o sistema deve imprimir ""ACESSO NEGADO"". + +**Regras de Preço:** + +Para quem tem acesso permitido, o valor do ingresso é: + +- R$ 10,00 (meia-entrada) para estudantes ou menores de 18 anos. + +- R$ 20,00 para os demais casos. + +Seu papel é imprimir na tela: + +- **ACESSO NEGADO** caso a pessoa não possa brincar + +- **10 reais** caso esse seja o valor que a pessoa deve pagar para brincar + +- **20 reais** caso esse seja o valor que a pessoa deve pagar para brincar + +```javascript +const idade = 18; +const possuiPatologia = false; +const altura = 180; +const ehEstudante = false; + +``` + +Para este exemplo a resposta correta é `20 reais` + +Lembre-se de testar seu código para outras variações de entrada.",Condicionais,rw17552773848501ad9ee +Mostrar o maior valor digitado,Terceiro exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + +Implemente o método `mostrarMaiorValor`, que recebe um array de números e retorna o maior valor digitado. + +- O método deve iterar sobre os números e identificar o maior valor. + +## Exemplos: + +- Para a entrada `[10, 25, 3, 18]`, a saída deve ser: `25`. +- Para a entrada `[1, 100, 45, 60]`, a saída deve ser: `100`. +- Para a entrada `[7, 7, 7]`, a saída deve ser: `7`. +",Repetição (Typescript: Lógica de Programação),rw1751554432252955c80 +Mostrar o segundo maior valor digitado,Terceiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Implemente o método `mostrarSegundoMaiorValor`, que recebe um array de números e retorna o segundo maior valor digitado. + +- O método deve identificar o maior valor e o segundo maior valor em uma única iteração. + +## Exemplos: + +- Para a entrada `[10, 25, 3, 18]`, a saída deve ser: `18`. +- Para a entrada `[50, 100, 99, 80]`, a saída deve ser: `99`. +- Para a entrada `[5, 5, 5, 3]`, a saída deve ser: `3`. +",Repetição,rw1727888759901a297ca +Múltiplo de 3,Quinto exercício da lista com o objetivo de aprofundar o aprendizado," **O problema:** + + Crie uma função chamada verificarMultiploDeTres que receba um número inteiro. A função deve retornar ""é múltiplo de 3"" se o número for divisível por 3, ou ""não é múltiplo de 3"" caso contrário. + +## Exemplos: + +verificarMultiploDeTres(9); + +Entrada: 9 → Saída: ""é múltiplo de 3"" + +verificarMultiploDeTres(10); + +Entrada: 10 → Saída: ""não é múltiplo de 3"" + +verificarMultiploDeTres(0); + +Entrada: 0 → Saída: ""é múltiplo de 3"" + + +",Condicionais (Typescript: Lógica de Programação),rw1751552757468282e36 +Navegação com React Router,Crie uma navegação simples entre páginas utilizando o Reat Router no Next.js,"**Instruções:** + +1. **Configure o React Router no seu projeto:** + - Instale o React Router com o comando: + ```bash + npm install react-router-dom + ``` + +2. **Crie um arquivo `app/routes.tsx` para definir as rotas do projeto.** + +3. **Crie duas páginas:** + - **Home:** + - A página inicial com um botão para redirecionar para a página About. + - **About:** + - Uma página simples com um título e uma mensagem. + +4. **No componente Home:** + - Adicione um botão com o texto **""Ir para About""**. + - Utilize o hook **useNavigate** do React Router para redirecionar o usuário ao clicar no botão. + +5. **Configure o React Router para gerenciar as rotas do projeto:** + - Utilize o componente `BrowserRouter` para envolver seu aplicativo. + - Use o componente `Router` para definir as rotas. + +--- + +**Dica:** +- Utilize o componente `BrowserRouter` como o provedor de rotas. +- Para redirecionamento programático, use o hook **useNavigate**. ",Direcionamento de Páginas,rw1732639866885f3bd9f +Nome para exibição,Sétimo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +​Considerando que uma pessoa pode ter nome, sobrenome e/ou apelido, crie um código que imprima o nome da pessoa no console, seguindo esta ordem de prioridade: + +- Apelido: Se a variável apelido estiver preenchida, imprima apenas o seu valor. +- Nome e Sobrenome: Se a variável apelido não estiver preenchida, verifique se o sobrenome existe. +- Se o sobrenome estiver preenchido, imprima o primeiroNome seguido de um espaço e o sobrenome. +- Se o sobrenome não estiver preenchido, imprima apenas o primeiroNome. + +Lembre-se que o primeiroNome é sempre obrigatório e estará preenchido. + +**Exemplos** + +​1. Apelido preenchido + +```javascript +const primeiroNome = ""Mario""; +​const sobrenome = """"; +​const apelido = ""Bros""; +// Saída esperada: Bros +``` + +​2. Sobrenome preenchido + +```javascript +const primeiroNome = ""Mario""; +const sobrenome = ""Bros""; +const apelido = """"; +// Saída esperada: Mario Bros +``` + +​3. Apenas o primeiro nome + +```javascript +const primeiroNome = ""Mario""; +const sobrenome = """"; +const apelido = """"; +// Seu código aqui +// Saída esperada: Mario +``` + +",Condicionais,rw1755277672141849448 +Notas faixa,Terceiro exercício da lista com o objetivo de aprofundar o aprendizado," **O problema:** + +Elabore um método que leia uma série de 50 notas e uma média necessária para aprovação. O método deve retornar quantas notas estão no intervalo de 10% abaixo e 10% acima da média. + +- O método deve calcular a faixa de aprovação (10% abaixo e 10% acima da média) e contar quantas notas estão nesse intervalo. + +### Exemplo: + +- Quando a entrada for: + - Notas: `[50, 60, 70, 80, 90]` + - Média: `70` +- A saída deve ser `2 notas estão entre 63 e 77`. + +"," Array simples (Typescript: Lógica de Programação)",rw1751553414853317534 +Números Armstrong,Quarto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Números de Armstrong são números onde a soma de cada algarismo elevado à quantidade de algarismos é igual ao número original. Por exemplo: + +- Para verificar se o número 9 é um número de Armstrong, fazemos o seguinte cálculo: + - \(9\) (o primeiro algarismo do número original) elevado a \(1\) (a quantidade de algarismos do número original). + - Portanto, \(9^1 = 9\), logo 9 é sim um número de Armstrong. + +- Agora, considere o número 13: + - \(1\) (primeiro algarismo) elevado a \(2\) (total de algarismos) mais \(3\) (segundo algarismo) elevado a \(2\) (total de algarismos). + - O cálculo seria \(1^2 + 3^2 = 1 + 9 = 10\), logo 13 não é um número de Armstrong. + +- Para o número 153: + - \(1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153\) + - Portanto, 153 é um número de Armstrong. + +Escreva algum código para determinar se um número é um número Armstrong. Pense nos casos de teste: + +## Retorna mensagem de sucesso quando o número for de Armstrong + +- Identifica ""3"" corretamente, respondendo ""Este é um número de Armstrong!"" +- Identifica ""153"" corretamente, respondendo ""Este é um número de Armstrong!"" + +## Retorna mensagem de aviso quando o número NÃO for de Armstrong + +- Identifica ""10"" corretamente, respondendo ""Este não é um número de Armstrong!"" +- Identifica ""154"" corretamente, respondendo ""Este não é um número de Armstrong!""",Fundamentos,rw1725642166308a69249 +Objeto de data,Segundo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Implemente o método criaObjeto, que recebe como argumento uma string no formato `dd/mm/aaaa`, e retorna um objeto, do tipo: + +```javascript +{ + dia: dd, + mes: mm, + ano: aaaa +} +``` + +## Casos de teste + +- Quando a entrada for ""12/08/2020"", a saida deve ser ""{ dia: 12, mes: 08, ano: 2020 }"" +- Quando a entrada for ""08/01/2012"", a saida deve ser ""{ dia: 08, mes: 01, ano: 2012 }"" +- Quando a entrada for ""24/03/2000"", a saida deve ser ""{ dia: 24, mes: 03, ano: 2000 }"" +",Fundamentos,rw1725642159329a2d9f4 +Par ou ímpar,Primeiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +​ +Duas pessoas estão jogando par ou ímpar. O primeiro usuário escolhe um número e o segundo usuário escolhe outro. A soma desses dois números determina o vencedor. + +Você deve imprimir ""par"" se a soma dos números for par, indicando que o usuário que escolheu par venceu. Você deve imprimir ""ímpar"" se a soma dos números for ímpar, indicando que o usuário que escolheu ímpar venceu. + +```javascript= +const jogada1 = 5; +const jogada2 = 3; + +//seu código aqui +``` +Observação: A soma das jogadas é 5 + 3 = 8. Como 8 é um número par, a resposta deve ser par. + +Lembre-se de testar seu código para outras variações de entrada.",Condicionais,rw1726148767193d37419 +Par ou impar,Quarto exercício da lista com o objetivo de aprofundar o aprendizado," **O problema:** + + + + Crie uma função chamada verificarParOuImpar que receba um número inteiro. A função deve retornar ""PAR"" se o número for par e ""ÍMPAR"" se o número for ímpar. + + + +## Exemplos: + + + +verificarParOuImpar(4); + + + +Entrada: 4 → Saída: ""PAR"" + + + +verificarParOuImpar(7); + + + +Entrada: 7 → Saída: ""ÍMPAR"" + + + +verificarParOuImpar(0); + + + +Entrada: 0 → Saída: ""PAR"" + + + +",Condicionais (Typescript: Lógica de Programação),rw17515527172787e011c +Personalizando Fontes na Página,Personalize sua página aplicando estilos de fontes e explore o poder do CSS para criar uma tipografia única e envolvente!," +**Objetivo** + +Praticar o uso das propriedades de fontes no CSS, ajustando o estilo, o tamanho, e outros detalhes para criar uma tipografia mais personalizada e envolvente na sua página. + +**Instruções** + +1. **Seleção de Fontes** + + Aplique diferentes tipos de fontes ao longo da sua página. Use fontes genéricas ou experimente fontes personalizadas, como Google Fonts, para criar um estilo único. + +2. **Ajustes de Tamanho e Peso** + + Experimente definir diferentes tamanhos e pesos de fonte para cada seção da sua página. Teste variações para criar uma hierarquia visual clara, tornando as informações mais fáceis de ler. + +3. **Exploração de Estilos e Espaçamentos** + + Escolha trechos do texto para aplicar estilos como itálico, negrito ou pequenas variações de altura de linha. Isso ajudará a destacar partes importantes e dará um toque mais profissional à página. + +**Resultado Esperado** + +Sua página deve refletir um uso prático e personalizado das propriedades de fontes, com um visual mais organizado e atraente. A leitura e a navegação pelos textos devem ser claras e convidativas, mantendo a consistência tipográfica em toda a página. + +**Dicas Adicionais** + +- Explore várias combinações de fonte e tamanho para encontrar um estilo que harmonize com o conteúdo da sua página. +- Não é obrigatório aplicar todas as propriedades aprendidas; escolha aquelas que melhor atendem ao design desejado. +- Ao finalizar, revise a página para garantir que o texto está legível e que o estilo geral da tipografia é consistente e profissional.",Fontes,rw17309914063027a4e65 +Pontuação do concurso,Quarto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Crie um método que leia a pontuação final de 25 provas de um concurso e os nomes dos respectivos participantes. O método deve retornar os participantes que obtiveram mais de 70 pontos. + +- O método deve percorrer as pontuações e listar os nomes dos participantes que atingiram mais de 70 pontos. + +### Exemplo: + +- Quando a entrada for: + - Nome: `João` + - Pontuação: `75` +- A saída deve ser `João obteve mais de 70 pontos`. +",Array Simples,rw1727887863868c37cc0 +Positivo negativo ou nulo,Segundo exercício da lista com o objetivo de aprofundar o aprendizado," **O problema:** + +Crie uma função chamada verificarSinal que receba um número inteiro. A função deve retornar uma das seguintes mensagens: ""POSITIVO"", ""NEGATIVO"" ou ""NULO"", dependendo do valor do número. + +## Exemplos: + +verificarSinal(5); + +​ +​​Entrada: 5 → Saída: ""POSITIVO"" +​ +​ +​ +verificarSinal(-3); + +​ +​​ +​Entrada: -3 → Saída: ""NEGATIVO"" + +​ +​​ +verificarSinal(0); + +​​​ +​​Entrada: 0 → Saída: ""NULO"" +​ + +",Condicionais (Typescript: Lógica de Programação),rw1751552572795b6b20e +Primeiros Comandos Usando Git,Criando e Gerenciando um Repositório Git,"Abra o terminal ou Git Bash: +No Windows, procure por ""Git Bash"" no menu iniciar e abra. +No macOS ou Linux, abra o aplicativo ""Terminal"". + +Passos: + +Configurações iniciais do Git: + +Antes de começar, configure seu nome de usuário e email no Git. Esses dados serão utilizados para identificar quem fez os commits. No terminal, digite os seguintes comandos: + +**git config --global user.name ""Seu Nome""** +**git config --global user.email ""seuemail example.com""** + +Essas configurações serão aplicadas globalmente, ou seja, para todos os repositórios que você criar ou gerenciar no seu computador. + + +Crie uma pasta de projeto no seu computador: + +No terminal, navegue até a pasta onde deseja criar seu projeto. Para isso, use o comando cd (change directory). Por exemplo: + +**cd ~/Documentos/Projetos** + +Crie uma nova pasta para o projeto, chamada meu-projeto-git, com o comando: + +**mkdir meu-projeto-git** + +Entre na pasta recém-criada: + +**cd meu-projeto-git** + +Inicialize o Git no projeto: + +Agora, dentro da pasta do projeto, inicialize um repositório Git: + +**git init** + +Esse comando cria uma pasta oculta chamada .git, que o Git usa para rastrear as alterações no projeto. + +Crie um arquivo de README: + +Crie um arquivo chamado **README.md** com a descrição do projeto. Se estiver no terminal, você pode usar um editor de texto como o **nano** ou abrir o arquivo em um editor de sua preferência. + +**nano README.md** + +No arquivo, adicione o seguinte texto: + +**# Meu Projeto Git +Este é um projeto de exemplo para aprender Git.** + +Salve o arquivo e feche o editor. No nano, isso é feito pressionando Ctrl+O para salvar e Ctrl+X para sair. + +Verifique o status do repositório: + +Verifique o status atual do repositório para ver quais arquivos foram modificados e estão prontos para serem adicionados ao Git: + +**git status** + + +Adicione o arquivo ao repositório: + +Adicione o arquivo README.md à área de stage (preparado para commit): + +**git add README.md** + +Faça o commit das alterações: + +Agora que o arquivo está no stage, faça o commit para salvar as alterações no histórico do repositório: + +**git commit -m ""Adiciona o arquivo README.md""** + +## Bons Estudos!",Como utilizar o GitHub e Git,rw17279755805932f4be4 +Prisma Migrate e Prisma Client,Neste exercício você vai criar sua primeira tabela em um banco de dados sem escrever uma única linha de código SQL utilizando o Prisma Migrate," Seguindo o exercício anterior, você criou sua primeira tabela no banco de dados sem escrever uma única linha de código SQL. Usando o Prisma Migrate, você definiu um modelo de dados Task e executou uma migração automática, demonstrando como o Prisma transforma definições de schema em estruturas de banco funcionais. + +​ +**Passo 1: Edite o arquivo prisma/client:** + +```bash +generator client { + provider = ""prisma-client-js"" +} + +datasource db { + provider = ""sqlite"" + url = ""file:./dev.db"" +} + +model Task { + id Int *id *default(autoincrement()) + title String + completed Boolean *default(false) + createdAt DateTime *default(now()) +} +``` + +--- + +**Passo 2: Reset do banco e Executar a Migração** + +```bash +npx prisma migrate reset +npx prisma migrate dev --name create_tasks_table +``` + +--- + + +**Passo 3: Gerar o Cliente** + + +```bash +npx prisma generate +``` +--- + +**Passo 4: ​Criar o script MIGRATE:** + +Crie o arquivo migrate-simple.ts na raiz do projeto: + +```ts +import prisma from './lib/prisma' + +async function main() { + console.log(' Testando Prisma Migrate - Modelo Task\n') + + try { + // Verificar se o modelo Task está disponível após a migração + console.log(' Verificando modelo Task...') + console.log('- Task model:', typeof prisma.task) + + if (typeof prisma.task !== 'object') { + console.log(' Modelo Task não encontrado!') + console.log(' Execute: npx prisma migrate dev --name create_tasks_table') + return + } + + // Limpar dados existentes + await prisma.task.deleteMany() + console.log(' Tarefas antigas removidas') + + // CREATE - Criar tarefas + console.log('\n Criando tarefas...') + const task1 = await prisma.task.create({ + data: { + title: 'Estudar Prisma Migrate', + completed: false + } + }) + + const task2 = await prisma.task.create({ + data: { + title: 'Testar migrações', + completed: true + } + }) + + console.log(' Tarefas criadas:', task1.title, '|', task2.title) + + // READ - Ler tarefas + console.log('\n Lendo todas as tarefas...') + const allTasks = await prisma.task.findMany({ + orderBy: { createdAt: 'asc' } + }) + console.log(' Total de tarefas:', allTasks.length) + + allTasks.forEach(task => { + const status = task.completed ? '✅' : '⏳' + console.log(`${status} ${task.title}`) + }) + + // UPDATE - Marcar tarefa como concluída + console.log('\n Marcando primeira tarefa como concluída...') + const updatedTask = await prisma.task.update({ + where: { id: task1.id }, + data: { completed: true } + }) + console.log(' Tarefa atualizada:', updatedTask.title) + + // READ - Filtrar tarefas concluídas + console.log('\n Tarefas concluídas:') + const completedTasks = await prisma.task.findMany({ + where: { completed: true } + }) + console.log(' Total concluídas:', completedTasks.length) + + // DELETE - Deletar uma tarefa + console.log('\n Deletando uma tarefa...') + await prisma.task.delete({ + where: { id: task2.id } + }) + console.log(' Tarefa deletada com sucesso') + + // Verificar resultado final + const remainingTasks = await prisma.task.count() + console.log(' Tarefas restantes:', remainingTasks) + + } catch (error) { + console.error(' Erro:', error) + console.log('\n Certifique-se de que executou:') + console.log('1. npx prisma migrate dev --name create_tasks_table') + console.log('2. npx prisma generate') + } finally { + await prisma.$disconnect() + console.log('\n Migrate test finalizado') + } +} + +main() +``` + +​Execute o teste: + + +```bash +npx tsx migrate-simple.ts +``` + +",PrismaORM,rw1750769620065527d4b +Produtos e lucros,Terceiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido,"**O problema:** + +Faça um método que leia o nome, o custo e o preço de venda de 50 produtos. O método deve contar quantos produtos têm: + +- Lucro menor que 10% +- Lucro entre 10% e 30% +- Lucro maior que 30% + +- O método deve calcular o lucro percentual de cada produto e contar quantos produtos se encaixam em cada faixa de lucro. + +### Exemplo: + +- Quando a entrada for: + - Nome: `Produto A` + - Custo: `R$50,00` + - Preço de venda: `R$55,00` +- A saída deve ser `Lucro entre 10% e 30%`. + +",Array Simples,rw1727887740711bbc6c1 +Publicando seu Projeto com Netlify,"Aprenda a realizar o deploy de seu site no Netlify, configurando deploys automáticos e garantindo atualizações simples e eficientes","**Objetivo** + +Realizar o **deploy** de um projeto já desenvolvido, utilizando o Netlify como plataforma de hospedagem. Este exercício permitirá que você aprenda a publicar seu site de forma prática e eficiente, disponibilizando-o online para acesso público. Além disso, você entenderá como configurar deploys automáticos, garantindo que futuras atualizações sejam aplicadas sem complicações. + + +**Instruções** + +1. **Preparando os Arquivos para o Deploy** + Certifique-se de que o projeto desenvolvido nos exercícios anteriores está completo e organizado. Todos os arquivos do seu site, como HTML, CSS, JavaScript e quaisquer imagens ou recursos adicionais, devem estar reunidos em uma única pasta. + + Revise o código para garantir que não existam erros que possam comprometer a funcionalidade ou a apresentação do site. Se houver algum arquivo desnecessário, remova-o para manter o projeto limpo e organizado. + +2. **Acessando o Netlify** + - Visite o site [Netlify](https://netlify.com) e clique em **Sign Up** para criar uma conta gratuita ou em **Log In** se já tiver uma. + - Após realizar o login, você será direcionado ao painel principal, onde poderá visualizar e gerenciar seus projetos hospedados no Netlify. + +3. **Deploy Manual (Para Projetos Simples)** + - No painel do Netlify, clique no botão **""Add New Site""**. Em seguida, selecione a opção **""Deploy manually""**. + - Você será levado para uma página onde poderá arrastar e soltar os arquivos do seu site. Localize a pasta do projeto no seu computador, selecione todos os arquivos e arraste-os para a área de upload no Netlify. + - O Netlify fará o upload e processará automaticamente os arquivos, configurando o ambiente necessário para que seu site funcione corretamente. + + Após a conclusão do processo, o Netlify gerará um link público único que permitirá que qualquer pessoa acesse o seu site. + + - **Personalize o Domínio (Opcional):** + Para tornar o link mais amigável, vá até as configurações do site clicando em **""Site Settings""**. Em **""Domain Settings""**, você pode alterar o subdomínio padrão ou conectar um domínio personalizado, como `www.seusite.com`. + +4. **Deploy Automatizado com GitHub** + - Caso tenha versionado seu projeto com GitHub, você pode configurar o deploy automatizado. No painel do Netlify, clique novamente em **""Add New Site""** e escolha a opção **""Import from Git""**. + - Autorize o Netlify a acessar sua conta do GitHub. Uma vez conectado, você verá uma lista de repositórios. Selecione o repositório que contém o projeto que deseja publicar. + - Escolha a branch que será monitorada (geralmente ""main"" ou ""master""). Se o projeto for mais complexo (usando frameworks como React ou Vue), defina o comando de build, por exemplo: + ```bash + npm run build + ``` + - Uma vez configurado, o Netlify monitorará a branch escolhida. Toda vez que você fizer um `push` para o repositório, o Netlify automaticamente realizará o build e atualizará o site. + +5. **Verificando o Deploy** + - Após o deploy, acesse o link público gerado pelo Netlify para visualizar o seu site. + - Teste o site em diferentes dispositivos e resoluções para garantir que ele funcione corretamente em todas as telas. + - Se algo não estiver funcionando como esperado, você pode revisar os logs de build no painel do Netlify para identificar possíveis problemas e corrigi-los. + + +**Resultado Esperado** + +Ao concluir o exercício, seu projeto estará disponível online por meio de um link público gerado pelo Netlify. Com a configuração do deploy automatizado via GitHub, qualquer alteração feita no repositório será refletida automaticamente no site, garantindo que ele esteja sempre atualizado sem a necessidade de passos manuais adicionais. + + +**Próximos Passos** + +Com o site publicado, você pode começar a explorar outras funcionalidades oferecidas pelo Netlify, como configurações avançadas de deploy, integração com ferramentas de análise de tráfego e otimização de performance. Além disso, continue refinando o projeto com novas funcionalidades e melhorias."," Deploy com o Netlify",rw1731946635738b8a139 +Refatorando Arrays,Primeiro exercício da lista com objetivo de fixar os conceitos da refatoração em TypeScript,Refatore os exercícios do topico [**Arrays Simples**](https://staging--e-acelera-homologacao.netlify.app/Nivelamento/rw1720014886324a56ac2-Typescript:%20Lógica%20de%20Programação/rw1727203515904ad3fa2-Array%20Simples) do tema **TypeScript: Lógica de programação.**,Principais Técnicas de Refatoração em TypeScript,rw172795995480204cc77 +Refatorando Testes para Melhor Manutenção,"Nesta atividade, você vai refatorar um conjunto de testes para garantir que eles sejam organizados e fáceis de manter.","Nesta atividade, você vai refatorar um conjunto de testes para garantir que eles sejam organizados e fáceis de manter. O objetivo é garantir que os testes sejam reutilizáveis, claros e eficientes. A refatoração envolve o uso de boas práticas, como agrupar testes com `describe` e escrever os testes de forma que cubram diferentes cenários. + +**Objetivo** +- Refatorar os testes para garantir que eles sejam organizados e reutilizáveis. +- Criar um conjunto de testes que cubra diferentes cenários de maneira clara e eficiente. + +**Exemplo de código**: + +```javascript +// calculator.js +function multiply(a, b) { + return a * b; +} + +function divide(a, b) { + if (b === 0) throw new Error('Cannot divide by zero'); + return a / b; +} + +module.exports = { multiply, divide }; + +// calculator.test.js +const { multiply, divide } = require('./calculator'); + +describe('Funções de cálculo', () => { + test('multiplica dois números', () => { + expect(multiply(2, 3)).toBe(6); + }); + + test('divide dois números', () => { + expect(divide(6, 2)).toBe(3); + }); + + test('não pode dividir por zero', () => { + expect(() => divide(6, 0)).toThrow('Cannot divide by zero'); + }); +}); +``` +--- + +**Critérios de Aceitação** +- Os testes devem estar bem organizados, com describe e test claros. +- Os testes devem cobrir os cenários mais comuns e de erro. + +--- + +**Recursos** +- Use boas práticas para escrever testes reutilizáveis e organizados. +- Tecnologias Recomendadas +- Jest para testes unitários. +",Boas Práticas de Testes,rw1732803174198ffbf6a +Retornar a aluna com menor nota,"Nesta atividade, você irá retornar o nome da aluna com a menor nota","**O problema:** + +Faça uma função que receba uma lista pré-construída e retorne o nome da aluna com menor nota. +",Métodos map filter e sort,rw1755093112006fb018e +Retornar nomes das aprovadas,"Nesta atividade, você vai implementar as funções, usando métodos de array, para retornar os nomes das alunas aprovadas.","**O problema:** + +Faça uma função que receba uma lista pré-construída e retorne um array com os nomes das alunas aprovadas. +",Métodos map filter e sort,rw17549300132192ebb02 +Retornar objeto com as informações das alunas,"Nesta atividade, você irá retornar um objeto com as informações das alunas aprovadas","**O problema** + +Fazer uma função que receba a lista pre constuida retorne um array de objetos com as seguintes propriedades: +```javascript + [ + { + nome: String , + media: Number, + aprovada: Boolean + } + ] +``` +**Exemplo de saída:** + +Deve ser feito calculo de media e retornada as seguintes informações de cada aluna: +```javascript + [ + { nome: ""Ashley"", media: 7.1, aprovada: true }, + { nome: ""Sabrina"", media: 7.9, aprovada: true }, + { nome: ""Samantha"", media: 5.0, aprovada: false } + ] +``` +",Métodos map filter e sort,rw1755092831407e570c5 +Soma com ajuste,Sétimo exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + + Crie uma função chamada somaComAjuste que receba dois números inteiros. A função deve somar os dois valores e, dependendo do resultado, fazer um ajuste: + +Se a soma for maior que 20, adicione 8 ao valor. + +Se a soma for menor ou igual a 20, subtraia 5 do valor. + +## Exemplos: + +somaComAjuste(15, 10); + +Entrada: 15 e 10 → Soma: 25 → Resultado ajustado: 33 + +somaComAjuste(12, 7); + +Entrada: 12 e 7 → Soma: 19 → Resultado ajustado: 14 + + +",Condicionais (Typescript: Lógica de Programação),rw1751552821533df6b2b +Soma de intervalos,Quarto exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + + + +Implemente o método `somarNumerosEntreMeN`, que recebe dois números M e N e retorna a soma de todos os números entre eles, inclusive M e N. + + + +- O método deve continuar pedindo pares até que o valor de M seja maior que N. + + + +## Exemplos: + + + +- Para a entrada `M = 1` e `N = 5`, a saída deve ser: `15` (pois 1 + 2 + 3 + 4 + 5 = 15). + +- Para a entrada `M = 10` e `N = 15`, a saída deve ser: `75` (pois 10 + 11 + 12 + 13 + 14 + 15 = 75). + +- Para a entrada `M = 3` e `N = 6`, a saída deve ser: `18`(pois 3+4+5+6=18). + + +",Repetição (Typescript: Lógica de Programação),rw1751554459322694909 +Soma dobrada,Primeiro exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + +Implemente o método `somaDobrada`, que recebe como argumento dois números inteiros e retorna um valor inteiro. A implementação deve considerar as seguintes regras: + +- Caso os dois números recebidos sejam iguais, o método retorna o dobro da soma; + +- Caso um dos números seja menor do que 1, o método retorna -1; + +- Caso nenhuma das condições anteriores seja verdadeira, o método retorna a soma dos dois números. + +## Casos de teste: + +- Quando a entrada for ""1"" e ""2"", a saida deve ser ""3"" +- Quando a entrada for ""3"" e ""2"", a saida deve ser ""5"" +- Quando a entrada for ""2"" e ""2"", a saida deve ser ""8"" +- Quando a entrada for ""7"" e ""7"", a saida deve ser ""28"" +- Quando a entrada for ""3"" e ""-3"", a saida deve ser ""-1"" + +",Fundamentos(typescript Fundamentos),rw1751481256893111248 +Soma maior 50,Primeiro exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + +Crie uma função chamada somaMaiorQueCinquenta que receba dois números inteiros. A função deve somar os dois números e retornar o valor da soma somente se o resultado for maior que 50. Caso contrário, a função deve retornar null. + +## Exemplos: + +somaMaiorQueCinquenta(25,30); + +Entrada: 25 e 30 → Saída: 55 + +somaMaiorQueCinquenta(20,35); + +Entrada: 20 e 25 → Saída: null + + +",Condicionais (Typescript: Lógica de Programação),rw17515525189894c60af +Testando a Soma com Jest,Nesta atividade você vai escrever um teste unitário simples para uma função que soma dois números,"Nesta atividade, você vai escrever um teste unitário simples para uma função que soma dois números. + +O objetivo é entender como criar testes para funções que executam operações simples. + +--- + +**Objetivo** +- Criar uma função `sum(a, b)` que recebe dois números e retorna a soma. +- Escrever um teste unitário usando Jest para verificar se a função está funcionando corretamente. +- Garantir que o teste passe para valores positivos e negativos. + +--- + +**Exemplo de código**: + +```javascript +// sum.js +function sum(a, b) { + return a + b; +} + +module.exports = { sum }; + +// sum.test.js +const { sum } = require('./sum'); + +test('soma dois números positivos', () => { + expect(sum(1, 2)).toBe(3); +}); + +test('soma números negativos', () => { + expect(sum(-1, -2)).toBe(-3); +}); +``` + +--- + +**Critérios de Aceitação** + +A função sum deve retornar a soma de dois números corretamente. +Os testes devem cobrir tanto números positivos quanto negativos. + +--- + +**Recursos** + +Use Jest para rodar os testes. + +--- + +**Tecnologias Recomendadas** + +Jest para testes unitários.",Conceitos Básicos de Testes Unitários,rw1732800899865ca56dd +Testando Código com Banco de Dados Simulado,Nesta atividade você vai criar uma função que simula a inserção de dados em um banco de dados,"Nesta atividade, você vai criar uma função que simula a inserção de dados em um banco de dados. A interação com o banco será simulada utilizando mocks, o que permite que você teste a função sem depender de uma conexão real com o banco de dados. O uso de mocks é importante para isolar os testes e garantir que a lógica da função seja validada de maneira eficiente. + +**Objetivo** +- Criar uma função que insira dados em um banco de dados simulado. +- Simular a interação com o banco de dados utilizando mocks para garantir que o código funciona corretamente. + +**Exemplo de código**: + +```javascript +// database.js +function insertData(data) { + // Simula a inserção no banco de dados + return Promise.resolve({ id: 1, ...data }); +} + +module.exports = { insertData }; + +// database.test.js +const { insertData } = require('./database'); + +jest.mock('./database'); + +test('insere dados no banco', async () => { + insertData.mockResolvedValueOnce({ id: 1, name: 'John' }); + const result = await insertData({ name: 'John' }); + expect(result.id).toBe(1); + expect(result.name).toBe('John'); +}); +``` + +--- + +**Critérios de Aceitação** + +- O mock do banco de dados deve retornar dados simulados. +- A função de inserção deve ser testada sem uma conexão real com o banco. + +--- + +**Recursos** + +- Use Jest para mockar a interação com o banco de dados. + +--- + +**Tecnologias Recomendadas** + +- Jest para testes unitários. +",Testando Código com Dependências Externas,rw1732810429625e12b85 +Testando uma Função com Dependências Externas,Você irá criar e testar uma função que realiza uma requisição HTTP a uma API externa,"Nesta atividade, você vai testar uma função que depende de uma API externa. + +O objetivo é aprender a mockar a resposta da API para que o teste seja controlado e não dependa de uma chamada real. + +--- + +**Objetivo** + +- Escrever uma função fetchData(url) que faz uma requisição HTTP para uma URL e retorna os dados. +- Criar um mock da API para testar a função sem fazer uma requisição real.~ + +--- + +**Exemplo de código:** + +```javascript +// fetchData.js +const fetch = require('node-fetch'); + +async function fetchData(url) { + const response = await fetch(url); + return response.json(); +} + +module.exports = { fetchData }; +``` + + +```javascript +// fetchData.test.js +const { fetchData } = require('./fetchData'); +const fetch = require('node-fetch'); + +jest.mock('node-fetch'); + +test('mockando a API para retornar dados simulados', async () => { + fetch.mockResolvedValueOnce({ + json: jest.fn().mockResolvedValue({ data: 'test data' }), + }); + + const result = await fetchData('https://api.example.com/data'); + expect(result.data).toBe('test data'); +}); +``` + +--- + +**Critérios de Aceitação** + +- A função fetchData deve retornar a resposta mockada da API. +- O mock deve ser configurado corretamente para simular a resposta da API. + +--- + +**Recursos** + +- Use Jest para mockar a função da API. + +--- + +**Tecnologias Recomendadas** + +Jest para testes unitários. +",Testando Funções e Módulos com Jest,rw17328104408179a988d +Teste Componente de Contador,Nesta atividade você vai testar um componente contador utilizando Jest e React Testing Library,"Neste exercício, você irá criar um componente de contador que pode ser incrementado ao clicar em um botão. Em seguida, você escreverá testes para garantir que o botão está funcionando corretamente e que o valor do contador é exibido corretamente. + +--- + +**Objetivo** +- Criar um componente React simples de contador. +- Escrever testes para verificar se o contador é incrementado corretamente ao clicar no botão. + +--- + +**Exemplo de código**: + +```javascript +// Counter.js +import React, { useState } from 'react'; + +function Counter() { + const [count, setCount] = useState(0); + + const increment = () => setCount(count + 1); + + return ( + + Contagem: {count} + Incrementar + + ); +} + +export default Counter; + +// Counter.test.js +import { render, screen, fireEvent } from ' testing-library/react'; +import Counter from './Counter'; + +test('deve exibir o contador e incrementar ao clicar no botão', () => { + render(); + + const button = screen.getByText('Incrementar'); + const countText = screen.getByText('Contagem: 0'); + + expect(countText).toBeInTheDocument(); + + fireEvent.click(button); + const updatedCountText = screen.getByText('Contagem: 1'); + + expect(updatedCountText).toBeInTheDocument(); +}); +``` +--- + +**Critérios de Aceitação** + +- O componente deve exibir o valor inicial do contador como 0. +- O contador deve ser incrementado em 1 cada vez que o botão for clicado. +- O teste deve garantir que o valor exibido na tela seja atualizado corretamente. + +--- + +**Recursos** + +- Use  testing-library/react para testar o componente. +- Utilize fireEvent para simular o clique no botão e verificar a - atualização do contador. + +--- + +**Tecnologias Recomendadas** + +- Jest para testes unitários. + +- React Testing Library para renderização e interação com o componente."," Testando Componentes React ",rw1732812769706adad54 +Teste de Comparação de String,Nesta atividade você vai escrever um teste para comparar duas strings,"Nesta atividade, você vai escrever um teste para comparar duas strings. + +O objetivo é entender como o Jest realiza comparações e verificar se os valores estão sendo retornados corretamente. + +--- + +**Objetivo** + +- Escrever uma função `compareStrings(str1, str2)` que compara duas strings e retorna se são iguais ou não. +- Criar testes para verificar se a função está funcionando corretamente. + +--- + +**Exemplo de código**: + +```javascript +// compareStrings.js +function compareStrings(str1, str2) { + return str1 === str2; +} + +module.exports = { compareStrings }; +``` + +--- + +```javascript +// compareStrings.test.js +const { compareStrings } = require('./compareStrings'); + +test('compara duas strings iguais', () => { + expect(compareStrings('teste', 'teste')).toBe(true); +}); + +test('compara duas strings diferentes', () => { + expect(compareStrings('teste', 'outro')).toBe(false); +}); +```",Escrevendo Testes Simples com Jest,rw1732803088332a5dd34 +Uniformizando Estilos em Navegadores com Reset.css,Entenda o Reset.css e como ele mantém a consistência visual em diferentes navegadores,"**Objetivo** + +Entender como aplicar o Reset.css no seu projeto, linkando-o ao HTML para uniformizar a aparência dos elementos. Esse exercício reforça a importância de uma configuração inicial para evitar variações indesejadas entre navegadores. + +**Instruções** + +1. **Revisão do Reset.css** + + Certifique-se de que o arquivo `reset.css` foi criado e está salvo na mesma pasta que o seu HTML ou em uma pasta específica de estilos, conforme sua organização preferida. + +2. **Preparando o HTML para usar o Reset.css** + + No seu arquivo HTML, localize a seção responsável por importar arquivos de estilo. Pense em qual seção do HTML faz essa função e onde deve ser posicionado o link para o `reset.css` dentro dessa estrutura. + +3. **Ligação dos Arquivos** + + Refletindo sobre o nome e o caminho do arquivo `reset.css`, insira-o adequadamente dentro da seção do HTML que importa estilos. O objetivo é que o navegador carregue o reset antes de aplicar seus próprios estilos personalizados. + +4. **Teste** + + Abra sua página em um navegador e verifique se os estilos padrão foram removidos. Esse é o indicativo de que o `reset.css` está funcionando corretamente. + +",Reset.css,rw17309876100642d9bba +Vetor invertido,Segundo exercício da lista com o objetivo de aprofundar o aprendizado,"**O problema:** + + + +Desenvolva um método que leia um vetor de 30 números inteiros e gere um segundo vetor com os mesmos dados, mas na ordem invertida. + + + +- O método deve ler os 30 números e reverter a ordem deles no novo vetor. + + + +### Exemplo: + + + +- Quando a entrada for `[1, 2, 3, 4, 5]`, a saída deve ser `[5, 4, 3, 2, 1]`. + + + +"," Array simples (Typescript: Lógica de Programação)",rw1751553389129395eda \ No newline at end of file diff --git a/prisma/data/themes.csv b/prisma/data/themes.csv new file mode 100644 index 0000000..237deb0 --- /dev/null +++ b/prisma/data/themes.csv @@ -0,0 +1,49 @@ +title,cardDescription,description,image,topics,category,topicsInfo1,alt,sequence,topicsInfo,topicsDescription_old,topicsDescription,idThemes +Exercícios Adicionais,Exercícios complementares a tópicos existentes no nivelamento,"Cada tópico listado aqui corresponde a um conteúdo que já aparece na aba de Nivelamento. A ideia é oferecer, de forma complementar, uma série de exercícios que ajudam a reforçar e aprofundar o que foi visto anteriormente. Esses exercícios variam em nível de dificuldade alguns são mais tranquilos e fáceis de entender, enquanto outros propõem um desafio maior, ideal pra quem quer testar seus conhecimentos ou praticar um pouco mais. O objetivo principal é ajudar no desenvolvimento contínuo, oferecendo mais uma oportunidade de fixar os conceitos e avançar no aprendizado.",Imagens no Stackby.png (https://cdn.filestackcontent.com/dZsxEUsMQ2SYZjF0MfEH),"Fundamentos(typescript Fundamentos),Condicionais (Typescript: Lógica de Programação), Array simples (Typescript: Lógica de Programação),Repetição (Typescript: Lógica de Programação)",Autoestudo,"rw175147221097169153e,2025-10-17T19:19:46+00:00,rw17514730654126505cd,2025-10-17T19:19:46+00:00","Ícone de uma folha com uma lista de afazeres e uma lupa ao lado, com o nome ""Exercícios Adicionais"" a direita, tudo em fonte branca com um fundo em tons rosa e laranja",,"rw175147221097169153e,rw1751472269115737a43,rw17514730654126505cd,rw175154749268307462c","Exercícios complementares referentes ao tópico de fundamentos, Exercícios adicionais referente ao tópico de Condicionais, Exercícios adicionais referente ao tópico de Array simples, Exercícios adicionais referente ao tópico de Repetição","Exercícios complementares referentes ao tópico de fundamentos,Exercícios adicionais referente ao tópico de Condicionais,Exercícios adicionais referente ao tópico de Array simples,Exercícios adicionais referente ao tópico de Repetição",rw1747321293489e7c851 +Preparando a Máquina,Passo a passo de instalação das ferramentas básicas para iniciar o ambiente de desenvolvimento.,"Para começar sua jornada no desenvolvimento de software, é fundamental preparar corretamente o ambiente de trabalho. + +Isso inclui a instalação de ferramentas e softwares essenciais que possibilitarão a criação, teste e implementação dos seus projetos de forma eficiente. Vamos explorar juntos os componentes básicos que precisam ser configurados em seu computador, garantindo que você possa iniciar suas atividades de desenvolvimento de maneira produtiva e organizada. A configuração adequada do ambiente de desenvolvimento é um passo crucial para qualquer pessoa desenvolvedora, pois evita problemas futuros relacionados a ajustes técnicos malfeitos. Nas próximas sessões, veremos essas ferramentas e técnicas em detalhes, assegurando que tudo esteja devidamente configurado para que você possa dar início aos seus projetos com confiança e fluidez.",Preparando A Máquina - NIVELAMENTO.png (https://cdn.filestackcontent.com/QBA1FzpTmGwWY9IvSUW4),"Instalar Visual Studio Code,Instalar Node.js,Extensões no Visual Studio Code,Git bash",Nivelamento,"rw171923779887648423e,2025-10-17T19:19:46+00:00,rw17201095165728b5a2f,2025-10-17T19:19:46+00:00",Ícone de monitor com engrenagens ao lado do titulo do card (preparando máquina) com fundo em tons azuis.,1,"rw171923779887648423e,rw1727186657231c1af77,rw17201095165728b5a2f,rw1727186962924b98d86","Aprenda como realizar a instalação desta ferramenta., Como instalar o Node.js no Windows Linux ou macOS., Adicione extensões que facilitam na manipulação do código., Entenda o que é e como usar git bash na sua maquina.","Aprenda como realizar a instalação desta ferramenta.,Como instalar o Node.js no Windows Linux ou macOS.,Adicione extensões que facilitam na manipulação do código.,Entenda o que é e como usar git bash na sua maquina.",rw17169041087123b2d76 +Iniciando a Jornada,Acesse conteúdos para aprimorar seus métodos de estudo e dar seus primeiros passos na programação.,"Aqui você encontra conteúdos de vídeos como uma maneira eficaz de melhorar e construir uma jornada de aprendizado em programação ágil. +Para maximizar seu aprendizado, combine vídeos com a prática constante e participação em comunidades de desenvolvimento. Essa combinação de recursos ajudará a consolidar seu conhecimento e aplicá-lo de maneira eficaz em projetos reais. + +",Iniciando Jornada - AUTOESTUDO.png (https://cdn.filestackcontent.com/y0VC4C9URt2HNTu9PMLe),"Aprenda a aprender,Como posso estudar melhor,Como estudo programação,Como posso aprender a programar?,Técnicas para aprender a programar",Autoestudo,"2025-10-17T19:19:45+00:00,rw1719583500014767687,rw171958350792237d5b0,rw17192374230680ab385,2025-10-17T19:19:45+00:00",Ícone de uma pessoa seguindo em uma longa estrada ao lado do titulo do card (Iniciando a Jornada) com fundo em tons de rosa e laranja.,1,"rw17195834951124516c5,rw1719583500014767687,rw171958350792237d5b0,rw17192374230680ab385,rw1719237431883f5c222","Importância do aprendizado autônomo e habilidades essenciais para desafios do mercado., Organize seus estudos com disciplina e com dicas de planejamento., Aprenda fundamentos e conceitos básicos da linguagem de programação., Aqui você encontrará dicas para te ajudar a dar os primeiros passos na programação., Essas técnicas ajudam a aprender programação e se aplicam a outras áreas.","Importância do aprendizado autônomo e habilidades essenciais para desafios do mercado.,Organize seus estudos com disciplina e com dicas de planejamento.,Aprenda fundamentos e conceitos básicos da linguagem de programação.,Aqui você encontrará dicas para te ajudar a dar os primeiros passos na programação.,Essas técnicas ajudam a aprender programação e se aplicam a outras áreas.",rw1716904108694cc944a +Configurando Banco de Dados,Passo a passo para configuração e instalação do banco de dados em diferentes sistemas operacionais.,"Nesta introdução, vamos explorar como configurar e utilizar bancos de dados com PostgreSQL, um sistema de gerenciamento robusto e confiável amplamente utilizado em aplicações modernas. + +O PostgreSQL oferece segurança avançada, escalabilidade e uma ampla gama de recursos para armazenamento e recuperação eficientes de dados relacionais. + +Ao longo deste aprendizado, exploraremos passos essenciais para configurar ambientes de banco de dados. Vamos aprender a instalar o PostgreSQL, configurar usuários e permissões, criar e gerenciar bancos de dados, e utilizar ferramentas de administração. + +Também abordaremos como otimizar o desempenho, implementar backups e recuperação de dados, e garantir a segurança do seu banco de dados. O objetivo é fornecer uma base sólida para que você possa utilizar o PostgreSQL de forma eficiente e eficaz em seus projetos. + +Vamos começar nossa jornada para dominar o PostgreSQL e suas potencialidades!",Preparando A Máquina - NIVELAMENTO.png (https://cdn.filestackcontent.com/0yNsUZkYTmKZWQrkUCu1),"Instalação para Windows,Instalação para macOS,Instalação para Linux",Nivelamento,"2025-10-17T19:19:46+00:00,rw172019665783251efa3,2025-10-17T19:19:46+00:00",Ícone de um banco de dados ao lado do titulo do card (Configurando Banco de Dados) com fundo em tons azuis.,2,"rw1720109585838a51c06,rw172019665783251efa3,rw1720196673427294957","Instruções para instalar o PostgreSQL no Windows baixando o instalador adequado do site oficial do PostgreSQL., Instruções para instalar o PostgreSQL e o no macOS baixando o instalador adequado do site oficial do PostgreSQL, Instruções para instalar o PostgreSQL no Linux baixando o instalador adequado do site oficial do PostgreSQL.","Instruções para instalar o PostgreSQL no Windows baixando o instalador adequado do site oficial do PostgreSQL.,Instruções para instalar o PostgreSQL e o no macOS baixando o instalador adequado do site oficial do PostgreSQL,Instruções para instalar o PostgreSQL no Linux baixando o instalador adequado do site oficial do PostgreSQL.",rw1720196065111461967 +Introdução ao HTML e CSS,HTML5 e CSS3 são as tecnologias fundamentais para construção de páginas web modernas e interativas.,"O **HTML5** é uma linguagem de marcação que estrutura o conteúdo e define a semântica das páginas, facilitando o desenvolvimento de paginas web e aplicações com recursos como elementos de vídeo, áudio e gráficos. Já o **CSS3** é a linguagem de estilos que dá forma e visual às páginas. Ele oferece animações, transições, gradientes e flexibilidade para criar layouts que se adaptam a diferentes tamanhos de tela. + +Juntos, **HTML5** e **CSS3** permitem criar interfaces intuitivas, leves e adaptáveis, proporcionando uma experiência de usuário otimizada em qualquer plataforma. Eles facilitam a construção de aplicações web mais complexas e envolventes, favorecendo a performance, usabilidade e compatibilidade entre navegadores e dispositivos móveis, sendo assim uma base sólida para a criação de experiências web modernas e atraentes.",Introdução a HTML e a CSS - AUTOESTUDO.png (https://cdn.filestackcontent.com/ucqHw2sQt6tJrX15zl3u),"Estrutura Básica,Estrutura de Páginas Web e Links,Elementos Multimídia,Formulários - Tabelas - Listas,Estilos.css,Reset.css,Posicionamento,Hierarquia no CSS,Fontes,Seletores CSS,Design responsivo,Box model e Box sizing,Flexbox e Grid",Autoestudo,"rw17301368164191bfc4c,rw17303925853926d59c2,rw17303926086341dc649,rw1730392611795685162,rw17301368262879f399f,rw1730136932113000d16,rw1730136949117191333,rw1730137012921a48842,rw17301370383075596dd,rw1730137044079bf6288,rw173013705844645778d,rw17301371000848a4ab0,2025-10-17T19:19:46+00:00","Ícones do 5 e do 3 em um brasão ( representando ""html5"" e ""css3"") ao lado do titulo do card (introdução ao HTML e CSS) com fundo em tons de rosa e laranja.",2,"rw17301368164191bfc4c,rw17303925853926d59c2,rw17303926086341dc649,rw1730392611795685162,rw17301368262879f399f,rw1730136932113000d16,rw1730136949117191333,rw1730137012921a48842,rw17301370383075596dd,rw1730137044079bf6288,rw173013705844645778d,rw17301371000848a4ab0,rw1730137140936bdf782","Informações que formam uma base sólida para entender o uso de HTML5 na criação de sites e aplicações web., Descubra como organizar e estruturar uma página web de forma intuitiva e eficiente. , Incorporar elementos multimídia torna a página mais interativa e acessível para melhorar a experiência do usuário., Desvende os formulários com validação tabelas e listas no contexto de desenvolvimento web., Aprenda sobre os diferentes estilos do CSS e aprenda a aplicá-los de forma estratégica para criar designs versáteis e eficientes., Mude o estilo dos elementos HTML em todos os navegadores com o Reset.css uma técnica que elimina conflitos visuais e melhora a consistência do layout., Entenda mais sobre os diferentes tipos de posicionamento no CSS e como aplicá-los para construir layouts dinâmicos e precisos., Descubra como funciona a hierarquia e especificidade do CSS e aprenda a aplicar estilos de forma eficiente., Explore como estilizar fontes no CSS com propriedades básicas e avançadas para melhorar a legibilidade e o design., Transforme suas páginas com seletores CSS estilizando elementos HTML com precisão e eficiência para um design único., Descubra como o design responsivo transforma layouts para qualquer dispositivo e como unidades viewport ajustam elementos perfeitamente à tela., Entenda como o Box Model organiza o espaço dos elementos e como o Box Sizing facilita o controle de larguras e alturas no layout., Descubra como Flexbox e Grid revolucionam layouts CSS com estruturas modernas responsivas e perfeitamente organizadas.","Informações que formam uma base sólida para entender o uso de HTML5 na criação de sites e aplicações web.,Descubra como organizar e estruturar uma página web de forma intuitiva e eficiente. ,Incorporar elementos multimídia torna a página mais interativa e acessível para melhorar a experiência do usuário.,Desvende os formulários com validação tabelas e listas no contexto de desenvolvimento web.,Aprenda sobre os diferentes estilos do CSS e aprenda a aplicá-los de forma estratégica para criar designs versáteis e eficientes.,Mude o estilo dos elementos HTML em todos os navegadores com o Reset.css uma técnica que elimina conflitos visuais e melhora a consistência do layout.,Entenda mais sobre os diferentes tipos de posicionamento no CSS e como aplicá-los para construir layouts dinâmicos e precisos., Descubra como funciona a hierarquia e especificidade do CSS e aprenda a aplicar estilos de forma eficiente.,Explore como estilizar fontes no CSS com propriedades básicas e avançadas para melhorar a legibilidade e o design.,Transforme suas páginas com seletores CSS estilizando elementos HTML com precisão e eficiência para um design único.,Descubra como o design responsivo transforma layouts para qualquer dispositivo e como unidades viewport ajustam elementos perfeitamente à tela.,Entenda como o Box Model organiza o espaço dos elementos e como o Box Sizing facilita o controle de larguras e alturas no layout.,Descubra como Flexbox e Grid revolucionam layouts CSS com estruturas modernas responsivas e perfeitamente organizadas.",rw17308119603145f559b +Deploy,Deploy é o processo de disponibilizar uma aplicação em um ambiente de produção permitindo o acesso e uso por pessoas usuárias.,"**Deploy** é o processo de disponibilizar uma aplicação ou sistema para ser acessado e utilizado por usuários. Em termos simples, é quando você pega o código que foi desenvolvido e testado e o coloca em um servidor ou plataforma para que ele funcione na prática. + +O deploy pode incluir etapas como copiar os arquivos para o servidor, configurar o ambiente (por exemplo, banco de dados, variáveis de ambiente), e ativar a aplicação para que esteja pronta para uso. Hoje, ferramentas como **Netlify**, **Vercel**, **Heroku** e **AWS** tornam o processo mais rápido e automatizado, permitindo que desenvolvedores façam atualizações frequentes e seguras.",deploy.png (https://cdn.filestackcontent.com/oItDfBrrQYSZQZ4ose0l),"O que é Deploy?, Deploy com o Netlify",Autoestudo,"rw17327343320856e374b,2025-10-17T19:19:46+00:00",Ícone de um foguete ao lado do titulo do card (Deploy) com fundo em tons de rosa e laranja.,3,"rw17327343320856e374b,rw17319342118235d2670","Descubra como as aplicações ganham vida e chegam até você! Entenda o que é deploy e como ele funciona., O Netlify é uma ferramenta robusta para automação de deploy e hospedagem de sites modernos com facilidade.","Descubra como as aplicações ganham vida e chegam até você! Entenda o que é deploy e como ele funciona., O Netlify é uma ferramenta robusta para automação de deploy e hospedagem de sites modernos com facilidade.",rw173193361204827d788 +Descubra o Git e GitHub,Descubra como o Git permite gerenciar versões de código e como o GitHub facilita a colaboração em projeto.,"O **Git**, criado por Linus Torvalds em 2005, é uma ferramenta poderosa para controlar as versões do seu código, garantindo que você possa acompanhar as mudanças de forma segura. O **GitHub**, lançado em 2008, é uma plataforma que usa o Git para hospedar seus projetos online, permitindo que você compartilhe seu código, desenvolva novas funcionalidades e colabore em projetos com outras pessoas. Juntas, essas ferramentas tornam o desenvolvimento em equipe mais fácil e organizado, além de promover a contribuição em projetos de código aberto.",Git e Github - NIVELAMENTO.png (https://cdn.filestackcontent.com/XWRiZzxWSDqsTEomalGC),"Git ,GitHub,Como utilizar o GitHub e Git,Como personalizar o GitHub",Nivelamento,"2025-10-17T19:19:46+00:00,rw1727184465499e3f709,2025-10-17T19:19:46+00:00,rw17271835297323eec3b",Ícone da logo do git hub ao lado do titulo do card (Git e Github) com fundo em tons azuis.,3,"rw1727183980819e0ac72,rw1727184465499e3f709,rw172718446645846e05e,rw17271835297323eec3b","Entenda como funciona o controle de versionamento com Git., GitHub é uma ferramenta para armazenar e gerenciar projetos na nuvem a qual facilita a colaboração em código aberto e funcionando como portfólio digital essencial para desenvolvedores., As principais funcionalidades do GitHub e Git permitem colaborar e gerenciar projetos de desenvolvimento de software., Criando um portfólio com o GitHub.","Entenda como funciona o controle de versionamento com Git.,GitHub é uma ferramenta para armazenar e gerenciar projetos na nuvem a qual facilita a colaboração em código aberto e funcionando como portfólio digital essencial para desenvolvedores.,As principais funcionalidades do GitHub e Git permitem colaborar e gerenciar projetos de desenvolvimento de software.,Criando um portfólio com o GitHub.",rw1716904108731aca962 +TypeScript: Fundamentos,TypeScript é uma linguagem de programação fortemente tipada que se baseia em JavaScript adicionando tipos estáticos opcionais.,"**TypeScript** é uma linguagem de programação de código aberto desenvolvida pela Microsoft, que se baseia em JavaScript e adiciona tipagem estática opcional. Ao contrário de JavaScript, que é fracamente tipado, TypeScript permite as pessoas desenvolvedoras definir tipos para variáveis, parâmetros de função e retornos de função, o que ajuda a detectar erros em tempo de compilação, em vez de tempo de execução. Isso proporciona um desenvolvimento mais seguro e confiável. Uma das grandes vantagens do TypeScript é a compatibilidade com JavaScript existente, permitindo que os desenvolvedores gradualmente migrem seus projetos sem reescrever tudo do zero. Além disso, TypeScript suporta recursos modernos de JavaScript, como classes, módulos e funções assíncronas, e adiciona funcionalidades adicionais, como interfaces e enums. O sistema de tipos avançado de TypeScript facilita a autocompletar de código e fornece melhor documentação durante o desenvolvimento, aumentando a produtividade das desenvolvedoras. Ferramentas como o Visual Studio Code têm suporte robusto para TypeScript, tornando a experiência de desenvolvimento ainda mais eficiente. TypeScript é especialmente útil para grandes projetos de código base, onde a manutenção e escalabilidade são cruciais. Ele ajuda a evitar bugs sutis que podem surgir de tipagem dinâmica e torna o código mais fácil de entender e refatorar. Adotar TypeScript em projetos novos ou existentes pode levar a um ciclo de desenvolvimento mais ágil e menos propenso a erros, tornando-se uma escolha popular entre desenvolvedoras e empresas ao redor do mundo.",TyperScript Fundamentos - NIVELAMENTO.png (https://cdn.filestackcontent.com/f9B9PSW1RN6lLIWRiaSE),"Fundamentos,Operadores,Tipos de variáveis",Nivelamento,"2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00","Ícone da logo do TypeScript(as letras ""TS"") ao lado do titulo do card (Typescript: Fundamentos) com fundo em tons azuis.",4,"rw1721236357157ccf465,rw1721236361209aa4ab7,rw17212367412369c1494","Seus principais benefícios incluem detecção de erros em tempo de desenvolvimento e autocompletar de código mais inteligente melhorando a produtividade das pessoas desenvolvedoras., Os operadores em TypeScript permitem manipular valores em expressões aritméticas lógicas e de comparação., A tipagem estática ajuda a capturar erros de tipo durante a compilação promovendo um código mais robusto e legível além de facilitar a manutenção.","Seus principais benefícios incluem detecção de erros em tempo de desenvolvimento e autocompletar de código mais inteligente melhorando a produtividade das pessoas desenvolvedoras.,Os operadores em TypeScript permitem manipular valores em expressões aritméticas lógicas e de comparação.,A tipagem estática ajuda a capturar erros de tipo durante a compilação promovendo um código mais robusto e legível além de facilitar a manutenção.",rw17169041087560470c1 +TypeScript: Lógica de Programação,"Lógica de Programação com TypeScript é o fundamento para resolver problemas de forma eficiente, utilizando estruturas como loops e condicionais, com o suporte de tipos estáticos da linguagem.","**Lógica de programação em TypeScript** permite que as pessoas desenvolvedoras implementem soluções eficientes e organizadas por meio da definição clara de tipos e estruturas de controle. Utilizando condicionais como `if` e `switch`, é possível criar ramificações lógicas que orientam o fluxo do programa. Os loops, como `for` e `while`, ajudam a executar repetidamente blocos de código, facilitando a iteração sobre conjuntos de dados. + +Além disso, TypeScript suporta a criação de funções que podem ser **tipadas**, promovendo a reutilização de código e a clareza na intenção. O uso de **classes** e **interfaces** permite a modelagem de entidades do mundo real, simplificando a lógica de negócios em aplicações complexas. + +Com essas características, TypeScript se destaca como uma poderosa ferramenta para a aplicação de lógica de programação, melhorando a legibilidade e a segurança do código.",TyperScript - Lógica de Programação - NIVELAMENTO.png (https://cdn.filestackcontent.com/QEEC1l1hTZyRiDe08xpr),"Condicionais,Repetição,Funções ,Algoritmos,Operador Ternário,Array Simples,Métodos map filter e sort",Nivelamento,"2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00",Ícone de do contorno de uma cabeça humana com engrenagens no cérebro ao lado do titulo do card (Typescript: Lógica de Programação) com fundo em tons azuis.,5,"rw17212367802520ba251,rw1726765151047cfa7ec,rw1726770563183563cea,rw17267745321437cbec1,rw17267746000309152e6,rw1727203515904ad3fa2,rw17515517780331570b6","São fundamentais para implementar lógica de decisão no código adaptando o comportamento do programa conforme diferentes cenários e entradas., Estruturas de Repetição em TypeScript permitem executar blocos de código várias vezes de forma eficiente utilizando laços como `for` `while` e `do while` com o suporte de tipos estáticos para garantir segurança e consistência no código., Funções em TypeScript permitem definir comportamentos reutilizáveis com tipagem estática garantindo código mais seguro e organizado., Algoritmos são sequências de instruções lógicas e finitas para resolver problemas ou realizar tarefas de forma eficiente e estruturada., Operadores Ternários em TypeScript exploraremos a sintaxe e os benefícios desse operador que simplifica decisões condicionais em uma única linha de código., Arrays em TypeScript permitem armazenar e manipular dados de forma organizada com suporte para tipos estáticos propriedades anuláveis e métodos como propriedades de objetos., Uso de map filter sort e reduce para manipular listas","São fundamentais para implementar lógica de decisão no código adaptando o comportamento do programa conforme diferentes cenários e entradas.,Estruturas de Repetição em TypeScript permitem executar blocos de código várias vezes de forma eficiente utilizando laços como `for` `while` e `do while` com o suporte de tipos estáticos para garantir segurança e consistência no código.,Funções em TypeScript permitem definir comportamentos reutilizáveis com tipagem estática garantindo código mais seguro e organizado.,Algoritmos são sequências de instruções lógicas e finitas para resolver problemas ou realizar tarefas de forma eficiente e estruturada.,Operadores Ternários em TypeScript exploraremos a sintaxe e os benefícios desse operador que simplifica decisões condicionais em uma única linha de código.,Arrays em TypeScript permitem armazenar e manipular dados de forma organizada com suporte para tipos estáticos propriedades anuláveis e métodos como propriedades de objetos.,Uso de map filter sort e reduce para manipular listas",rw1720014886324a56ac2 +TypeScript: Refatoração,A refatoração visa melhorar a legibilidade e eficiência do código eliminando duplicações e implementando boas práticas de desenvolvimento.,"O processo de refatoração tem como principal objetivo melhorar a estrutura interna do código sem alterar seu comportamento externo. Essa tarefa envolve reescrever trechos de código, otimizando a organização e tornando o código mais coeso, modular e de fácil manutenção. A refatoração facilita a compreensão do sistema por toda a equipe, melhora a navegabilidade e torna futuras implementações mais simples e seguras. Além disso, ela ajuda a reduzir a complexidade, melhora a performance em alguns casos, e prepara a base de código para escalar de maneira mais eficiente, eliminando potenciais gargalos e problemas de longo prazo.",TyperScript - Refatoração - NIVELAMENTO.png (https://cdn.filestackcontent.com/2fnamP0WSOS0TBScEQyH),"Principais Técnicas de Refatoração em TypeScript,Benefícios da Refatoração",Nivelamento,"2025-10-17T19:19:46+00:00,rw17267632624582fe2e7",Ícone de 2 paginas indicando mudança de uma para a outra ao lado do titulo do card (Tipescript:Refatoração) com fundo em tons azuis.,6,"rw17267635193113866b5,rw17267632624582fe2e7","Técnicas de refatoração em TypeScript melhoram a clareza do código e tornam a manutenção mais fácil., Refatoração melhora legibilidade reutilização reduz erros e facilita a manutenção do código.","Técnicas de refatoração em TypeScript melhoram a clareza do código e tornam a manutenção mais fácil.,Refatoração melhora legibilidade reutilização reduz erros e facilita a manutenção do código.",rw17200146726922cce88 +Node.js,"Node.js é um ambiente de execução que permite rodar JavaScript no servidor. Possui uma arquitetura assíncrona e orientada a eventos, oferecendo eficiência para lidar com múltiplas requisições simultâneas.","O **Node.js** foi criado para executar o JavaScript **fora** de um navegador web, ampliando o potencial dessa linguagem para o desenvolvimento de aplicações back-end, APIs e bibliotecas. Ele nos permite criar soluções diversas e completas, funcionando de maneira eficiente e leve em diferentes contextos e dispositivos. + +O Node.js **interpreta código JavaScript**, assim como faria um navegador, mas fora do ambiente do browser. Quando executamos um comando em JavaScript, o Node.js faz a conversão do código para **linguagem de máquina**, pronta para ser executada pelo computador. Por isso, ele é conhecido como um JavaScript Runtime, uma plataforma que executa JavaScript diretamente no sistema. + +Node.js possibilita a criação de **aplicações web** e **desktop**, interfaces de linha de comando (CLI), chatbots, e é amplamente utilizado em projetos de Internet das Coisas (IoT), além de outras possibilidades que você pode explorar com essa ferramenta. Essa tecnologia é adotada por grandes empresas, como LinkedIn, IBM, Uber, e Netflix, devido à sua leveza, eficiência e multifuncionalidade. +",Node JS - NIVELAMENTO.png (https://cdn.filestackcontent.com/Omen4D1QRJSkjRT1W6Qp)," Internet: Conceitos e fundamentos,Protocolo HTTP,REST API,TypeORM,Migrations,PrismaORM",Nivelamento,"rw1730305190028e89fd1,2025-10-17T19:19:46+00:00,rw17303052691599a76af,rw1730305270222b120a7,rw1730305280757a1a95b,2025-10-17T19:19:46+00:00","Ícone do Node.js(as letras ""JS"" cercadas por um hexágono ao lado do titulo do card (Node.js) com fundo em tons azuis.",8,"rw1730305190028e89fd1,rw1730305252555aab804,rw17303052691599a76af,rw1730305270222b120a7,rw1730305280757a1a95b,rw175068136549736a7ee","Entenda o que é Node.js como ele revolucionou o desenvolvimento web ao permitir a execução de JavaScript no lado do servidor., No Node.js o módulo HTTP facilita a criação de servidores que manipulam requisições e respostas tornando possível desenvolver aplicações web dinâmicas e escaláveis., REST API é uma interface que permite interações entre sistemas usando HTTP., Este guia rápido mostra como instalar o TypeORM e configurá-lo com um banco de dados PostgreSQL em um projeto Node.js., As migrations facilitam a criação e manutenção da estrutura do banco de dados ao longo do desenvolvimento., Prisma é um ORM (Object-Relational Mapper) de nova geração que visa simplificar e proteger a interação com bancos de dados.","Entenda o que é Node.js como ele revolucionou o desenvolvimento web ao permitir a execução de JavaScript no lado do servidor., No Node.js o módulo HTTP facilita a criação de servidores que manipulam requisições e respostas tornando possível desenvolver aplicações web dinâmicas e escaláveis.,REST API é uma interface que permite interações entre sistemas usando HTTP., Este guia rápido mostra como instalar o TypeORM e configurá-lo com um banco de dados PostgreSQL em um projeto Node.js.,As migrations facilitam a criação e manutenção da estrutura do banco de dados ao longo do desenvolvimento.,Prisma é um ORM (Object-Relational Mapper) de nova geração que visa simplificar e proteger a interação com bancos de dados.",rw17302281624589bf88f +React.js,"React é uma biblioteca JavaScript para criar interfaces de usuário de forma eficiente, permitindo a construção de Componentes reutilizáveis e atualizações rápidas na tela com o Virtual DOM.","React é uma biblioteca JavaScript desenvolvida pelo Facebook para criar interfaces de usuário eficientes e interativas. Sua abordagem declarativa e baseada em Componentes permite construir interfaces de forma modular, onde cada parte da interface é dividida em pequenos ""Componentes"" reutilizáveis. Um dos diferenciais do React é o uso do Virtual DOM, uma representação leve da interface que otimiza o desempenho ao atualizar apenas os elementos necessários, sem recarregar toda a página. +Além disso, React permite combinar lógica de JavaScript com o layout visual por meio do JSX, uma sintaxe que torna o desenvolvimento mais intuitivo. Com a introdução dos ""Hooks"", React simplificou o gerenciamento de estado e efeitos colaterais em Componentes funcionais, tornando-se uma das bibliotecas mais populares para construir aplicações web e móveis escaláveis.",React JS - NIVELAMENTO.png (https://cdn.filestackcontent.com/jVu9VwOpQaeYz3XOalq9),"Componentes,Props,State,Rendering ,One-way Data Flow,Hooks,Refs,React DOM,Router,Axios",Nivelamento,"2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-11-06T18:48:27+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00,2025-10-17T19:19:46+00:00",Ícone do React (similar ao desenho de um átomo) ao lado do titulo do card (React.js) com fundo em tons azuis.,9,"rw17303805251492d2538,rw1730380625688dfb8ce,rw1730380736895949100,rw17303807028326d25e2,rw17303806036144fb980,rw173038056720390e1fe,rw173038068290709a104,rw17303806518422c6086,rw1730380721158da9173,rw173038051978684a925","Axios é uma biblioteca JavaScript para fazer requisições HTTP com suporte a Promises permite comunicação entre cliente e servidor simplificando operações com APIs., Um Component em React é como uma função JavaScript que retorna elementos de interface., Aprenda a usar Hooks em React como useState useEffect useParams e useNavigate para tornar seus componentes mais dinâmicos e interativos., O One-way Data Flow em React garante que os dados fluam do componente pai para os filhos tornando o estado mais previsível e o código mais fácil de manter., Props em React.js são fundamentais para criar componentes reutilizáveis e dinâmicos., Explore como o ReactDOM permite a interação eficiente com o DOM em aplicações React Aprenda sobre seus métodos principais e casos de uso para otimizar seu desenvolvimento., Refs no React permitem acessar diretamente elementos do DOM para manipulações fora do ciclo de renderização., Render é o processo em que o React atualiza a interface com base no estado e nas props. Ele acontece inicialmente e sempre que o estado muda., Domine conceitos essenciais como rotas componentes de navegação e rotas aninhadas para criar experiências interativas e fluídas., Entenda o State em React e como ele permite gerenciar dados dinâmicos em suas aplicações.","Um Component em React é como uma função JavaScript que retorna elementos de interface.,Props em React.js são fundamentais para criar componentes reutilizáveis e dinâmicos.,Entenda o State em React e como ele permite gerenciar dados dinâmicos em suas aplicações.,Render é o processo em que o React atualiza a interface com base no estado e nas props. Ele acontece inicialmente e sempre que o estado muda.,O One-way Data Flow em React garante que os dados fluam do componente pai para os filhos tornando o estado mais previsível e o código mais fácil de manter.,Aprenda a usar Hooks em React como useState useEffect useParams e useNavigate para tornar seus componentes mais dinâmicos e interativos.,Refs no React permitem acessar diretamente elementos do DOM para manipulações fora do ciclo de renderização.,Explore como o ReactDOM permite a interação eficiente com o DOM em aplicações React Aprenda sobre seus métodos principais e casos de uso para otimizar seu desenvolvimento.,Domine conceitos essenciais como rotas componentes de navegação e rotas aninhadas para criar experiências interativas e fluídas.,Axios é uma biblioteca JavaScript para fazer requisições HTTP com suporte a Promises permite comunicação entre cliente e servidor simplificando operações com APIs.",rw1730218811141b9a688 +Next.js,O Next.js é um framework de desenvolvimento em React que facilita a criação de aplicações web modernas e escaláveis.,"O Next.js é um framework de desenvolvimento para React criado em 2016 pela Vercel, com o objetivo de simplificar a construção de aplicações web modernas e escaláveis. Lançado sob a licença MIT, ele é de código aberto e tem uma comunidade ativa que contribui com melhorias e novas funcionalidades. Esse framework combina flexibilidade e desempenho, permitindo que desenvolvedores criem interfaces otimizadas e com excelente experiência de usuário, aproveitando as capacidades do React com recursos adicionais. + +Um dos aspectos mais atraentes do Next.js é seu suporte para renderização híbrida, permitindo tanto renderização no lado do cliente quanto renderização no lado do servidor. Além disso, ele possibilita a Geração de Páginas Estáticas (SSG) e Incremental Static Regeneration (ISR), onde páginas estáticas podem ser atualizadas após a build inicial. Isso é especialmente útil para SEO e desempenho, já que combina a rapidez de sites estáticos com a flexibilidade de conteúdo dinâmico.",Next.js - NIVELAMENTO.png (https://cdn.filestackcontent.com/KIpcZTlFRs6LLKeXcuwZ),"Fundamentos Next.js,Variáveis e Constantes,Funções + Next.js,CSS + Next.js,Componentes + Next.js,Componentes + props,Renderização,Direcionamento de Páginas,Listas",Nivelamento,"rw173022821547674e4af,rw1730305470024733aba,rw173030547906927cbfb,rw1730305490354a90f72,rw17303055001178b3f26,2025-10-17T19:19:46+00:00,rw1730305525617ed167f,rw173030553294685cacb,2025-10-17T19:19:46+00:00","Ícone do next.js (a letra ""N"" envolta por um circulo branco) ao lado do titulo do card (Next.js) com fundo em tons azuis.",10,"rw173022821547674e4af,rw1730305470024733aba,rw173030547906927cbfb,rw1730305490354a90f72,rw17303055001178b3f26,rw17303055178849abcf2,rw1730305525617ed167f,rw173030553294685cacb,rw1730305540107e95fd7","O Next.js é um framework para criar aplicações web rápidas e escaláveis com React oferecendo renderização server-side e páginas estáticas que melhoram desempenho e SEO., Aprenda a usar variáveis e constantes para armazenar valores e entender seus escopos em React e Next.js., Funções permitem modularizar e reutilizar código executando blocos específicos conforme necessário., Entenda como aplicar estilos em componentes usando CSS e Next.js, Criando componentes reutilizáveis e interface modular flexível., Flexibilizando componentes com props passando propriedades., Renderização condicional em React é uma técnica essencial para exibir ou ocultar componentes com base em condições específicas do código., React Router permite a criação de rotas em aplicações React possibilitando navegação fluida entre componentes sem recarregar a página. Isso facilita a organização e manutenção do código., Neste conteúdo abordamos como criar listas dinâmicas em React com Next.js e TypeScript com foco em preencher um elemento usando dados variáveis.","O Next.js é um framework para criar aplicações web rápidas e escaláveis com React oferecendo renderização server-side e páginas estáticas que melhoram desempenho e SEO.,Aprenda a usar variáveis e constantes para armazenar valores e entender seus escopos em React e Next.js.,Funções permitem modularizar e reutilizar código executando blocos específicos conforme necessário.,Entenda como aplicar estilos em componentes usando CSS e Next.js,Criando componentes reutilizáveis e interface modular flexível.,Flexibilizando componentes com props passando propriedades.,Renderização condicional em React é uma técnica essencial para exibir ou ocultar componentes com base em condições específicas do código.,React Router permite a criação de rotas em aplicações React possibilitando navegação fluida entre componentes sem recarregar a página. Isso facilita a organização e manutenção do código.,Neste conteúdo abordamos como criar listas dinâmicas em React com Next.js e TypeScript com foco em preencher um elemento usando dados variáveis.",rw1730225705921272534 +Projetos Fullstack,Um espaço para aplicar habilidades em TypeScript e explorar conceitos aprendidos de forma prática por meio de projetos desafiadores.,"Este tema oferece uma oportunidade para reforçar o aprendizado em TypeScript através de projetos que envolvem o uso de condicionais, arrays e outros conceitos fundamentais. Os exercícios propostos ajudam a resolver problemas reais, promovendo a compreensão e aplicação de lógica de programação, manipulação de dados e boas práticas de desenvolvimento. + +A abordagem prática incentiva a exploração de diferentes cenários, a construção de soluções criativas e o desenvolvimento da confiança necessária para enfrentar desafios no mundo da programação. É o espaço ideal para consolidar o aprendizado e avançar no domínio do TypeScript. +",Preparando A Máquina - NIVELAMENTO .png (https://cdn.filestackcontent.com/3IA30CKOScK7LUvKg8ix),"Projeto Pokémon,Projeto Acelera Movies",Nivelamento,"rw1732546252209eee8fb,2025-10-17T19:19:46+00:00",Ícone de uma planilha com engrenagens ao lado do titulo do card (Projetos Fullstack) com fundo em tons azuis.,11,"rw1732546252209eee8fb,rw17326239607377fa730","Explore o mundo Pokémon enquanto aprende habilidades incríveis de front-end e back-end., Este projeto consiste na criação de uma biblioteca de filmes utilizando os templates pré-configurados de repositórios fornecidos pela Aceleradora TW.","Explore o mundo Pokémon enquanto aprende habilidades incríveis de front-end e back-end.,Este projeto consiste na criação de uma biblioteca de filmes utilizando os templates pré-configurados de repositórios fornecidos pela Aceleradora TW.",rw1733155048176679f2e +Testes Unitários com Jest,Aprenda como escrever e executar testes unitários usando o Jest uma das ferramentas de teste mais populares para JavaScript.,"O Jest é uma ferramenta poderosa que facilita a escrita de testes para garantir que o seu código esteja funcionando corretamente. Este módulo irá abordar os conceitos fundamentais dos testes unitários, como configurá-los no Jest, criar mocks e espiar funções, e também fornecerá exemplos práticos para você começar a testar suas aplicações. +",JEST - NIVELAMENTO.png (https://cdn.filestackcontent.com/7FZcEtuOSjat9essw6QS),"Conceitos Básicos de Testes Unitários,Escrevendo Testes Simples com Jest,Testando Funções e Módulos com Jest, Cobertura de Código,Mocking e Espiões,Testando Código com Dependências Externas, Testando Componentes React ,Boas Práticas de Testes",Nivelamento,"rw1732729739182de554a,rw1732729774319f3a701,rw1732734177188ad5703,2025-10-17T19:19:46+00:00,rw17327243381915bac78,rw1732725191266b72448,rw1732725482864a45477,2025-10-17T19:19:46+00:00",Ícone do jest.js (um sapato estilo de palhaço) ao lado do titulo do card (Testes unitários com jest.js) com fundo em tons azuis.,12,"rw1732729739182de554a,rw1732729774319f3a701,rw1732734177188ad5703,rw1732734206416123fc2,rw17327243381915bac78,rw1732725191266b72448,rw1732725482864a45477,rw1732726244691adcd36","Compreenda o que são testes unitários, a importância de garantir a qualidade do código e quando utilizá-los., Aprenda a usar o Jest para criar testes básicos. , Explore como testar funções e módulos em JavaScript utilizando Jest para garantir que seu código esteja funcionando corretamente., Entenda a importância da cobertura de código e como utilizar ferramentas para medir e melhorar a qualidade dos seus testes., Entenda a importância dos Spies e como usá-los para melhorar seus testes automatizados., Aprenda a testar código que depende de serviços externos, como APIs de terceiros enquanto garante a confiabilidade e a estabilidade dos seus testes., Aprender a testar componentes React utilizando bibliotecas e boas práticas para garantir qualidade e funcionalidade., Boas práticas de testes são essenciais para garantir a qualidade do código e facilitar a manutenção dos sistemas.","Compreenda o que são testes unitários, a importância de garantir a qualidade do código e quando utilizá-los.,Aprenda a usar o Jest para criar testes básicos. ,Explore como testar funções e módulos em JavaScript utilizando Jest para garantir que seu código esteja funcionando corretamente.,Entenda a importância da cobertura de código e como utilizar ferramentas para medir e melhorar a qualidade dos seus testes.,Entenda a importância dos Spies e como usá-los para melhorar seus testes automatizados.,Aprenda a testar código que depende de serviços externos, como APIs de terceiros enquanto garante a confiabilidade e a estabilidade dos seus testes.,Aprender a testar componentes React utilizando bibliotecas e boas práticas para garantir qualidade e funcionalidade.,Boas práticas de testes são essenciais para garantir a qualidade do código e facilitar a manutenção dos sistemas.",rw17331575209736c7811 \ No newline at end of file diff --git a/prisma/data/topics.csv b/prisma/data/topics.csv new file mode 100644 index 0000000..2a0d187 --- /dev/null +++ b/prisma/data/topics.csv @@ -0,0 +1,5628 @@ +title,cardDescription,themes,description,idTopics,videoInfo,video,videoReference,videoDescription,videoLink,references,exercisesDescription,exercisesInfo,exercises +Props,Props em React.js são fundamentais para criar componentes reutilizáveis e dinâmicos.,React.js,"**O que são Props?** A palavra ""Props"" é uma abreviação de ""propriedades"". Em React, Props são usadas para passar dados de um componente pai para um componente filho, permitindo um fluxo de dados unidirecional. Essa funcionalidade torna os componentes mais flexíveis e reutilizáveis, pois eles podem exibir diferentes dados dependendo das Props recebidas. **Exemplo de Componente Sem e Com Props** Para ilustrar o uso de Props, vamos comparar dois exemplos de componentes: um com dados estáticos e outro com Props. **Componente sem Props (dados estáticos):** ```javascript const DizerOla = () => { return ( Olá, José ); }; ``` Neste caso, o componente `DizerOla` sempre exibe ""Olá, José"", independentemente do contexto em que é usado. Ele é fixo e não reutilizável para outros nomes. **Componente com Props (dados dinâmicos):** ```javascript const DizerOlaComProps = (props) => { return ( Olá, {props.nome} ); }; // Adicionando o componente ao App const App = () => { const nome = 'José'; return ( ); }; ``` Agora, o componente `DizerOlaComProps` é mais dinâmico. Ele recebe a Prop `nome`, permitindo que a pessoa desenvolvedora defina o valor que será exibido ao reutilizar o componente. **Props em Detalhes** As Props em React são somente leitura. Isso significa que, uma vez passadas para um componente, elas não podem ser modificadas dentro desse componente. Tentar alterar diretamente uma Prop resultará em um erro. Props podem ser acessadas por meio de desestruturação para tornar o código mais limpo e legível: ```javascript const DizerOlaComProps = ({ nome }) => { return ( Olá, {nome} ); }; ``` **Passando Valores Padrão para Props** É possível definir valores padrão para as Props, garantindo que o componente sempre tenha um valor mesmo quando nenhuma Prop for passada: ```javascript const DizerOlaComProps = ({ nome = 'Desconhecido' }) => { return ( Olá, {nome} ); }; ``` **Props Além de Dados: Funções e Objetos** Props não se limitam a strings ou números; você pode passar funções e objetos para componentes. Isso permite que a pessoa desenvolvedora crie componentes que sejam mais interativos e que se comuniquem com o componente pai: ```javascript const ComponenteComFuncao = ({ acao }) => { return ( Clique aqui ); }; const App = () => { const mostrarMensagem = () => { alert('Botão clicado!'); }; return ( ); }; ``` **Conclusão** Props em React são como argumentos de funções, aceitando variados tipos de dados e funções. Elas permitem que você, pessoa desenvolvedora, crie componentes reutilizáveis e mais dinâmicos, personalizando a exibição de informações e melhorando a interação com a pessoa usuária. Explore essa funcionalidade para desenvolver aplicativos mais robustos e flexíveis. ",rw1730380625688dfb8ce,rw1730480898416cd510b,# Aprenda Props no React de Forma Simples e Rápida! | Recorte,Felipe Rocha • Full Stack Club,"[{""foreignRowId"":""rw1730480898416cd510b"",""foreignRowDisplayName"":""Este vídeo ensina tudo sobre Props no React, um conceito essencial para a comunicação entre componentes. Você aprenderá como elas funcionam, sua importância para criar aplicações modulares e reutilizáveis, e como usá-las para passar dados de forma eficiente. Dominar Props é fundamental para avançar no React!""}]",https://www.youtube.com/watch?v=MEUdCa9mPNM,[React - O que são Props](https://dev.to/nascimento_/react-o-que-sao-props-5h39),,, +Como posso aprender a programar?,Aqui você encontrará dicas para te ajudar a dar os primeiros passos na programação.,Iniciando a Jornada,"Aprender a programar pode ser uma jornada divertida e gratificante, e existem várias maneiras de começar. Não existe uma ""maneira correta"" de aprender, já que cada pessoa pode descobrir o que funciona melhor para si. Aqui estão algumas dicas: + +**Escolha uma linguagem de programação:** + +Começar com uma linguagem que seja relativamente simples e amplamente usada pode ajudar a entender os conceitos básicos. Algumas boas opções são: + +- **Python:** Fácil de aprender, com uma sintaxe simples e limpa. +- **JavaScript:** Ideal para desenvolvimento web e popular em projetos frontend e backend. +- **HTML/CSS:** Não são linguagens de programação, mas são fundamentais para desenvolvimento web e têm conceitos fáceis de entender para iniciantes. + +**Aprenda os Fundamentos:** + +Domine os conceitos básicos da linguagem de programação que você está estudando, como variáveis, tipos de dados, estruturas de controle e funções. + +**Pratique Bastante:** + +A melhor maneira de aprender programação é através da prática. Faça exercícios, resolva problemas e participe de projetos para aplicar o que você está aprendendo. + +**Utilize recursos Online:** + +Existem diversos recursos online gratuitos e pagos que podem te ajudar a aprender programação, como tutoriais, videoaulas, cursos online e fóruns de discussão. + +**Participe de comunidades de pessoas Programadoras:** + +Interaja com outras programadoras online ou presencialmente para trocar experiências, tirar dúvidas e se manter motivado. + +- Stack Overflow +- Reddit +- Discord(comunidades de programação) + +**Seja Paciente:** + +Aprender programação leva tempo e esforço. Não desanime se você não entender algo na primeira vez. Continue praticando e buscando ajuda quando necessário. + +**Comemore suas Conquistas:** +Reconheça e comemore seus progressos, por menores que sejam. Isso te ajudará a se manter motivado e confiante. + +**Cuide da Sua Saúde Física e Mental:** + +Mantenha uma boa alimentação, pratique exercícios físicos e durma bem. A saúde física e mental são essenciais para um bom desempenho nos estudos.",rw17192374230680ab385,rw171802568550836053b,# Como posso aprender a programar?,Alura,"[{""foreignRowId"":""rw171802568550836053b"",""foreignRowDisplayName"":""Para quem está começando no mundo da programação, uma das principais dúvidas são: **por onde começar?** Neste vídeo, Gabs Ferreira e Paulo Silveira compartilham dicas valiosas sobre como dar os primeiros passos nesse universo.""}]",https://www.youtube.com/watch?v=MwCx2qKdbDw,[7 dicas práticas de como aprender a programar](https://www.alura.com.br/artigos/como-comecar-programar),,, +Técnicas para aprender a programar,Essas técnicas ajudam a aprender programação e se aplicam a outras áreas.,Iniciando a Jornada,"Aprender a programar pode ser desafiador, especialmente ao enfrentar tópicos mais avançados, mas isso faz parte do processo. Existem algumas técnicas que são valiosas não apenas para superar essas dificuldades, mas também para quem está começando do zero. O mais importante é que esses métodos funcionam para qualquer linguagem de programação, seja Python, JavaScript, Node.js, Java, C#, PHP, HTML ou CSS. + +- **Desbloqueie sua mentalidade:** Entenda que você é capaz de aprender qualquer coisa, a única questão é o tempo que levará para isso. Não se limite pelas dificuldades iniciais. + +- **Combine teoria e prática:** Escreva o código por conta própria, evite copiar e colar. Estude e leia sobre o tema, mesmo que não compreenda tudo de imediato. Pause quando necessário e busque novas fontes de estudo para complementar seu entendimento. + +- **Use a repetição espaçada:** Pratique todos os dias, mesmo que por pouco tempo. Esse hábito faz uma grande diferença no processo de aprendizado e na memorização, uma técnica amplamente utilizada em aplicativos como o [Anki](https://apps.ankiweb.net/) para repetições.",rw1719237431883f5c222,rw17180256855225581f7,# 3 Técnicas que eu uso para aprender a programar qualquer coisa,Filipe Deschamps,"[{""foreignRowId"":""rw17180256855225581f7"",""foreignRowDisplayName"":""Neste vídeo, são apresentadas técnicas fundamentais para aprender programação, mesmo para aquelas pessoas que não se consideram naturalmente talentosas nessa área. ""}]",https://www.youtube.com/watch?v=ZtMzB5CoekE,[Dicas Para Estudar Programação: Aprenda De Forma Eficiente E Desenvolva Suas Habilidades](https://awari.com.br/dicas-para-estudar-programacao-aprenda-de-forma-eficiente-e-desenvolva-suas-habilidades/),,, +Instalar Visual Studio Code,Aprenda como realizar a instalação desta ferramenta.,Preparando a Máquina,"Uma das ferramentas mais importantes que você irá utilizar é o `Visual Studio Code`, - popularmente chamado de VSCode - um editor de código poderoso, intuitivo e altamente flexível, que oferece um ambiente de desenvolvimento eficiente. Siga as instruções abaixo para instalá-lo, conforme o sistema operacional da sua máquina. + + +**Windows** + +1. Acesse o [site oficial do Visual Studio Code](https://code.visualstudio.com/Download). +2. Baixe o instalador para Windows (.exe). +3. Execute o arquivo baixado (`VSCodeSetup-.exe`). +4. Siga as instruções do assistente de instalação, usando as opções padrão. +5. Ao final da instalação, o VSCode estará pronto para uso. Você o encontrará no menu Iniciar ou na área de trabalho. + +**Linux** + +Para instalar no Linux, abra o terminal e siga os comandos abaixo de acordo com sua distribuição: + +**Ubuntu/Debian:** + +```bash +sudo apt update +sudo apt install software-properties-common apt-transport-https wget +wget -q https://packages.microsoft.com/keys/microsoft.asc -O- | sudo apt-key add - +sudo add-apt-repository ""deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main"" +sudo apt update +sudo apt install code +``` +**Fedora:** + +```bash +sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc +sudo dnf config-manager --add-repo https://packages.microsoft.com/yumrepos/vscode +sudo dnf install code +``` + +Para outras distribuições, consulte a [documentação oficial do Visual Studio Code](https://code.visualstudio.com/docs). + +**macOS** + +1. Acesse o [site oficial do Visual Studio Code](https://code.visualstudio.com/Download). +2. Baixe o arquivo `.zip` para macOS. +3. Abra o arquivo `.zip` e arraste o aplicativo `Visual Studio Code.app` para a pasta `Applications`. +4. Abra o Finder, vá até `Applications` e inicie o `Visual Studio Code.app`. +5. Confirme a abertura do aplicativo, se for solicitado. + +**Observações** + +Certifique-se de que seu sistema atende aos requisitos mínimos. As instruções podem variar conforme novas atualizações são lançadas, por isso, **verifique** sempre a documentação mais recente. + +Seguindo essas etapas, seu ambiente de desenvolvimento estará pronto para você iniciar seus projetos. Estaremos explorando mais ferramentas e técnicas nas próximas sessões, para garantir que tudo esteja configurado corretamente para que você progrida com confiança!",rw171923779887648423e,rw1720197669951f72e18,# Veja como instalar VS Code,Ativs Code,"[{""foreignRowId"":""rw1720197669951f72e18"",""foreignRowDisplayName"":""Nesse vídeo, vemos o simples passo a passo para instalar no seu Windows o Visual Studio Code, um dos editores de código mais populares entre desenvolvedores. O VS Code oferece uma ampla variedade de extensões e ferramentas para programação em diversas linguagens, tornando o ambiente de desenvolvimento ágil e eficiente.""}]",https://www.youtube.com/watch?v=QT-YWT1-YI4,"[VsCode para iniciantes](https://www.youtube.com/watch?v=NXgsXiu4LtA) +[Como Instalar o Visual Studio Code (VSCode) no macOS?]( https://www.youtube.com/watch?v=A6chGzaJovs)",,, +Aprenda a aprender,Importância do aprendizado autônomo e habilidades essenciais para desafios do mercado.,Iniciando a Jornada,"Aprender de forma eficiente é uma habilidade essencial que pode ser desenvolvida em qualquer área, seja na programação ou em outros campos de conhecimento. Ao entender como nosso cérebro processa informações e adotar técnicas adequadas, podemos não apenas absorver o conteúdo mais rapidamente, mas também reter o aprendizado de forma duradoura. + +**Técnicas de Memorização:** + +Memorizar de forma eficiente não significa apenas decorar, mas realmente internalizar o conteúdo. Aqui estão algumas técnicas eficazes: + +- Mapas Mentais: Organizar informações em um formato visual ajuda a compreender e lembrar conceitos complexos. +- Técnica de Feynman: Explique o que você aprendeu como se estivesse ensinando a alguém. Isso ajuda a identificar lacunas no conhecimento. +- Repetição Espaçada: Revise o conteúdo em intervalos crescentes ao longo do tempo. Isso ajuda a fixar a memória de longo prazo. + +**Estratégias de Estudo:** + +Dicas práticas para otimizar o tempo de estudo e aumentar a produtividade: + +- Estudo Ativo: Ao invés de apenas ler ou assistir, interaja com o material por meio de exercícios, resumos ou perguntas. +- Técnica Pomodoro: Estude em blocos de tempo, como 25 minutos de foco intenso seguidos de 5 minutos de descanso. Isso melhora a concentração e previne a fadiga mental. +- Elaboração Interrogativa: Questione o conteúdo que está estudando com perguntas do tipo ""Por quê?"" ou ""Como isso funciona?"". Isso ajuda a formar conexões mais profundas com o material. +- Divisão do Estudo em Pequenos Blocos: Quebrar grandes temas em blocos menores facilita a absorção de informações e reduz a sensação de sobrecarga. + +**Motivação e Disciplina:** + +A motivação e a disciplina são pilares fundamentais no processo de aprendizagem, e cada uma desempenha um papel crucial para garantir o sucesso a longo prazo. + +- Defina Metas Claras: Objetivos específicos e alcançáveis aumentam a motivação e proporcionam um senso de progresso. +- Crie um Ambiente Favorável: Elimine distrações e crie um espaço propício para a concentração. +- Recompensas e Pausas: Ofereça a si mesmo pequenas recompensas ao atingir metas de estudo, o que pode manter a motivação em alta. + +**Erros Comuns:** + +Erros comuns no processo de aprendizagem, como a procrastinação, a falta de planejamento e a repetição passiva de conteúdos, podem comprometer a retenção e o progresso.",rw17195834951124516c5,rw1719238213648dc3250,# Guia definitivo de Aprendendo a Aprender,Fabio Akita,"[{""foreignRowId"":""rw1719238213648dc3250"",""foreignRowDisplayName"":""O vídeo é um guia detalhado sobre técnicas e estratégias para melhorar a aprendizagem. Aborda tópicos como: entendendo o funcionamento do cérebro, técnicas de memorização, estratégias de estudo, motivação, disciplina e erros comuns.""}]",https://www.youtube.com/watch?v=oUPaJxk6TZ0,"[Guia DEFINITIVO de Aprendendo a Aprender | A maior BRONCA da sua vida](https://www.akitaonrails.com/2020/04/01/akitando-76-guia-definitivo-de-aprendendo-a-aprender-a-maior-bronca-da-sua-vida-rated-r) +[5 dicas para aprender melhor e mais rápido](https://unileao.edu.br/blog/aprender-melhor-e-mais-rapido/) +[Como aprender a aprender: 7 dicas para melhorar seu aprendizado +](https://blog.escolaconquer.com.br/como-aprender-a-aprender-7-dicas-para-melhorar-seu-aprendizado/) +[Técnica Pomodoro: saiba como gerenciar seu tempo e ser mais produtivo](https://www.napratica.org.br/pomodoro/)",,, +Como posso estudar melhor,Organize seus estudos com disciplina e com dicas de planejamento.,Iniciando a Jornada,"Para organizar melhor seus estudos, aqui estão algumas dicas que podem te ajudar a criar uma rotina eficiente e produtiva: + +**Compromisso com a Agenda:** + +Marque horários específicos no seu calendário, assim como faria com compromissos sociais ou profissionais. Isso garante que você tenha tempo dedicado exclusivamente ao aprendizado. + +**Planejamento:** + +Use um calendário, agenda ou aplicativo de organização para planejar suas atividades de estudo e equilibrar o tempo entre diferentes tópicos ou matérias. + +**Estudo Contínuo:** + +Priorize a consistência no estudo. É mais eficiente estudar um pouco todos os dias do que tentar absorver grandes quantidades de informação de uma só vez. A repetição ajuda a fixar os conteúdos de forma mais duradoura. + +**Definição de Tarefas:** + +No final de cada dia, planeje o dia seguinte definindo blocos de tempo para cada tarefa. Ao decidir previamente o que vai estudar e em quais horários, você evita a indecisão e aumenta a produtividade, aproveitando melhor seu tempo.",rw1719583500014767687,rw171802568549384bdc9,# Como posso estudar melhor?,Alura,"[{""foreignRowId"":""rw171802568549384bdc9"",""foreignRowDisplayName"":""O vídeo apresenta dicas para melhorar a organização nos estudos, destacando a importância de estabelecer compromissos semanais, como em compromissos sociais, e utilizar uma agenda ou calendário para planejar horários específicos para cada disciplina. Sugere evitar o estudo intenso de última hora, espaçando o aprendizado para melhor retenção, e alternar entre momentos de foco e relaxamento para consolidar o conhecimento.""}]",https://www.youtube.com/watch?v=Is6c9KSGCbk,"[Conheça 10 dicas para estudar melhor, segundo a ciência](https://www.napratica.org.br/dicas-para-estudar-melhor-ciencia/)",,, +Como estudo programação,Aprenda fundamentos e conceitos básicos da linguagem de programação.,Iniciando a Jornada,"Melhores Práticas para Aprender Programação para Iniciantes + +- **Comece com os Fundamentos:** Dominar os conceitos básicos é essencial. Entenda as estruturas de controle, tipos de dados e funções antes de avançar. + +- **Pratique Regularmente:** A prática constante é fundamental para o aprendizado eficaz. Escreva código regularmente para ganhar familiaridade e melhorar suas habilidades. + +- **Faça Projetos Pequenos:** Criar projetos pequenos ajuda a aplicar o que você aprendeu de maneira prática. Isso também ajuda a manter a motivação e a consolidar o conhecimento. + +- **Busque Compreensão Profunda:** Não se contente em apenas copiar e colar código. Busque entender como e por que as coisas funcionam. Isso ajuda a resolver problemas de maneira mais eficaz. + +- **Utilize Recursos Online:** Aproveite plataformas de aprendizado online, como cursos e tutoriais em vídeo, para expandir seus conhecimentos e explorar novos conceitos. + +- **Participe de Comunidades:** Envolva-se em comunidades de programação para compartilhar experiências, obter suporte e aprender com outros programadores. + +- **Mantenha-se Atualizado:** A tecnologia muda rapidamente. Esteja sempre disposto a aprender novas linguagens e ferramentas conforme necessário para se manter relevante.",rw171958350792237d5b0,rw171802568547809418e,# Como estudo programação?,Rafaella Ballerini,"[{""foreignRowId"":""rw171802568547809418e"",""foreignRowDisplayName"":""O vídeo aborda tópicos importantes para ajuda na hora do estudo sobre programação\nOrganização, Métodos de Estudo, Ambiente de Estudo. Autoconhecimento, Estudo de Programação e Motivação e Produtividade.""}]",https://www.youtube.com/watch?v=Xfgc3ZDtwTQ,[Como começar a programar?](https://www.alura.com.br/artigos/como-comecar-programar?utm_term=&utm_campaign=%5BSearch%5D+%5BPerformance%5D+-+Dynamic+Search+Ads+-+Artigos+e+Conte%C3%BAdos&utm_source=adwords&utm_medium=ppc&hsa_acc=7964138385&hsa_cam=11384329873&hsa_grp=164240702375&hsa_ad=703853654617&hsa_src=g&hsa_tgt=dsa-2276348409543&hsa_kw=&hsa_mt=&hsa_net=adwords&hsa_ver=3&gad_source=1&gclid=Cj0KCQjw9Km3BhDjARIsAGUb4nySBLBighkqo8L10b1YjAaIWnHf8zh4Rdr4lEiOLipQnDB6GBLOCSgaAjRPEALw_wcB),,, +Extensões no Visual Studio Code,Adicione extensões que facilitam na manipulação do código.,Preparando a Máquina,"As **extensões** são ferramentas adicionais que podem ser instaladas no Visual Studio Code, para melhorar e personalizar a experiência de desenvolvimento. Elas oferecem funcionalidades extras, como suporte a novas linguagens de programação, ferramentas de formatação, temas visuais, integração com sistemas de controle de versão e muito mais. + +Para otimizar sua experiência de codificação no Visual Studio Code, você pode instalar algumas extensões essenciais que melhorarão a produtividade e a organização do código. Siga os passos abaixo para adicionar as extensões: + +**Como instalar as extensões**: + +1. Abra o **Visual Studio Code**. +2. Clique no ícone de **Extensões** na barra lateral esquerda ou pressione: + - No **Windows/Linux**: `Ctrl+Shift+X` + - No **macOS**: `Cmd+Shift+X` +3. Na barra de pesquisa, digite o nome da extensão desejada. +4. Clique em **Instalar** na extensão correspondente. + +**Extensões recomendadas:** + +1. **Dracula Official** + Altere o tema do VS Code para o estilo escuro do Dracula, que é visualmente agradável e ajuda a reduzir o cansaço visual. + +2. **GitLens → Git supercharged** + Melhore sua visualização de histórico Git diretamente no editor. Veja quem fez mudanças no código, explore commits, branches e muito mais. + **Caminho**: Depois de instalar, conecte sua conta do GitHub clicando no ícone do GitHub na barra inferior direita. + +3. **IntelliCode** + Receba sugestões inteligentes de código baseadas em padrões de desenvolvimento. Ao escrever CSS, JavaScript, ou outras linguagens, o IntelliCode apresenta opções de preenchimento automático personalizadas. + +4. **Material Icon Theme** + Adiciona ícones visuais às pastas e arquivos do projeto, facilitando sua identificação. Por exemplo, o arquivo JavaScript exibe o ícone amarelo correspondente. + +5. **Prettier - Code Formatter** + Um formatador de código eficiente e amplamente utilizado. Ele ajusta automaticamente a formatação do seu código de acordo com as regras do projeto, garantindo um estilo consistente. + **Dica**: Após a instalação, configure as regras de formatação no arquivo de configurações do projeto. + +6. **vscode-styled-components** + Ideal para quem utiliza `styled-components` no React. Essa extensão melhora o destaque de sintaxe, mostrando o código CSS de maneira organizada dentro dos arquivos JavaScript. +",rw17201095165728b5a2f,rw1720199151690506d7d,# 20 Extensões VS Code para otimizar seu tempo na programação,Hero Code,"[{""foreignRowId"":""rw1720199151690506d7d"",""foreignRowDisplayName"":""Neste vídeo, você aprenderá a instalar 20 extensões essenciais no Visual Studio Code para maximizar sua produtividade e personalizar seu ambiente de desenvolvimento. Cada extensão é explicada brevemente, destacando suas funcionalidades e como podem facilitar seu fluxo de trabalho.""}]",https://www.youtube.com/watch?v=7P2idkQBZws,,,, +Instalação para Windows,Instruções para instalar o PostgreSQL no Windows baixando o instalador adequado do site oficial do PostgreSQL.,Configurando Banco de Dados,"Siga os passos abaixo: + +**1. Baixe o Instalador:** + + Acesse o site oficial do [PostgreSQL](https://www.postgresql.org/download/windows/) e baixe o instalador adequado para o seu sistema (32-bit ou 64-bit). Selecione a versão mais recente disponível. + +**2. Execute o Instalador:** + + Dê um duplo clique no arquivo de instalação que você baixou. Isso iniciará o assistente de instalação. + +**3. Configuração Inicial:** + + - Escolha o diretório de instalação. O padrão geralmente é adequado, mas você pode escolher outro se preferir. + + - Selecione os componentes a serem instalados. A opção padrão geralmente inclui tudo o que você precisa. + +**4. Defina Senha do Superusuário:** + + Durante a instalação, será solicitado que você defina uma senha para a pessoa usuária superusuária (PostgreSQL). Escolha uma senha forte e lembre-se dela, pois você a utilizará para administrar o banco de dados. + +**5. Porta de Conexão:** + + Configure a porta de conexão. A porta padrão é 5432. + +**6. Local e Codificação:** + + Configure o local e a codificação de acordo com suas preferências ou mantenha as configurações padrão. + +**7. Inicie o Serviço:** + + No final da instalação, você será perguntado se deseja iniciar o serviço do PostgreSQL. Deixe a opção marcada para que o serviço seja iniciado automaticamente. + +**8. Conclua a Instalação:** + + Conclua o assistente de instalação. + +--- + +## Instalação do DBeaver no Windows +​ +​Acesse o site oficial do [DBeaver](https://dbeaver.com/docs/dbeaver/) + + +**1. Baixe o Instalador do DBeaver:** + + No site, clique no botão [Download](https://dbeaver.io/download/) e selecione a versão adequada para o Windows. + +**2. Execute o Instalador:** + + Após o download, execute o arquivo de instalação que você baixou. O instalador geralmente tem um nome como `dbeaver-ce--x86_64-setup.exe` para a versão de 64 bits ou similar. + + **3. Configurações de Instalação:** + + Siga as instruções do assistente de instalação. Você pode aceitar as configurações padrão ou personalizá-las conforme necessário. Certifique-se de selecionar a opção para adicionar o DBeaver ao PATH durante a instalação. + +**4. Conclua a Instalação:** + Aguarde até que a instalação seja concluída. O DBeaver será instalado no seu sistema. + +**5. Inicie o DBeaver:** + + Após a instalação, encontre o ícone do DBeaver no menu Iniciar ou na área de trabalho e clique para iniciar o aplicativo. + +**6. Configuração Inicial:** + + Durante a primeira execução, o DBeaver pode pedir para configurar algumas opções, como o local do JDK (Java Development Kit). Siga as instruções, se necessário.",rw1720109585838a51c06,rw17256336124819cd8eb,# Como Instalar o PostgreSQL no Windows,Rogério Napoleão Jr,"[{""foreignRowId"":""rw17256336124819cd8eb"",""foreignRowDisplayName"":""Neste vídeo, você aprenderá de forma rápida e direta como fazer a instalação do PostgreSQL no Windows.""}]",https://www.youtube.com/watch?v=UbX-2Xud1JA,"[Conectando no banco de dados PostgreSQL utilizando DBeaver Community](https://alexdepaula18.medium.com/conectando-no-banco-de-dados-postgresql-utilizando-dbeaver-community-1275f4c9bcba) +[Como instalar o Dbeaver Community no Windows](https://www.youtube.com/watch?v=My08qYIJbR4) +[Como Instalar o DBeaver no Windows - Passo a Passo Rápido](https://www.youtube.com/watch?v=2M6nBt7ai28) +[Criando e Configurando a Conexão do DBeaver com o PostgreSQL](https://www.youtube.com/watch?v=USUN-brxWl8)",,, +Instalação para macOS,Instruções para instalar o PostgreSQL e o no macOS baixando o instalador adequado do site oficial do PostgreSQL.,Configurando Banco de Dados,"Para configurar o PostgreSQL no macOS, você pode usar o Homebrew, um gerenciador de pacotes popular no sistema. Siga os passos abaixo: + +**1. Instale o Homebrew (caso ainda não tenha):** + +Se o Homebrew não estiver instalado, abra o Terminal e execute o seguinte comando para instalá-lo: + +```bash +/bin/bash -c ""$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"" +``` + +Este comando instalará o Homebrew no seu sistema. Após a instalação, você pode verificar se está tudo certo com: + +```bash +brew --version +``` + +**2. Instale o PostgreSQL:** + +Com o Homebrew instalado, prossiga com a instalação do PostgreSQL usando o comando: + +```bash +brew install postgresql +``` + +Isso instalará o PostgreSQL junto com todas as dependências necessárias. + +**3. Inicie o PostgreSQL:** + +Após a instalação, inicie o PostgreSQL com o comando: + +```bash +brew services start postgresql +``` + +Este comando garante que o PostgreSQL será iniciado automaticamente ao iniciar o sistema. Para confirmar que ele está rodando, você pode usar: + +```bash +brew services list +``` + +**4. Verifique a Instalação:** + +Agora, você pode verificar se o PostgreSQL foi instalado corretamente executando o seguinte comando para acessar o shell do banco de dados: + +```bash +psql postgres +``` + +Se tudo estiver correto, você verá o prompt do PostgreSQL. Agora, seu banco de dados está pronto para uso! + +--- + +## Instalação do DBeaver no macOS + +O DBeaver é uma ferramenta gráfica popular para gerenciar bancos de dados. Veja como instalá-la no macOS: + +**1. Baixe o DBeaver:** + +Visite o [site oficial do DBeaver](https://dbeaver.io/download/) e baixe a versão **Community Edition** para macOS. + +**2. Instale o DBeaver:** + +Após o download do arquivo `.dmg`, que geralmente estará na sua pasta de downloads, siga os passos abaixo: + +- Abra o arquivo `.dmg`. +- Arraste o ícone do DBeaver para a pasta ""Aplicativos"" para concluir a instalação. + +**3. Configure o Java Development Kit (JDK):** + +O DBeaver depende do Java para funcionar. Se o JDK não estiver instalado, você será solicitado a instalá-lo. Você pode baixar a versão mais recente do JDK diretamente do [site oficial da Oracle](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html) ou seguir as instruções fornecidas pelo próprio DBeaver. + +**4. Abra o DBeaver:** + +Vá até a pasta ""Aplicativos"" e abra o DBeaver. Se o macOS exibir uma mensagem de segurança sobre o aplicativo ter sido baixado da internet, confirme que deseja abrir. + +**5. Inicie e Configure o DBeaver:** + +Na primeira execução, o DBeaver pode pedir para configurar preferências básicas, como o tema e as configurações de workspace. Basta seguir as instruções. Após isso, você pode adicionar novas conexões de banco de dados, incluindo o PostgreSQL que você acabou de instalar. + +Agora, você tem o DBeaver instalado e configurado, pronto para gerenciar seus bancos de dados no macOS!",rw172019665783251efa3,rw17256341835236ba28a,# Como instalar o PostgreSQL no Mac,Programming Knowledge,"[{""foreignRowId"":""rw17256341835236ba28a"",""foreignRowDisplayName"":""Neste vídeo, você aprenderá de forma rápida e direta como fazer a instalação do PostgreSQL no Mac .""}]",https://www.youtube.com/watch?v=PShGF_udSpk,"[Documentação Dbeaver](https://dbeaver.com/docs/dbeaver/) +[Documentação PostgreSQL](https://www.postgresql.org/docs/) +[Como instalar o PostegreSQL](https://www.youtube.com/watch?v=JYVnabdUp-0) +[Como instalar o Postgresql](https://www.youtube.com/watch?v=shLDKvNF4Hc) +[Como instalar o Dbeaver no MacOS](https://www.youtube.com/watch?v=L5xnGT72-UEab_channel=DataWayBR) +[How to Install PostgreSQL on macOS](https://www.youtube.com/watch?v=PShGF_udSpk) +[Como conectar o postgresql e o dbeavr no macos](https://www.youtube.com/watch?v=OjsIKtTFYW8) +",,, +Instalação para Linux,Instruções para instalar o PostgreSQL no Linux baixando o instalador adequado do site oficial do PostgreSQL.,Configurando Banco de Dados,"Siga os passos abaixo: + + + + **1.Adicionar o repositório do PostgreSQL:** + Abra o terminal e execute este comando: + + ```bash + + sudo sh -c 'echo ""deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main"" > /etc/apt/sources.list.d/pgdg.list' + ``` + Esse comando adiciona o repositório oficial do PostgreSQL ao seu sistema. + + **2.Importar a chave de assinatura:** + + Execute o seguinte comando: + + ```bash + wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - + ``` + + Ele baixa e adiciona a chave de segurança que garante a autenticidade dos pacotes do PostgreSQL. + + + **3.Atualizar a lista de pacotes:** + + Para incluir as informações do novo repositório, use o comando: + + ```bash + + sudo apt-get update + + ``` + + **4.Instalar o PostgreSQL:** + + Agora, instale o PostgreSQL com o comando: + + ```bash + + sudo apt-get -y install postgresql + + ``` + + O PostgreSQL está pronto para uso no seu sistema Linux. + + +​**5.Configurando a senha:** + +​Abrir o terminal e rodar os seguintes comandos: + +```bash + +​sudo -i -u postgres + +psql + +``` + +Isso vai abrir o console do PostgreSQL. +Para definir uma senha para o usuário postgres: +```bash +ALTER USER postgres PASSWORD 'nova_senha'; +``` +Depois, digite \q para sair do PostgreSQL e exit para voltar ao usuário normal. + +--- + +### Instalação do DBeaver no Linux: + + **1.Baixar e instalar o DBeaver:** + Depois de configurar o repositório, instale o DBeaver com: + + ```bash + sudo apt-get -y install dbeaver-ce + ``` +​ + Isso instalará a versão gratuita (Community Edition) do DBeaver, uma ferramenta para gerenciar e visualizar bancos de dados. + + +Depois desses passos, você poderá usar o DBeaver para administrar seus bancos de dados de forma simples e eficiente.",rw1720196673427294957,rw1720441083154060eaf,# Instalando o PostgreSQL e pgAdmin no Linux Ubuntu,José Ailton TI,"[{""foreignRowId"":""rw1720441083154060eaf"",""foreignRowDisplayName"":""Nesse vídeo vemos o simples passo a passo para instalar o PostgreSQL e a interface de usuário PgAdmin 4. Postgres é um dos ambientes SQL mais utilizados em todo o mundo.""}]",https://www.youtube.com/watch?v=1jSb4LJH1dw,"[Documentação PostgreSQL](https://www.postgresql.org/download/linux/redhat/) +[Documentação DBeaver](https://dbeaver.com/docs/dbeaver/Local-Client-Configuration/#local-client-configuration-for-mac-and-linux) +[Instalar banco de dados PostgreSQL no Linux](https://www.youtube.com/watch?v=TeOryFA67zA) +[Como instalar o DBeaver no Ubuntu](https://www.youtube.com/watch?v=JCLUXgmpOHQ) +[Como conectar o DBeaver ao PostgreSQL](https://www.youtube.com/watch?v=OjsIKtTFYW8) +[Como instalar o Dbeaver no Ubunto - Espanhol](ttps://www.youtube.com/watch?v=5SEsBPUMCtY&ab_channel=Developerstepbystep)",,, +Fundamentos,Seus principais benefícios incluem detecção de erros em tempo de desenvolvimento e autocompletar de código mais inteligente melhorando a produtividade das pessoas desenvolvedoras.,TypeScript: Fundamentos,"TypeScript é uma linguagem de programação desenvolvida pela Microsoft que estende o JavaScript, adicionando recursos avançados de tipagem e programação orientada a objetos (POO). É projetado para ajudar as pessoas desenvolvedoras a escrever código mais robusto e menos propenso a erros, e funciona como um superconjunto do JavaScript. Isso significa que qualquer código JavaScript válido também é válido em TypeScript, mas TypeScript oferece funcionalidades adicionais para aprimorar o desenvolvimento. + +**Tipagem Estática** + +Um dos principais recursos do TypeScript é a tipagem estática. Ao contrário do JavaScript, que é uma linguagem dinamicamente tipada (onde os tipos de dados das variáveis são determinados em tempo de execução), o TypeScript permite que as desenvolvedoras especifiquem os tipos de variáveis, parâmetros de funções e valores de retorno. Isso é feito por meio de anotações de tipo. Por exemplo, você pode definir que uma variável deve sempre conter um número ou uma string, e o compilador do TypeScript verificará se o código está em conformidade com essas especificações antes de ser executado. + +**Inferência de Tipos** + +Embora você possa especificar tipos explicitamente, o TypeScript também possui um mecanismo de inferência de tipos. Isso significa que, mesmo que você não declare um tipo explicitamente, o TypeScript tentará inferir o tipo com base no valor que é atribuído à variável. Isso pode simplificar o código e reduzir a necessidade de declarações de tipo repetitivas, mantendo ao mesmo tempo a segurança que a tipagem oferece. + +**Classes e Interfaces** + +TypeScript introduz uma sintaxe de classe mais rica, inspirada na programação orientada a objetos. As classes em TypeScript suportam conceitos como herança, encapsulamento e polimorfismo. Além disso, TypeScript permite definir interfaces que funcionam como contratos para objetos, especificando quais propriedades e métodos um objeto deve ter. Interfaces ajudam a garantir que as classes e objetos implementem os contratos esperados, melhorando a coesão e a integridade do código. + +**Generics** + +Os generics são um recurso poderoso em TypeScript que permite criar funções e classes que podem trabalhar com diferentes tipos de dados sem sacrificar a segurança de tipos. Ao usar generics, você pode definir tipos variáveis que são especificados no momento da chamada da função ou criação da instância da classe. Isso promove a reutilização do código e permite a criação de componentes mais flexíveis e genéricos. + +**Compilação para JavaScript** + +TypeScript é uma linguagem compilada, o que significa que o código TypeScript precisa ser convertido em JavaScript para ser executado em ambientes que entendem JavaScript, como navegadores da web ou servidores Node.js. O processo de compilação é gerenciado pelo compilador `tsc`, que traduz o código TypeScript em JavaScript e verifica se há erros de tipo. Esse processo de compilação também pode ser configurado para gerar código que é compatível com versões específicas do ECMAScript, garantindo que o código funcione em diferentes ambientes. + +**Suporte a Recursos Modernos** + +TypeScript é projetado para ser compatível com as últimas funcionalidades do ECMAScript, que é o padrão de linguagem JavaScript. Isso inclui suporte para recursos modernos como módulos, funções assíncronas e destructuring. Assim, você pode aproveitar as novas funcionalidades do JavaScript enquanto ainda se beneficia das melhorias de tipo e segurança oferecidas pelo TypeScript. + +**Benefícios do TypeScript** + +- **Detecção Precoce de Erros**: Com a verificação de tipos em tempo de compilação, muitos erros são detectados antes que o código seja executado, reduzindo a possibilidade de falhas em tempo de execução. +- **Melhor Manutenabilidade**: A tipagem explícita e os contratos definidos por interfaces tornam o código mais legível e fácil de entender, facilitando a manutenção e a colaboração em equipe. +- **Desenvolvimento Orientado a Objetos**: Recursos como classes e interfaces promovem uma abordagem mais estruturada e orientada a objetos para o desenvolvimento, o que pode ser benéfico para projetos complexos. + +",rw1721236357157ccf465,rw1725630408780f28e7a,# Curso de TypeScript para iniciantes,Dimitri Teixeira | Programação Web,"[{""foreignRowId"":""rw1725630408780f28e7a"",""foreignRowDisplayName"":""Este guia abrange os principais aspectos do TypeScript, começando com uma introdução aos seus fundamentos, onde são apresentados os conceitos básicos que diferenciam o TypeScript do JavaScript, especialmente no que se refere à tipagem estática. Em seguida, são fornecidas instruções detalhadas sobre como instalar e configurar o TS em diferentes ambientes de desenvolvimento. Além de explorar os tipos básicos e interfaces disponíveis na linguagem. Este conteúdo é ideal para quem deseja adquirir uma compreensão sólida e abrangente do TypeScript, abordando desde os conceitos iniciais até as funcionalidades mais avançadas.""}]",https://www.youtube.com/watch?v=svUEOLz-tms,"[GitHub repositório](https://github.com/Wander06/exercicios-typescript-T26/tree/main) +[TypeScript: Vantagens, mitos, dicas e conceitos fundamentais](https://blog.rocketseat.com.br/typescript-vantagens-mitos-conceitos/)","Primeiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Segundo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Terceiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Quarto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido","rw1716905602727ecf72e,rw1725642159329a2d9f4,rw172564217048038aaf4,rw1725642166308a69249","Fizz Buzz,Objeto de data ,Apurar Votação,Números Armstrong" +Operadores,Os operadores em TypeScript permitem manipular valores em expressões aritméticas lógicas e de comparação.,TypeScript: Fundamentos,"O TypeScript oferece uma variedade de operadores semelhantes aos de JavaScript, com suporte ao sistema de tipos, proporcionando maior segurança. + +**1. Operadores Aritméticos** + +Os operadores aritméticos realizam operações matemáticas sobre valores numéricos: + +- `+` Adição: Soma dois valores. Exemplo: `let soma = 5 + 2;` + +- `-` Subtração: Subtrai um valor do outro. Exemplo: `let subtracao = 5 - 2;` + +- `*` Multiplicação: Multiplica dois valores. Exemplo: `let multi = 5 * 2;` + +- `/` Divisão: Divide um valor pelo outro. Exemplo: `let div = 5 / 2;` + +- `%` Módulo: Retorna o resto da divisão. Exemplo: `let resto = 5 % 2;` + +**2. Operadores de Atribuição** + +Os operadores de atribuição são usados para atribuir valores a variáveis: + +- `=` : Atribui um valor. Exemplo: `let x = 10;` + +- `+=` : Soma o valor da direita à variável e atribui o resultado. Exemplo: `x += 5;` + +- `-=` : Subtrai o valor da direita da variável e atribui o resultado. Exemplo: `x -= 3;` + +- `*=` : Multiplica a variável pelo valor da direita e atribui o resultado. Exemplo: `x *= 2;` + +- `/=` : Divide a variável pelo valor da direita e atribui o resultado. Exemplo: `x /= 2;` + +**3. Operadores de Comparação** + +Os operadores de comparação comparam dois valores e retornam um valor booleano (`true` ou `false`): + +- `==` Igualdade: Verifica se os valores são iguais (sem verificar o tipo). Exemplo: `5 == '5'; // true` + +- `===` Igualdade Estrita: Verifica se os valores e os tipos são iguais. Exemplo: `5 === '5'; // false` + +- `!=` Diferença: Verifica se os valores são diferentes. Exemplo: `5 != '5'; // false` + +- `!==` Diferença Estrita: Verifica se os valores ou tipos são diferentes. Exemplo: `5 !== '5'; // true` + +- `>` Maior que: Verifica se o valor à esquerda é maior que o à direita. + +- `=` Maior ou igual: Verifica se o valor à esquerda é maior ou igual ao à direita. + +- `<=` Menor ou igual: Verifica se o valor à esquerda é menor ou igual ao à direita. + +**4. Operadores Lógicos** + +Os operadores lógicos permitem combinar múltiplas condições: + +- `&&` E lógico: Retorna `true` se ambas as condições forem verdadeiras. + +- `||` Ou lógico: Retorna `true` se uma das condições for verdadeira. + +- `!` Não lógico: Inverte o valor booleano.",rw1721236361209aa4ab7,rw1725556521808c8761e,# Curso de Typescript - Operadores,Filipe Morelli Developer,"[{""foreignRowId"":""rw1725556521808c8761e"",""foreignRowDisplayName"":""Neste vídeo, será explorado o uso dos operadores em TypeScript. Serão abordados os operadores matemáticos, operadores de atribuição de valores, operadores de comparação e os operadores lógicos. O objetivo é mostrar como esses conceitos funcionam na prática e como podem ser aplicados no código em TypeScript.""}]",https://www.youtube.com/watch?v=nqM6wDp47Sw,[Operadores TypeScript](https://vidafullstack.com.br/typescript/operadores-typescript/),,, +Tipos de variáveis,A tipagem estática ajuda a capturar erros de tipo durante a compilação promovendo um código mais robusto e legível além de facilitar a manutenção.,TypeScript: Fundamentos,"No TypeScript, as variáveis são declaradas utilizando as palavras-chave `let`, `const` ou `var`. A escolha entre essas opções depende do comportamento desejado para a variável em questão. + +`let` é a maneira mais comum de declarar variáveis no TypeScript. Diferente do `var`, o `let` respeita o escopo de bloco, o que significa que a variável só estará acessível dentro do bloco onde foi declarada. Isso ajuda a evitar bugs relacionados ao escopo das variáveis. + +**Exemplo:** + +```typescript +let nome: string = ""Helena""; +``` + +Quando uma variável é declarada usando `let`, usa-se o que alguns chamam de escopo léxico ou escopo de bloco. Diferente de variáveis declaradas com var no qual o escopo permeia suas funções, variáveis com escopo de bloco não são visíveis de fora de seus blocos mais próximos ou loop-for. + +**Exemplo** + +```typescript +function f(input: boolean) { + let a = 100; + if (input) { + // Ainda é ok referenciar 'a' + let b = a + 1; + return b; + } + // Erro: 'b' não existe aqui + return b; +} +``` +Aqui, temos duas variáveis locais a e b. O escopo de a é limitado ao corpo de f, enquanto o escopo de b é limitado ao bloco if na qual está contida. Outra propriedade de variáveis com escopo de bloco é que elas não podem ser lidas ou escritas antes de serem declaradas. + +`const` é usado para declarar constantes, ou seja, variáveis cujo valor não pode ser alterado após a sua inicialização . `const` também respeita o escopo de bloco, tendo a mesma regra de `let`, mas não é possível reatribuí-las. + +**Exemplo** + +```typescript +const maxConnections: number = 100; +``` +Nesse exemplo, maxConnections é uma constante que armazena o número máximo de conexões permitidas, e seu valor não pode ser alterado após a inicialização. + +`var` é uma forma mais antiga de declarar variáveis em JavaScript, e ainda é suportada pelo TypeScript. No entanto, var tem escopo de função, o que significa que a variável está disponível em todo o contexto da função em que foi declarada, o que pode levar a comportamentos inesperados. + +**Exemplo** + +```typescript +var idade: number = 25; + ``` + +**Conclusão** + +Com TypeScript sendo uma extensão de JavaScript é recomendável utilizar `let` para variáveis que podem mudar de valor e `const` para constantes, reservando var apenas para casos específicos onde o comportamento de escopo de função seja realmente necessário. Se houver duas opções de declaração de variáveis, o ideal é utilizar `const` sempre que possível, uma vez que restringe modificações indesejadas, tornando o código mais seguro e previsível.",rw17212367412369c1494,rw1725557273503aeca0c,"# Tipos de variáveis ",William Suane | DevDojo,"[{""foreignRowId"":""rw1725557273503aeca0c"",""foreignRowDisplayName"":""Abordagem sobre o uso de tipos em TypeScript, destacando a inclusão de tipos numéricos, booleanos e strings (incluindo template strings). Também explora arrays, tuplas e enumerações, explicando suas funcionalidades e diferenças em relação ao JavaScript. A explicação inclui exemplos práticos de código e a importância do uso de let para definir variáveis com escopo limitado.""}]",https://www.youtube.com/watch?v=rCKvrhLRFLE,"[TypeScript: Documentation - Declaração de variáveis](https://www.typescriptlang.org/pt/docs/handbook/variable-declarations.html) ",,, +Condicionais,São fundamentais para implementar lógica de decisão no código adaptando o comportamento do programa conforme diferentes cenários e entradas.,TypeScript: Lógica de Programação,"**Condicionais em TypeScript** + + + +As condicionais são usadas para tomar decisões com base em diferentes condições. Elas funcionam de forma semelhante ao JavaScript. + +**if, else if e else** + + + +A estrutura `if` permite executar um bloco de código se uma condição for avaliada como verdadeira. No exemplo abaixo, o bloco do `if` só é executado caso a variável `idade` seja maior ou igual a 18. Caso contrário, executa o bloco do `else`.",rw17212367802520ba251,rw17271015159244bf9b2,# Estrutura Condicional,Filipe Morelli Developer,"[{""foreignRowId"":""rw17271015159244bf9b2"",""foreignRowDisplayName"":""Neste vídeo, você aprenderá a usar as estruturas condicionais.\n\nAs principais estruturas condicionais em programação são:\n\n1. **if**: Executa um bloco de código se a condição for verdadeira.\n2. **else**: Executa um bloco de código se a condição do `if` for falsa.\n3. **else if**: Verifica múltiplas condições, permitindo testar mais de uma condição antes de executar o bloco `else`.\n4. **switch**: Usado para executar diferentes blocos de código com base no valor de uma variável.\n\nEntenda como e quando utilizar cada uma delas para tomar decisões em seu código!\n""}]",https://www.youtube.com/watch?v=bbYbgiD1XyM,"[TypeScript: Estruturas de Condição](https://medium.com/@habbema/typescript-estruturas-de-condi%C3%A7%C3%A3o-70e9e521b167) +[TypeScript: Switch](https://www.tutorialsteacher.com/typescript/typescript-switch)","Guia com os passos necessários para realizar as atividades corretamente, Primeiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Segundo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Terceiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Quarto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Quinto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Sexto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Sétimo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido","rw1725638686995f335f2,rw1726148767193d37419,rw172614877687962c399,rw1726148778374f4a37c,rw1726149090018cb2662,rw17552773848501ad9ee,rw1755277654851e10ef1,rw1755277672141849448","Instruções importantes,Par ou ímpar,Dominó,Dando nome as pedras,Isenção de impostos,Montanha Russa Muito Assustadora,Compra com Desconto,Nome para exibição" +Benefícios da Refatoração,Refatoração melhora legibilidade reutilização reduz erros e facilita a manutenção do código.,TypeScript: Refatoração,"A refatoração em TypeScript traz diversos benefícios, tanto para a qualidade do código quanto para a eficiência do desenvolvimento. Aqui estão alguns dos principais: + +**Legibilidade:** Código limpo e organizado facilita a compreensão por outros desenvolvedores, além de melhorar o fluxo de leitura. +**Reutilização:** Ao modularizar o código, fica mais fácil reutilizar funções e componentes em diferentes partes do projeto. +**Redução de Erros:** Ao remover duplicações e melhorar a lógica, você diminui as chances de introduzir erros. +**Facilidade de Manutenção:** Um código bem organizado e claro facilita a compreensão e a correção de problemas durante o ciclo de vida do projeto. +**Desempenho:** Refatorar pode melhorar a eficiência do código, resultando em melhor performance da aplicação, especialmente em trechos críticos. +**Testabilidade:** Código mais limpo e modular é mais fácil de testar, tanto manualmente quanto por meio de testes automatizados, o que melhora a qualidade geral do software. +**Escalabilidade:** Um código bem estruturado e otimizado torna-se mais fácil de escalar à medida que o projeto cresce, facilitando a adição de novas funcionalidades. +**Redução de Dívida Técnica:** Refatorar regularmente evita o acúmulo de soluções improvisadas e ""gambiarras"", reduzindo a dívida técnica ao longo do tempo.",rw17267632624582fe2e7,rw1727961920967e41be3,# Refatoração - Dicionário do Programador,Código Fonte TV,"[{""foreignRowId"":""rw1727961920967e41be3"",""foreignRowDisplayName"":""Neste vídeo você aprenderá o que é refatoração, seus principais benefícios e como deixar o seu código mais limpo.""}]",https://www.youtube.com/watch?v=VOxnyVI2lOc&ab_channel=CódigoFonteTV,[Refatoração - Dicionário do Programador](https://www.youtube.com/watch?v=VOxnyVI2lOc),,, +Principais Técnicas de Refatoração em TypeScript,Técnicas de refatoração em TypeScript melhoram a clareza do código e tornam a manutenção mais fácil.,TypeScript: Refatoração,"As principais técnicas de refatoração em TypeScript ajudam a manter o código mais limpo, eficiente e de fácil manutenção. Aqui estão algumas frequentemente utilizadas: + +**1. Extrair Funções** + +Quando você percebe que um bloco de código está se repetindo ou que uma função está fazendo várias coisas ao mesmo tempo, considere extrair parte desse código em funções menores. Isso aumenta a clareza e a modularidade. + +Exemplo antes da refatoração: + +``` typescript +function processUser(user: any) { + console.log(user.name); + console.log(user.age); + + // Validação + if (!user.name || !user.age) { + throw new Error(""Invalid data""); + } + // Processamento + user.isActive = true; +} +``` +Após a refatoração: +```typescript +function validateUser(user: any) { + if (!user.name || !user.age) { + throw new Error(""Invalid data""); + } +} + +function activateUser(user: any) { + user.isActive = true; +} + +function processUser(user: any) { + console.log(user.name); + console.log(user.age); + validateUser(user); + activateUser(user); +} +``` +**2. Renomear Variáveis** + +Escolher nomes descritivos para variáveis, funções e classes ajuda a tornar o código mais autodescritivo, evitando comentários desnecessários. Se uma variável chamada a não faz sentido, renomeie-a para algo mais significativo. + +Exemplo: +``` typescript +let a = 0; // O que é ""a""? +``` +Após a refatoração: +```typescript +let totalUsers = 0; +``` +**3. Evitar Duplicação de Código** + +Se você identificar que o mesmo trecho de código está sendo usado em vários lugares, considere extrair esse código em uma função reutilizável. + +Exemplo antes da refatoração: + +``` typescript +let user1 = { name: ""Alice"", age: 25 }; +console.log(user1.name); +console.log(user1.age); + +let user2 = { name: ""Bob"", age: 30 }; +console.log(user2.name); +console.log(user2.age); +``` + +Após a refatoração: +``` typescript +function logUserInfo(user: { name: string, age: number }) { + console.log(user.name); + console.log(user.age); +} + +let user1 = { name: ""Alice"", age: 25 }; +let user2 = { name: ""Bob"", age: 30 }; + +logUserInfo(user1); +logUserInfo(user2); +``` + +**4. Utilizar Tipagem Apropriada** + +TypeScript permite que você defina tipos explícitos para seus dados, o que ajuda a garantir que o código seja mais seguro e previsível. Se você está lidando com objetos complexos, considere criar tipos ou interfaces que representem esses dados. + +Exemplo antes da refatoração: +``` typescript +function getUserData(user: any) { + return user.name + "" is "" + user.age + "" years old""; +} +``` +Após a refatoração: +``` typescript +interface User { + name: string; + age: number; +} + +function getUserData(user: User) { + return `${user.name} is ${user.age} years old`; +} +``` + +**5. Simplificar Condicionais** + +Condicionais longas podem se tornar difíceis de ler e manter. Sempre que possível, simplifique-as. + +Exemplo antes da refatoração: +``` typescript +if (user.age > 18) { + if (user.isActive) { + return true; + } else { + return false; + } +} else { + return false; +} +``` +Após a refatoração: +``` typescript +return user.age > 18 && user.isActive; +```",rw17267635193113866b5,rw172676310522712900a,"# Refatoração Funcional ",Otávio Lemos,"[{""foreignRowId"":""rw172676310522712900a"",""foreignRowDisplayName"":""Neste vídeo você aprenderá a fazer Refatoração Funcional em TypeScript.""}]",https://www.youtube.com/watch?v=Hef59LiR8-0,[Refatoração em TypeScript](https://www.youtube.com/watch?v=Hef59LiR8-0),Primeiro exercício da lista com objetivo de fixar os conceitos da refatoração em TypeScript,rw172795995480204cc77,Refatorando Arrays +Repetição,Estruturas de Repetição em TypeScript permitem executar blocos de código várias vezes de forma eficiente utilizando laços como `for` `while` e `do while` com o suporte de tipos estáticos para garantir segurança e consistência no código.,TypeScript: Lógica de Programação,"Estruturas de repetição em TypeScript são utilizadas para executar blocos de código de forma contínua, até que uma condição seja atendida. Os laços mais comuns incluem `for`, `while` e `do while`. Eles permitem iterar sobre dados e realizar operações repetidas de maneira eficiente. Com o suporte de tipos estáticos, TypeScript garante que essas operações sejam seguras e consistentes, reduzindo o risco de erros no código. + +Aqui estão os exercícios com um exemplo de cada estrutura de repetição: `for`, `while`, e `do while`: + +--- + +**1. Exibir números de 1 a 5 usando `for`** + +```typescript +for (let i = 1; i = 1); +``` + +--- + +**2. Somar números de 1 a 10 usando `while`** + +```typescript +let i = 1; +let sum = 0; + +while (i = 1); +``` + + + + +--- + +**3. Exibir os números de 10 a 1 usando `do while`** + +```typescript +let i = 10; + +do { + console.log(i); + i--; +} while (i >= 1); +//O loop `do while` começa com 10 e exibe os números até chegar em 1. +``` + +--- + +Esses exercícios exemplificam cada estrutura de repetição de maneira simples! + +",rw1726765151047cfa7ec,rw17271020082434a6bb8,# Estrutura de Repetição,Filipe Morelli Developer,"[{""foreignRowId"":""rw17271020082434a6bb8"",""foreignRowDisplayName"":""Neste vídeo, você aprenderá a usar as estruturas de repetição.\n\nAs principais estruturas de repetição em programação são:\n\n1. **for**: Utilizada quando o número de iterações é conhecido.\n2. **while**: Usada quando o número de iterações não é conhecido e depende de uma condição.\n3. **do...while**: Semelhante ao `while`, mas garante que o bloco de código seja executado pelo menos uma vez.\n\nExplore cada uma delas para entender suas aplicações!\n""}]",https://www.youtube.com/watch?v=LC1-rDSI004,"[Laço de Repetição For no TypeScript](https://imperioog.com/estruturas-de-repeticao-while-do-while-e-for-em-javascript) +[Laço de Repetição While no TypeScript](https://dev.to/acaverna/lacos-de-repeticao-em-javascript-50hj) +[Do-While em TypeScript](https://imperioog.com/estruturas-de-repeticao-while-do-while-e-for-em-javascript) +","Guia com os passos necessários para realizar as atividades corretamente, Primeiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Segundo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Terceiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Quarto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Quinto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido","rw172788824375369b7de,rw172788849370372c4a4,rw1727888616227ba1cbc,rw1727888759901a297ca,rw1727888842484d0b855,rw172788889829812e9e6","Instruções Importantes,Exibir números de 0 a N,Exibir números entre M e N,Mostrar o segundo maior valor digitado,Contar múltiplos de 2 e 3 e múltiplos de 2 e 5,Calcular média de alunos" +Funções,Funções em TypeScript permitem definir comportamentos reutilizáveis com tipagem estática garantindo código mais seguro e organizado.,TypeScript: Lógica de Programação,"As funções em TypeScript são um componente essencial na lógica de programação, permitindo que os desenvolvedores criem blocos de código reutilizáveis e organizados. Elas oferecem uma maneira estruturada de encapsular comportamentos e operações, o que facilita a manutenção e a clareza do código. + +Uma das principais vantagens de usar funções em TypeScript é a possibilidade de definir tipos para os parâmetros e o retorno. Isso significa que você pode especificar exatamente quais tipos de dados uma função deve aceitar e o que ela deve retornar. Essa tipagem ajuda a evitar erros em tempo de execução, já que o compilador pode identificar incompatibilidades antes mesmo de o código ser executado. + +Além disso, as funções em TypeScript podem ser anônimas ou expressões de função, permitindo uma abordagem mais flexível e concisa ao escrever código. As chamadas de funções podem ser feitas de maneira clara, o que torna o fluxo do programa mais intuitivo. + +Outro aspecto importante é a possibilidade de usar **parâmetros opcionais** e **valores padrão** nas funções. Isso permite que você escreva funções que se adaptem a diferentes situações, aumentando a sua versatilidade. Por exemplo, uma função pode aceitar um nome e, opcionalmente, uma idade, retornando uma mensagem personalizada de acordo com os parâmetros fornecidos. + +As funções também promovem a reutilização de código, permitindo que trechos de lógica sejam aplicados em diferentes partes de uma aplicação. Isso não apenas reduz a duplicação de código, mas também melhora a legibilidade, já que funções bem nomeadas podem descrever claramente suas intenções. + +Aqui estão cinco exercícios em TypeScript com **funções**: + +### 1. Função que soma dois números + +```typescript +function somar(a: number, b: number): number { + return a + b; +} + +const resultado = somar(5, 3); +console.log(resultado); // Saída: 8 +``` + +A função `somar` recebe dois parâmetros do tipo `number` e retorna a soma deles. + +### 2. Função que verifica se um número é par + +```typescript +function ehPar(n: number): boolean { + return n % 2 === 0; +} + +console.log(ehPar(4)); // Saída: true +console.log(ehPar(7)); // Saída: false +``` + +A função `ehPar` verifica se o número é divisível por 2, retornando `true` ou `false`. + +### 3. Função que imprime uma saudação + +```typescript +function saudar(nome: string): void { + console.log(`Olá, ${nome}!`); +} + +saudar(""Joãozinho""); // Saída: Olá, Joãozinho! +``` + +Aqui, a função `saudar` recebe um nome como parâmetro e imprime uma saudação personalizada. + +### 4. Função que retorna o maior número de um array + +```typescript +function maiorNumero(arr: number[]): number { + let maior = arr[0]; + for (let i = 1; i maior) { + maior = arr[i]; + } + } + return maior; +} + +const numeros = [3, 7, 1, 9, 5]; +console.log(maiorNumero(numeros)); // Saída: 9 +``` + +A função `maiorNumero` percorre um array e retorna o maior número encontrado. + +### 5. Função que calcula o fatorial de um número + +```typescript +function fatorial(n: number): number { + if (n === 0 || n === 1) { + return 1; + } + return n * fatorial(n - 1); +} + +console.log(fatorial(5)); // Saída: 120 +``` + +Neste exemplo, a função `fatorial` utiliza recursão para calcular o fatorial de um número. + +--- + +Foram utilizadas **5 funções** nos exercícios. Cada função aborda um conceito básico de lógica de programação e manipulação de dados.",rw1726770563183563cea,rw17271128247767b3c39,# Funções,Daniel Berg,"[{""foreignRowId"":""rw17271128247767b3c39"",""foreignRowDisplayName"":""Neste vídeo, você aprenderá a usar funções em TypeScript.\n\nFunções são blocos de código reutilizáveis que executam uma tarefa específica. ""}]",https://www.youtube.com/watch?v=iSFxyGsXMpI,"[Entendendo Funções no TypeScript: Guia Completo para Desenvolvedores](https://www.escoladnc.com.br/blog/entendendo-funcoes-no-typescript-guia-completo-para-desenvolvedores/) ",,, +Algoritmos,Algoritmos são sequências de instruções lógicas e finitas para resolver problemas ou realizar tarefas de forma eficiente e estruturada.,TypeScript: Lógica de Programação,"**Algoritmos em TypeScript** + +Neste card, vamos explorar o que são algoritmos e como podemos utilizá-los em TypeScript para resolver problemas de forma eficiente e organizada. Se você nunca teve contato com o assunto, não se preocupe! Vamos explicar tudo de forma simples. + +**O que são Algoritmos?** + +Algoritmos são sequências de instruções que descrevem como realizar uma tarefa específica. Eles são essenciais em programação porque nos ajudam a resolver problemas de forma estruturada. Pense em um algoritmo como uma receita de culinária: ela nos diz exatamente quais ingredientes precisamos e os passos a seguir para preparar um prato. + +**Exemplo de Algoritmo:** + +Imagine que você quer fazer um suco de laranja. Aqui está um algoritmo simples para isso: + +**1. Ingredientes**: Laranjas, água, açúcar. + +**2. Passos**: + - Lave as laranjas. + - Corte as laranjas ao meio. + - Esprema as laranjas para extrair o suco. + - Misture o suco com água e açúcar a gosto. + +**A Importância dos Algoritmos na Programação** + +Os algoritmos são fundamentais porque nos ajudam a: +- **Organizar o pensamento**: Ao quebrar um problema em etapas menores. +- **Otimizar o desempenho**: Algoritmos eficientes podem reduzir o tempo de execução de um programa. +- **Reutilizar código**: Podemos aplicar os mesmos algoritmos em diferentes partes de um programa. + +**Algoritmos em TypeScript** + +TypeScript é uma linguagem de programação que é uma superconjunto do JavaScript. Isso significa que você pode usar tudo que já existe no JavaScript, mas com a adição de tipos, o que ajuda a evitar erros. Vamos ver alguns exemplos de algoritmos em TypeScript. + +**1. Busca Linear** + +A busca linear é um algoritmo que procura por um elemento em uma lista, verificando cada item um por um. Aqui está como implementar isso em TypeScript: + +```typescript +function buscaLinear(array: number[], alvo: number): number { + for (let i = 0; i < array.length; i++) { + if (array[i] === alvo) { + return i; // Retorna o índice do elemento encontrado + } + } + return -1; // Retorna -1 se o elemento não for encontrado +} + +// Exemplo de uso: +const numeros = [10, 20, 30, 40, 50]; +const resultado = buscaLinear(numeros, 30); +console.log(resultado); // Saída: 2 +``` + +Os algoritmos são ferramentas poderosas que nos ajudam a resolver problemas de forma lógica e eficiente. Ao utilizar TypeScript, conseguimos criar algoritmos mais seguros e robustos, aproveitando os benefícios da tipagem estática. Ao aprender e aplicar diferentes algoritmos, você se torna um programador mais competente e preparado para enfrentar desafios na programação. + +",rw17267745321437cbec1,rw1727113785634333cc8,# O que é o tal do Algoritmo?,Diolinux,"[{""foreignRowId"":""rw1727113785634333cc8"",""foreignRowDisplayName"":""No vídeo são exploradas essas questões e desvendar como o entendimento e o domínio dos algoritmos podem fazer toda a diferença na sua jornada como pessoa programadora. Mergulhe nesse universo e entenda por que os algoritmos estão por trás de tantas inovações tecnológicas!""}]",https://www.youtube.com/watch?v=z1XTcKKRbKM,"[Estruturas de Dados e Algoritmos com TS](https://www.youtube.com/watch?v=6t_n0TSkunE) + +[Algoritmos de Busca - Linear e Binária](https://www.youtube.com/watch?v=KUUXv6rBCrY&t=180s) + +[Entendendo a Ordenação por Seleção](https://www.youtube.com/watch?v=uoHp_h0j8UQ) + +[Calculando a Média ](https://www.youtube.com/watch?v=57nDcP_akbA) +",,, +Operador Ternário,Operadores Ternários em TypeScript exploraremos a sintaxe e os benefícios desse operador que simplifica decisões condicionais em uma única linha de código.,TypeScript: Lógica de Programação,"Operadores Ternários em TypeScript, exploraremos a sintaxe e os benefícios desse operador, que simplifica decisões condicionais em uma única linha de código. Veremos como ele pode ser uma alternativa eficiente ao uso de `if-else`, tornando o código mais enxuto e legível. Abordaremos como aplicá-lo em situações práticas, como atribuição de valores com base em condições, retorno de funções e outras operações lógicas. O objetivo é mostrar como o uso adequado do operador ternário melhora a clareza e a eficiência do código em cenários do dia a dia. + +**Operador ternário** + +Permite a avaliação de uma condição e a escolha entre duas expressões com base nessa condição, tudo em uma única linha de código. Veja um exemplo: + +```typescript +let idade: number = 18; +let resultado = idade >= 18 ? ""Adulto"" : ""Menor de idade""; +console.log(resultado); +``` + +Neste exemplo, a variável resultado recebe o valor ""Adulto"" se idade for maior ou igual a 18; caso contrário, recebe o valor ""Menor de idade"". +",rw17267746000309152e6,rw1727181976096a054ca,"# Operador Ternário (O ""economizador"" de linhas de código)",Código Fonte TV,"[{""foreignRowId"":""rw1727181976096a054ca"",""foreignRowDisplayName"":""No vídeo de hoje, vamos explorar como utilizar o operador ternário de maneira eficaz em suas aplicações. Vamos ver exemplos práticos que mostram como ele pode substituir estruturas condicionais mais longas, ajudando a manter seu código limpo e direto.""}]",https://www.youtube.com/watch?v=YjEtiFi2k7g,"[MDN Web Docs - Operador Condicional (Ternário)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/Conditional_operator) + +",,, +Como personalizar o GitHub,Criando um portfólio com o GitHub.,Descubra o Git e GitHub,"**Como configurar seu perfil** + +Personalizar seu perfil no GitHub é crucial, pois cria uma boa impressão, estabelece sua identidade profissional, facilita conexões e colaborações, serve como um **portfólio digital**, aumenta sua **visibilidade** na comunidade e acelera seu aprendizado. + + +1. **Clique na sua foto** no canto superior direito e selecione ""Your profile"". +2. Clique em **""Edit profile""** para adicionar ou atualizar seu nome, bio (uma pequena descrição sobre você), localização e link para seu site, se tiver. +**Escolher uma Foto de Perfil** + +Escolha uma foto que represente você. Isso pode ser uma foto sua ou um avatar que você gosta. + +**Adicionar Repositórios em Destaque** + +1. Vá até seu perfil e clique em **""Customize your pins""**. +2. Selecione os repositórios que você quer destacar e clique em **""Save""**. Isso ajuda a mostrar seus projetos mais importantes. + +**Criar um README.md** + +Em um repositório, crie um arquivo chamado `README.md`. Nele, escreva sobre o projeto, como usar e como contribuir. Isso ajuda as pessoas a entenderem seu trabalho. + +**Explorar e Seguir Outros** + +Siga outras pessoas desenvolvedoras e projetos que você gosta. Isso pode ajudar você a aprender e a se conectar com a comunidade. +",rw17271835297323eec3b,rw172718871387068b90f,# Como personalizar o seu perfil no Github (Readme),Rafaella Ballerini,"[{""foreignRowId"":""rw172718871387068b90f"",""foreignRowDisplayName"":""O vídeo ensina como personalizar o perfil do GitHub, começando pela criação do repositório e do arquivo `README.md`. Ele mostra como adicionar estatísticas do GitHub, ícones de tecnologias, badges de redes sociais, um GIF personalizado e a cobrinha de commits. \n\n \n \nA personalização do perfil é essencial para pessoas desenvolvedoras, pois ajuda a destacar suas habilidades e projetos de forma visual e interativa. Este vídeo é ideal tanto para iniciantes quanto para desenvolvedoras experientes que desejam aprimorar sua presença no GitHub.\n""}]",https://www.youtube.com/watch?v=TsaLQAetPLU,"[How to Create an Impressive GitHub Profile](https://www.sitepoint.com/github-profile-readme/) +[Como personalizar o seu perfil no Github](https://www.youtube.com/watch?v=TsaLQAetPLU&t=7s) +",,, +Git,Entenda como funciona o controle de versionamento com Git.,Descubra o Git e GitHub,"**Git** é um sistema de controle de versões (**VCS**) que tem como propósito levar um registro de mudanças e coordenar o trabalho de várias pessoas em um repositório compartilhado. + +O **Git** disponibiliza ferramentas para um trabalho rápido e eficiente dentro de uma equipe. O controle de versões permite as pessoas desenvolvedoras descarregar uma cópia do código fonte a seus repositórios locais (PC), fazer mudanças e subir uma versão nova ao repositório compartilhado. + +Ele permite comparar mudanças realizadas e ver quem modificou o código, permitindo comparar e analisar mudanças com a possibilidade de revertê-las se alguma coisa der errado. Dessa maneira, todas as desenvolvedoras interessados no projeto têm acesso ao histórico de modificações realizadas e podem contribuir para melhorar o código do software, dando a liberdade para desenvolver projetos sem preocupações. + +Atualmente o **Git** é normalmente utilizado através de sistemas como **GitHub**, **GitLab** e **Azure DevOps**, que fornecem uma plataforma sob o sistema, facilitando seu uso em nosso dia-a-dia. +",rw1727183980819e0ac72,rw17279619210594231cf,# Aprenda Git e Github em 5 minutos,Mucharski,"[{""foreignRowId"":""rw17279619210594231cf"",""foreignRowDisplayName"":"" Assuntos abordados:\n\n- O que é Git?\n- O que é Github?\n- Como utilizar cada um?\n- Qual a diferença entre Git e Github?\n- Comece a mostrar seus códigos;\n- Principais comandos;\n- Básico de Git e Github;\n- Github é um multiverso;""}]",https://www.youtube.com/watch?v=-l4Aa8wef8s,"[Usar o Git](https://docs.github.com/pt/get-started/using-git) +[O Básico do Git](https://git-scm.com/book/pt-br/v2/Começando-O-Básico-do-Git) +",,, +GitHub,GitHub é uma ferramenta para armazenar e gerenciar projetos na nuvem a qual facilita a colaboração em código aberto e funcionando como portfólio digital essencial para desenvolvedores.,Descubra o Git e GitHub,"**O GitHub** é uma plataforma de desenvolvimento colaborativo que permite armazenar e gerenciar projetos na nuvem, utilizando o **Git**, um sistema de controle de versões. Essa ferramenta facilita o rastreamento de todas as alterações realizadas em um código, proporcionando uma visão clara da evolução dos projetos e permitindo que as pessoas desenvolvedoras acompanhem o progresso de forma organizada. + +Grande parte dos projetos no **GitHub** são de **código aberto**, permitindo que outras desenvolvedoras colaborem, sugiram melhorias ou corrijam erros. Esse ambiente colaborativo incentiva a troca de conhecimento e a contribuição coletiva, promovendo o desenvolvimento contínuo dos projetos por meio de discussões e propostas de soluções. + +**O GitHub** também atua como uma **rede social**, conectando pessoas desenvolvedoras ao redor do mundo. Além de baixar programas e aplicativos, os usuários podem contribuir diretamente com o aprimoramento de projetos. A plataforma facilita essa **colaboração**, tornando simples a participação em projetos de outras pessoas por meio da correção de bugs, sugestões de funcionalidades e outros tipos de melhorias. + +No mercado profissional, o **GitHub** é amplamente utilizado como **portfólio digital**. Durante processos seletivos, é comum que as empresas solicitem o link do perfil no **GitHub** para analisar os projetos desenvolvidos e o código produzido. Por isso, manter um perfil ativo e profissional, com nome de usuário adequado, é fundamental para demonstrar comprometimento, evolução e dedicação ao aprendizado contínuo.",rw1727184465499e3f709,rw172718612668122783c,# O que é GIT e GITHUB? - definição e conceitos importantes 1/2,Rafaella Ballerini,"[{""foreignRowId"":""rw172718612668122783c"",""foreignRowDisplayName"":""Esse vídeo explica a definição de Git e Github e os principais conceitos utilizados na ferramenta! É algo muito necessário na vida de uma pessoa desenvolvedora.""}]",https://www.youtube.com/watch?v=DqTITcMq68k,"[Fluxo do GitHub](https://docs.github.com/pt/get-started/using-github/github-flow) +[Git e GitHub - Instalação, Configuração e Primeiros Passos](https://balta.io/blog/git-github-primeiros-passos) +[O que é GitHub](https://ebaconline.com.br/blog/o-que-e-github) +",Nesta atividade você irá criar uma conta no GitHub para conseguir criar repositórios e contribuir em projetos,rw17279767069844c209b,Criando uma conta no GitHub +Como utilizar o GitHub e Git,As principais funcionalidades do GitHub e Git permitem colaborar e gerenciar projetos de desenvolvimento de software.,Descubra o Git e GitHub,"O conhecimento desses termos a seguir é **fundamental**, pois eles formam a base do trabalho colaborativo e do controle de versão. Familiarizar-se com esses conceitos não apenas facilitará sua navegação na plataforma, mas também aprimorará sua capacidade de se comunicar com outros desenvolvedores. Além disso, ao entender como cada um desses termos se relaciona com o processo de desenvolvimento, você estará mais bem preparada para participar ativamente de projetos e contribuir de forma significativa. A prática e a aplicação desses termos em situações reais vão solidificar seu aprendizado e aumentar sua confiança ao usar o GitHub. + +#### Fundamentos Git e Github + +**Git** é um sistema de controle de versão distribuído que permite a desenvolvedores acompanhar alterações no código fonte ao longo do tempo. É amplamente utilizado para o gerenciamento de projetos de software, permitindo a colaboração em equipe e o versionamento de arquivos. + +**GitHub** é uma plataforma de hospedagem para projetos que utilizam Git. Ele oferece funcionalidades adicionais, como controle de versões, colaboração, gerenciamento de projetos e integração com outras ferramentas. + +#### Clone e fork +- **Clone:** Copia um repositório remoto para o ambiente local, permitindo que o desenvolvedor trabalhe em uma cópia do projeto. +- **Fork:** Cria uma cópia de um repositório que pertence a outro usuário, permitindo que o desenvolvedor faça alterações sem afetar o repositório original. + +#### Branching no Git e Github +O **branching** permite criar ramificações independentes do código principal, facilitando o desenvolvimento de novas funcionalidades ou correções de bugs sem interferir no código estável. + +#### Commit e push +- **Commit:** Salva alterações no repositório local, registrando um ponto no tempo. É essencial incluir uma mensagem descritiva para documentar o que foi alterado. +- **Push:** Envia os commits locais para o repositório remoto, atualizando o projeto na plataforma como o GitHub. + +#### Colaboração no Github +Trabalhar em equipe no GitHub envolve o uso de branches e **pull requests**. Os pull requests permitem que as alterações sejam revisadas antes de serem integradas ao código principal, facilitando a colaboração e a revisão de código. + +#### Github actions +Uma funcionalidade que permite automação de fluxos de trabalho diretamente no GitHub, como testes automatizados e implantações, melhorando a eficiência no desenvolvimento. + +#### Mini glossário dos comandos Git mais utilizados + +- **`git init`**: Inicializa um novo repositório Git em um diretório. +- **`git clone [URL]`**: Clona um repositório remoto para o local. +- **`git status`**: Mostra o estado atual do repositório, incluindo alterações não rastreadas e arquivos prontos para commit. +- **`git add [arquivo]`**: Adiciona um arquivo ou alterações ao índice para o próximo commit. +- **`git commit -m ""mensagem""`**: Cria um commit com as alterações adicionadas, acompanhadas de uma mensagem descritiva. +- **`git push [remoto] [branch]`**: Envia commits locais para o repositório remoto especificado. +- **`git pull`**: Atualiza o repositório local com as últimas alterações do repositório remoto. +- **`git branch`**: Lista todas as branches do repositório e mostra a branch atual. +- **`git checkout [branch]`**: Troca para a branch especificada. +- **`git merge [branch]`**: Mescla as alterações de outra branch na branch atual. +- **`git log`**: Exibe um histórico dos commits feitos no repositório. +",rw172718446645846e05e,rw1727188618314cdca08,"# Comandos Git mais usados por desenvolvedores ",Matheus Battisti,"[{""foreignRowId"":""rw1727188618314cdca08"",""foreignRowDisplayName"":""Neste vídeo serão demonstrados os comandos do Git mais utilizados no dia a dia de uma desenvolvedora. \n \nSerão abordados comandos como:\n- git init;\n- git status;\n- git add;\n- git commit;\n- git log;\n- git branch;\n- git checkout;\n- git merge;\n""}]",https://www.youtube.com/watch?v=Xxcjjh7DkJk,"[Como usar o GitHub (Para Iniciantes)](https://tecnoblog.net/responde/como-usar-o-github-guia-para-iniciantes/) +","Clonar um repositório existente e fazer um fork para praticar a colaboração, Criando e Gerenciando um Repositório Git, Leia o glossário abaixo e procure entender cada um dos termos","rw1727976078726bee9ab,rw17279755805932f4be4,rw172796579826251b1dd","Clonando um Repositório e Fazendo um Fork,Primeiros Comandos Usando Git,Aprendendo o Glossário do GitHub" +Instalar Node.js,Como instalar o Node.js no Windows Linux ou macOS.,Preparando a Máquina,"Node.js é um ambiente de execução para JavaScript, permitindo executar código fora do navegador, no lado do servidor. Usaremos o Node.js para configurar o ambiente de desenvolvimento e iniciar a codificação. + +**Como instalar Node.js?** + +Recomenda-se a versão *LTS* (suporte de longo prazo) por ser mais estável. A versão *Current* pode conter bugs e é recomendada apenas se você precisar de funcionalidades mais recentes. + +**Instalação no Windows** + +Acesse o site do [Node.js](https://nodejs.org/en/download/prebuilt-installer) e baixe a versão LTS para Windows (32 bits ou 64 bits, conforme seu sistema). + +Após o download, execute o instalador e clique em next até a tela de seleção de funcionalidades. + +Mantenha as opções padrão, garantindo que **Node.js runtime**, **npm package manager** e **Add to PATH** estejam selecionadas. + +Na tela de ferramentas para módulos nativos, selecione para instalar, garantindo compatibilidade com pacotes npm que requerem compilação no Windows. Por último, conclua a instalação. + +**Instalação no Linux (Ubuntu)** + +Para instalar a versão *LTS* no Linux Ubuntu, devemos digitar no terminal os seguintes comandos: + +```bash +curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - +sudo apt-get install -y nodejs +``` + +Após isso o Node.js já vai estar instalado. + +**Instalação no macOS** + +A instalação no macOS é bastante similar com a instalação do Windows, pois também podemos usar um pacote de instalação. + +Acesse o site do [Node.js](https://nodejs.org/en/download/prebuilt-installer) e baixe a versão LTS para macOS. + +Após o download, execute o instalador e marque todas opções como""continuar"" até concluir a instalação. + +**Verificando a instalação** + +Abra o prompt de comando ou terminal e digite `node --version` para verificar a versão instalada. Teste o npm com `npm --version`, que também será instalado junto com o Node.js. +",rw1727186657231c1af77,rw17271894235882d9cda,# Instalar o Node.js no Windows,Gordin de Óculos | Informática e Tecnologia,"[{""foreignRowId"":""rw17271894235882d9cda"",""foreignRowDisplayName"":""Neste vídeo será ensinado como instalar Node.js no Windows. ""}]",https://www.youtube.com/watch?v=OmJOT50TW1g&ab_channel=Gordinde%C3%93culos-Inform%C3%A1ticaeTecnologia,"[Como instalar o Node.js no Windows, Linux e macOS](https://www.alura.com.br/artigos/como-instalar-node-js-windows-linux-macos?srsltid=AfmBOoqNpU1JYk3_ubuIvziE5zaBDsCTHqAy_rtQgDZjlRBGHQEbl55N) +[Como instalar Node.js no Linux de maneira simples e fácil](https://www.youtube.com/watch?v=LU1TYsyPim0&ab_channel=ClaudineyJunior) +[Instalando Node no macOS](https://www.youtube.com/watch?v=YLO1FBIxgW4&ab_channel=ThiagoPereira)",,, +Git bash,Entenda o que é e como usar git bash na sua maquina.,Preparando a Máquina,"Git Bash é uma interface de linha de comando (similar ao Prompt de Comando no Windows) que permite que você use comandos do Git no seu computador. Ele fornece uma maneira poderosa e flexível de interagir com o Git, mesmo se você não estiver usando um ambiente de desenvolvimento específico. + +Com o Git Bash, você pode navegar até o diretório do seu projeto e executar comandos como git clone, que faz uma cópia do projeto para o seu computador, ou git pull, que obtém as últimas alterações feitas por outras pessoas na equipe. + +[Link para o download](https://git-scm.com/downloads)",rw1727186962924b98d86,rw1727959966242d7705d,# Como Instalar Git Bash no Windows,Alessandro Ramos,"[{""foreignRowId"":""rw1727959966242d7705d"",""foreignRowDisplayName"":""Neste vídeo é ensinado um passo a passo de como fazer download do terminal Git Bash. No final da instalação, é exibido como pode testar. ""}]",https://www.youtube.com/watch?v=eZBjPi--uRM&ab_channel=AlessandroRamos,"[Git bash: Definições, Comandos e Introdução- Atlassian](https://www.atlassian.com/br/git/tutorials/git-bash#:~:text=O%20que%20é%20o%20Git,por%20meio%20de%20comandos%20gravados.)",,, +Array Simples,Arrays em TypeScript permitem armazenar e manipular dados de forma organizada com suporte para tipos estáticos propriedades anuláveis e métodos como propriedades de objetos.,TypeScript: Lógica de Programação,"Arrays Simples e Arrays de Objetos em TypeScript permitem armazenar múltiplos valores de um mesmo tipo ou objetos organizados. Em TypeScript, é possível definir o tipo dos elementos para garantir a consistência dos dados. Além disso, o uso de **propriedades anuláveis (nullable)** permite que alguns elementos do array possam ser `null` ou `undefined`, trazendo mais flexibilidade ao código. Métodos podem ser definidos como propriedades de objetos dentro dos arrays, permitindo funcionalidades adicionais. + + +Aqui estão alguns exercícios com **Arrays Simples** e **Arrays de Objetos**: + +### 1. Array Simples - Listando números pares + +```typescript +let numeros: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + +function listarPares(arr: number[]): number[] { + return arr.filter(num => num % 2 === 0); +} + +console.log(listarPares(numeros)); // Saída: [2, 4, 6, 8, 10] +``` + +Neste exemplo, o array `numeros` contém números de 1 a 10 e a função `listarPares` filtra e retorna apenas os números pares. + +### 2. Array Simples - Somando todos os valores + +```typescript +let numeros: number[] = [5, 10, 15, 20]; + +function somarArray(arr: number[]): number { + return arr.reduce((acumulador, valorAtual) => acumulador + valorAtual, 0); +} + +console.log(somarArray(numeros)); // Saída: 50 +``` + +Aqui, a função `somarArray` utiliza o método `reduce` para somar todos os valores no array. + +--- + +### 3. Array de Objetos - Listando nomes de membros + +```typescript +type Membro = { + nome: string; + idade: number; +}; + +let membros: Membro[] = [ + { nome: ""Ana"", idade: 25 }, + { nome: ""Carlos"", idade: 30 }, + { nome: ""Bruna"", idade: 22 } +]; + +function listarNomes(arr: Membro[]): string[] { + return arr.map(membro => membro.nome); +} + +console.log(listarNomes(membros)); // Saída: ['Ana', 'Carlos', 'Bruna'] +``` + +Neste exercício, o array `membros` contém objetos com `nome` e `idade`, e a função `listarNomes` retorna um array com os nomes. + +### 4. Array de Objetos - Filtrando por idade + +```typescript +type Membro = { + nome: string; + idade: number; +}; + +let membros: Membro[] = [ + { nome: ""Ana"", idade: 25 }, + { nome: ""Carlos"", idade: 30 }, + { nome: ""Bruna"", idade: 22 } +]; + +function membrosMaioresDe25(arr: Membro[]): Membro[] { + return arr.filter(membro => membro.idade > 25); +} + +console.log(membrosMaioresDe25(membros)); // Saída: [{ nome: 'Carlos', idade: 30 }] +``` + +A função `membrosMaioresDe25` retorna os membros cuja idade é maior que 25. + +--- + +### 5. Array de Objetos - Atualizando a idade de um membro + +```typescript +type Membro = { + nome: string; + idade: number; +}; + +let usuarios: Membro[] = [ + { nome: ""Ana"", idade: 25 }, + { nome: ""Carlos"", idade: 30 }, + { nome: ""Bruna"", idade: 22 } +]; + +function atualizarIdade(arr: Membro[], nome: string, novaIdade: number): Membro[] { + return arr.map(membro => { + if (membro.nome === nome) { + return { ...membro, idade: novaIdade }; + } + return membro; + }); +} + +console.log(atualizarIdade(membros, ""Ana"", 26)); +// Saída: [{ nome: 'Ana', idade: 26 }, { nome: 'Carlos', idade: 30 }, { nome: 'Bruna', idade: 22 }] +``` + +Aqui, a função `atualizarIdade` busca pelo nome no array de membros e atualiza a idade do membro correspondente. +",rw1727203515904ad3fa2,rw1727182071303ae95a8,# Arrays simples de objetos,CodeTotal,"[{""foreignRowId"":""rw1727182071303ae95a8"",""foreignRowDisplayName"":""Neste vídeo, você aprenderá conceitos básicos sobre a utilização de Arrays simples e Arrays de objetos no JavaScript utilizando TypeScript.\n\nSerão abordados alguns tópicos, a exemplo:\n\n- Como declarar e manipular Arrays simples;\n- Como trabalhar com Arrays de objetos;\n- O uso de propriedades anuláveis (nullable) para evitar erros em casos onde valores podem ser `null` ou `undefined`;\n- Métodos como propriedades, permitindo que funções sejam atribuídas diretamente aos objetos e acessadas como qualquer outra propriedade.\n\nEste conteúdo é essencial para quem deseja aprofundar o uso de Arrays e melhorar a segurança e a estruturação do código em TypeScript.\n""}]",https://www.youtube.com/watch?v=mY_bJ9R-0bI," [Curso TypeScript - Arrays e Tuplas](https://jornadadodev.com.br/cursos/front-end/typescript/arrays-e-tuplas) + [Array.prototype.map() - MDN](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/map) +[Array.prototype.filter() - MDN](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) ","Guia com os passos necessários para realizar as atividades corretamente, Primeiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Segundo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Terceiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Quarto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido","rw17278857951789628d4,rw1727886436829261856,rw1727886940271b774a5,rw1727887740711bbc6c1,rw1727887863868c37cc0","Instruções importantes, Vetor pares dobro e impares triplo,Intercalação vetores,Produtos e lucros,Pontuação do concurso" +Estrutura Básica,Informações que formam uma base sólida para entender o uso de HTML5 na criação de sites e aplicações web.,Introdução ao HTML e CSS,"**1. Estrutura** + +- <!DOCTYPE html>: Essa é uma declaração que indica que o documento está em HTML5, a versão mais recente. Essa tag ajuda o navegador a renderizar a página de forma mais eficiente, otimizando o carregamento e evitando erros de compatibilidade. + +- <html>: A tag que envolve toda a estrutura do HTML. É como o ""nível raiz"" da página, onde o navegador entende que tudo o que está dentro é parte do documento HTML. + +- <head>: É uma seção que contém informações importantes sobre a página. Aqui você inclui: + - <title>: Define o título que aparece na aba do navegador. + - Metadados: Com a tag <meta>, você define informações como a codificação de caracteres (UTF-8, por exemplo) e a descrição da página, essencial para SEO. + - Links para estilos e scripts: Aqui você coloca links para folhas de estilo (CSS) e scripts JavaScript que serão aplicados à página. + +- <body>: Onde o conteúdo visível é estruturado. Dentro do body, coloca os textos, imagens, vídeos e todos os elementos que o usuário verá. + +**2. Semântica** + +- <header>: Usado para o cabeçalho da página, que geralmente contém logotipos, menus principais e informações de contato. + +- <nav>: Esse é o espaço para a navegação do site. Aqui você coloca o menu de navegação com links para as diferentes páginas ou seções. + +- <main>: Designa a área principal do conteúdo, única em cada página. É ótimo para SEO, pois indica ao mecanismo de busca onde está o conteúdo mais importante. + +- <section> e <article>: São blocos de conteúdo. **section** é usado para dividir o conteúdo em seções, enquanto **article** representa uma unidade independente de conteúdo (como uma postagem de blog ou um artigo de notícias). + +- <aside>: Para conteúdo complementar. Costuma ser usado para colocar informações extras, como uma barra lateral com links relacionados ou anúncios. + +- <footer>: A área final da página, geralmente com créditos, links para redes sociais, ou uma cópia de direitos autorais.",rw17301368164191bfc4c,rw173038056692115906a,# Aprenda HTML em apenas 5 MINUTOS (2023),Tiger Codes,"[{""foreignRowId"":""rw173038056692115906a"",""foreignRowDisplayName"":""Neste vídeo, aprenda as partes mais importantes do HTML em apenas 5 minutos! Explorando desde a estrutura básica de um documento HTML até aos elementos principais, como head, body, e links hipertextuais. ""}]",https://www.youtube.com/watch?v=5Hn58p-hYC0&t=126s&ab_channel=TigerCodes,[Estrutura HTML pronta: estrutura básica de uma página HTML!](https://blog.betrybe.com/html/input-html/estrutura-html-pronta-estrutura-basica-de-uma-pagina-html/),Este exercício ensina a criar a estrutura básica de uma página HTML5,rw1730385185255d8d1fc,Criando minha primeira página +Estilos.css,Aprenda sobre os diferentes estilos do CSS e aprenda a aplicá-los de forma estratégica para criar designs versáteis e eficientes.,Introdução ao HTML e CSS,"**Tipos de Estilos no CSS** + +CSS (*Cascading Style Sheets*) é a linguagem usada para definir o visual e o layout de uma página web. Você aprenderá o que precisa para começar a estilizar seu site, como ajustar o tamanho e a cor do texto, organizar os elementos na tela, criar designs atraentes com fundos, bordas e efeitos. Prepare-se para transformar a aparência das suas páginas e torná-las mais envolventes. + +O CSS permite aplicar estilos de diferentes maneiras dependendo das necessidades do projeto e da estrutura do código. Cada tipo de estilo tem suas características e usos recomendados, que veremos a seguir. + +***1. CSS Inline*** + +O CSS `Inline` é aplicado diretamente no elemento HTML usando o atributo `style`. Esse estilo afeta apenas o elemento específico onde ele foi inserido, sendo útil para pequenas personalizações rápidas e quando há uma necessidade de estilo muito particular que não se repetirá. + +**Exemplo:** + +<`style=""color: blue; font-size: 18px;""`> `Este é um exemplo de Inline CSS.`</p> + +Neste exemplo, o parágrafo terá cor azul e tamanho de fonte 18px. Esses estilos se aplicam apenas a esse parágrafo e não afetarão outros na página. + +*Vantagens:* 👍 + +- Fácil de aplicar para alterações rápidas e únicas. +- Ideal para situações onde o estilo é usado apenas uma vez ou precisa ser modificado sem impactar outros elementos. + +*Desvantagens:* 👎 + +- Difícil de manter e alterar em projetos grandes, já que o estilo está preso ao elemento específico. +- Não reutilizável: se você precisar do mesmo estilo em vários elementos, terá que copiá-lo várias vezes, aumentando o código e dificultando a manutenção. + +**Recomendações:** 💡 + +- Utilize Inline CSS para testes ou pequenos ajustes. +- `Evite` em projetos grandes ou complexos, pois pode comprometer a organização e manutenção do código. + +***2. CSS Interno*** + +O CSS `Interno` é colocado dentro da tag <` style `> no cabeçalho (<`head`>) de um documento HTML. Ele é aplicado a todos os elementos que correspondem aos seletores dentro do mesmo documento HTML, permitindo maior controle do que o Inline e facilitando a aplicação de estilos reutilizáveis. + +**Exemplo:** +```html + + + + + body { + font-family: Arial, sans-serif; + } + p { + color: green; + font-size: 20px; + } + + + + Este é um exemplo de Internal CSS. + Outro parágrafo com o mesmo estilo. + + +``` + + +*Vantagens:* 👍 + +- Fácil visualização e manutenção em projetos pequenos; como o css está no próprio documento HTML, ele é fácil de visualizar e editar sem a necessidade de abrir outro arquivo. +- Estilos específicos para uma única página +- Carregamento simples em uma página: para páginas isoladas ou de propósito único, o CSS interno elimina a necessidade de carregar um arquivo externo, simplificando o processo. + +*Desvantagens:* 👎 + +- Reutilização Limitada: os estilos definidos no css interno só se aplicam àquela página, o que impede a reutilização em outras páginas do site, levando a estilos duplicados. +- Dificuldade de manutenção em projetos grandes +- Impacto no desempenho, pois não pode ser armazenado em cache pelo navegador, o que pode aumentar o tempo de carregamento se a página for recarregada com frequência + +O CSS Interno é uma opção útil em *situações específicas*, mas para projetos maiores e com múltiplas páginas, o uso de CSS Externo costuma ser mais vantajoso para a manutenção e o desempenho. Iremos conhecê-lo mais a seguir. + +***3.CSS Externo*** + +O CSS `Externo` é uma forma eficiente de organizar e aplicar estilos em uma página web, utilizando um arquivo separado com extensão`.css`. Esse arquivo centraliza todos os estilos da aplicação ou site e pode ser vinculado a várias páginas HTML, garantindo consistência visual e facilitando a manutenção e a atualização de estilos em todo o projeto. O CSS externo é referenciado dentro do HTML com a tag <`link`>, o que permite reutilizar os estilos sem precisar redefini-los em cada página. Para implementá-lo, crie dois arquivos: um para o HTML e outro para o CSS. + + +**Exemplo:** + +- No arquivo HTML (*index.html*): + +```html + + + + + + + Este é um exemplo de External CSS. + + +``` + +- No arquivo CSS (*.styles.css*): + +```css +body { + font-family: 'Helvetica', sans-serif; + background-color: #f4f4f4; +} + +p { + color: navy; + font-size: 16px; +} +``` + +Neste exemplo, o arquivo `styles.css` define o estilo do corpo da página e de elementos específicos, como o parágrafo (<`p`>), e é vinculado ao HTML através da tag <`link`>. Com essa abordagem, alterações no CSS são automaticamente aplicadas a todas as páginas que referenciam esse arquivo, simplificando o processo de atualização dos estilos no projeto. + + +*Vantagens:* 👍 + +- Organização e Legibilidade: Manter os estilos em um arquivo dedicado torna o HTML mais limpo e facilita a manutenção dos códigos. +- Reutilização: O mesmo arquivo CSS pode ser aplicado a várias páginas, economizando tempo e evitando redundância. +- Carregamento e Desempenho: Navegadores conseguem armazenar em cache o arquivo CSS, carregando-o mais rapidamente em visitas subsequentes.",rw17301368262879f399f,rw1730391187322b4f666,# Estilos CSS inline,Gustavo Guanabara | Curso em vídeo,"[{""foreignRowId"":""rw1730391187322b4f666"",""foreignRowDisplayName"":""O vídeo apresenta uma introdução ao CSS, incluindo uma parte prática com exercícios e um enfoque específico no estilo CSS \""inline\"". Também são discutidas as principais vantagens e desvantagens desse estilo para ajudar você a decidir quando utilizá-lo em seus projetos. Ao final da página, você encontrará referências com conteúdos complementares para aprofundar o aprendizado neste tópico.""}]",https://www.youtube.com/watch?v=byqhpuVpvEI,"[Estilos CSS internos](https://www.youtube.com/watch?v=fzyab4P2pn8) + +[Estilos CSS externos](https://www.youtube.com/watch?v=-i1JVMspDJQ&t=17s)",Aprenda a aplicar diferentes tipos de CSS para transformar e organizar o visual da sua página de forma prática e fácil,rw17309852666022c4de8,Aplicando diferentes tipos de CSS +Reset.css,Mude o estilo dos elementos HTML em todos os navegadores com o Reset.css uma técnica que elimina conflitos visuais e melhora a consistência do layout.,Introdução ao HTML e CSS,"O **Reset.css** é um conjunto de estilos CSS criado para uniformizar a aparência padrão dos elementos HTML em todos os navegadores. Como cada navegador aplica seus próprios estilos por padrão, isso pode causar variações indesejadas no layout de um projeto web. O Reset.CSS elimina essas inconsistências ao remover esses estilos padrão, garantindo que todos os navegadores comecem a renderizar os elementos de forma mais consistente. + +**Criando um Reset.css** + +Cada pessoa pode criar seu próprio reset com base nas necessidades específicas de seu projeto ou optar por utilizar resets prontos que já estão disponíveis na comunidade. + +Aqui está um exemplo simples de um reset que alguém poderia criar: + +```css +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: Arial, sans-serif; +} + +h1, h2, h3 { + font-weight: normal; +} +``` + +O `*` é um seletor universal, ou seja, vai aplicar para todos os elementos do CSS. + +Existem diversos Reset.CSS prontos disponíveis que podem ser utilizados em seus projetos. Um exemplo bastante utilizado é o Reset CSS de Eric Meyer, no [CSS Tools: Reset CSS](https://meyerweb.com/eric/tools/css/reset/), ele explica como funciona a técnica e como desenvolveu o seu código reset. + +```css +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +``` + +Ao decidir entre criar seu próprio reset ou usar um pronto, como o de Eric Meyer, considere as necessidades do seu projeto e o nível de personalização que deseja. Um reset bem implementado pode ajudar a garantir uma experiência de usuário consistente e agradável em sua aplicação web.",rw1730136932113000d16,rw173038438692167ef21,# O que é Reset CSS?,Marco Bruno,"[{""foreignRowId"":""rw173038438692167ef21"",""foreignRowDisplayName"":""Neste vídeo, é apresentada uma comparação da criação de um site em HTML e CSS em diferentes navegadores. Ressaltando a importância do Reset CSS, que garante uma base consistente. Além disso, é demonstrado como usar o Reset CSS e o que cada tag está fazendo.""}]",https://www.youtube.com/watch?v=23G_3ODk5mY&ab_channel=MarcoBruno,"[Reset CSS: O que é, exemplos, como criar e usar](https://www.alura.com.br/artigos/o-que-e-reset-css?srsltid=AfmBOopg4yGOxEEISBHBafrC5m01V0Lwf0T-7YCZM0Is2kj07jUpvThD) +[Exemplos de Reset CSS ](https://www.youtube.com/watch?v=cXUrg9Q9RUE&ab_channel=MarcoBruno)",Entenda o Reset.css e como ele mantém a consistência visual em diferentes navegadores,rw17309876100642d9bba,Uniformizando Estilos em Navegadores com Reset.css +Posicionamento,Entenda mais sobre os diferentes tipos de posicionamento no CSS e como aplicá-los para construir layouts dinâmicos e precisos.,Introdução ao HTML e CSS,"No CSS, o posicionamento é uma técnica que permite controlar o layout dos elementos na página. Com diferentes tipos de posicionamento, é possível definir a localização precisa de cada elemento em relação aos outros ou à própria página. As propriedades de posicionamento ajudam a *organizar o conteúdo, criar camadas e melhorar a responsividade. + +**1. Posicionamento Estático (position: static)** + +Por padrão, todos os elementos são posicionados de forma estática. Isso significa que eles seguem o fluxo natural da página, sem ajuste manual. + +```css +p { + position: static; +} +``` + +- **Não permite ajustes manuais** com propriedades como top, right, bottom, ou left. +- **Uso comum**: Para manter a ordem padrão dos elementos na página. + + +**2. Posicionamento Relativo (position: relative)** + +O posicionamento relativo permite ajustar a posição de um elemento em relação à sua posição original, sem alterar o fluxo do layout. + +```css +p { + position: relative; + top: 10px; + left: 5px; +} +``` + +- **Move o elemento** conforme valores de top, right, bottom, e left, mas ainda reserva o espaço original no layout. +- **Uso comum**: Para deslocar um elemento levemente, mantendo seu espaço na página. + +**3. Posicionamento Absoluto (position: absolute)** + +O posicionamento absoluto retira o elemento do fluxo padrão e o posiciona em relação ao primeiro elemento pai com posição diferente de static. + +```css +div { + position: absolute; + top: 20px; + right: 15px; +} +``` + +- **O elemento é posicionado** em relação ao contêiner posicionado mais próximo (não static), ou ao se não houver contêiner pai posicionado. +- **Uso comum**: Para sobrepor ou ajustar elementos em layouts mais complexos. + + +**4. Posicionamento Fixo (position: fixed)** + +O posicionamento fixo mantém o elemento fixado em relação à janela de visualização, garantindo que ele permaneça visível no mesmo local, independentemente da rolagem da página. + +```css +header { + position: fixed; + top: 0; + width: 100%; +} +``` + +- **Útil para criar elementos** que sempre ficam visíveis, como menus e barras de navegação. +- **Uso comum**: Para cabeçalhos, rodapés ou botões que devem permanecer fixos na tela. + + +**5. Posicionamento Sticky (position: sticky)** + +O posicionamento sticky é uma mistura de relativo e fixo. Ele permite que o elemento fique fixo quando atinge uma posição específica na rolagem da página. + +```css +nav { + position: sticky; + top: 0; +} +``` + +- **O elemento se comporta como** relative até alcançar o valor de top, momento em que se torna fixo na página. +- **Uso comum**: Para menus de navegação ou títulos que ficam fixos enquanto o conteúdo é rolado.",rw1730136949117191333,rw1730480417487fc918c,# CSS: Aprenda de verdade css position,Daniel Tapias | Serliv,"[{""foreignRowId"":""rw1730480417487fc918c"",""foreignRowDisplayName"":""Aprenda, de uma vez por todas, como dominar o posicionamento no CSS! Neste vídeo, você vai entender a fundo as diferenças entre position: **static, absolute, relative, fixed e stick**, para aplicar esses conceitos com confiança e precisão nos seus projetos.""}]",https://www.youtube.com/watch?v=XCvSUC0zECI,,Explore o poder do CSS para posicionar elementos e criar layouts organizados e modernos em sua página!,rw17309888120468a6f1a,Aplicando posicionamento no CSS +Hierarquia no CSS,Descubra como funciona a hierarquia e especificidade do CSS e aprenda a aplicar estilos de forma eficiente.,Introdução ao HTML e CSS,"Ao criar estilos no CSS, muitas vezes surge a dúvida: qual a diferença entre usar um ID ou uma Classe? Essa escolha pode impactar não só a aparência, mas também a flexibilidade e a manutenção do seu código. Entender essa diferença é essencial para dominar a hierarquia e a especificidade do CSS, garantindo que seus estilos sejam aplicados de forma eficiente e consistente. + +**1. Hierarquia e Especificidade no CSS** + + +O CSS possui uma hierarquia e uma especificidade de estilos, ou seja, dependendo do que você usar para criar seu estilo, ele pode acabar sobrescrevendo algum outro estilo! Isso acontece porque o CSS possui uma contagem de pontos para saber qual o estilo é mais importante. + +- **Estilo In-line**: O estilo mais específico é o in-line, onde você define o estilo diretamente no HTML, o que sobrescreve todos os outros estilos aplicados ao elemento. + +Exemplo: +```html + + Este texto será exibido em vermelho e negrito devido ao estilo in-line. + +``` + +- **Seletores: ID, Classes e Tags**: Agora, vamos falar dos seletores ID, Classes e Tags: + +**ID** é o seletor mais específico entre os três, pois deve ser único em cada página HTML. Por isso, não é recomendado para estilização, já que não pode ser reutilizado em vários lugares. + +Exemplo: + ```css + #footer { + background-color: #424242; + } + ``` + +**Classes** são menos específicas que IDs, mas são amplamente utilizadas, pois podem ser repetidas quantas vezes forem necessárias na página, permitindo o reaproveitamento de código. + +Exemplo: + ```css + .card { + border-radius: 5px; + } + ``` + +**Tags HTML**: são a forma mais genérica de aplicar estilos, afetando todos os elementos de um tipo específico. + +Exemplo: + ```css + p { + font-size: 16px; + } + ``` + +- **Pseudo-classes e Pseudo-elementos** + +**Pseudo-classes** como `:hover`, `:active`, `:focus`, etc., têm a mesma especificidade que classes (10 pontos). + ```css + a:hover { + color: red; + } + ``` + +**Pseudo-elementos** como `::before` e `::after` seguem a mesma regra de especificidade que tags HTML (1 ponto). + ```css + p::before { + content: 'Prefixo: '; + } + ``` + +- **Ordem de Declaração**: Se dois seletores tiverem a mesma especificidade, a última regra declarada no CSS será aplicada. + +Por exemplo: +```css +p { + color: red; +} + +p { + color: blue; +} +``` +Neste caso, a cor ***azul*** será aplicada. + +- **Uso do important**: O `!important` é uma exceção à hierarquia de especificidade. Ele sobrescreve qualquer outro estilo, independentemente da sua especificidade: +```css +.classe { + color: #ff0000 !important; +} +``` +O `!important` deve ser usado com moderação, pois pode tornar o código CSS difícil de manter e depurar. + +**2. Exemplo de Especificidade** + +Vamos ver um exemplo para entender melhor: + +```css +#paragrafo p { + color: red; +} + +.paragrafo p { + color: blue; +} +``` + +Para descobrir qual estilo será aplicado, vamos contar de acordo com a regra de especificidade: + +- Estilo 1: Temos um ID e uma tag HTML, então o valor desse CSS é: 100 (ID) + 1 (Tag) = **101**. +- Estilo 2: Temos uma classe e uma tag HTML, então o valor desse CSS é: 10 (Classe) + 1 (Tag) = **11**. + +Resultado: O primeiro CSS tem um “peso” maior, portanto, a cor **vermelha** será aplicada. + + + +**3. Tabela de Pontuação de Especificidade** + +``` +| Elemento | Valor | +|------------------------------------|-------| +| Estilo In-line | 1000 | +| ID | 100 | +| Classes, pseudo-classes e atributos| 10 | +| HTML Tags | 1 | +```",rw1730137012921a48842,rw1730469206916700276,# Como Funciona A Hierarquia No CSS,Nicholas Arths,"[{""foreignRowId"":""rw1730469206916700276"",""foreignRowDisplayName"":""Este vídeo aborda em detalhes como funciona a hierarquia entre as diferentes maneiras de declarar propriedades em CSS.""}]",https://www.youtube.com/watch?v=ioO3Y81oMbQ&ab_channel=N%C3%ADcolasArths.,"[Seletores CSS](https://developer.mozilla.org/pt-BR/docs/Web/CSS/CSS_selectors) +[Como Funciona a Hierarquia Do CSS](https://backefront.com.br/como-funciona-hierarquia-css/)",Explore como a hierarquia de seletores no CSS afeta a aplicação de estilos e aprenda a usá-los de forma eficaz,rw1730990599513cf847b,Compreendendo a Especificidade no CSS +Fontes,Explore como estilizar fontes no CSS com propriedades básicas e avançadas para melhorar a legibilidade e o design.,Introdução ao HTML e CSS,"O CSS permite controlar a aparência das fontes em uma página da web, ajustando o estilo, tamanho, peso e outras propriedades para melhorar a legibilidade e a estética do texto. Vamos explorar algumas propriedades básicas e avançadas para manipular fontes no CSS. + +**Propriedades para fontes** + +**1. Font-Family** + + +A propriedade `font-family` é usada para definir a fonte de um texto. Você pode usar fontes genéricas, como 'serif', 'sans-serif', ou fontes personalizadas, especificando uma lista de fontes de reserva. + +Exemplo: + +```css +p { + font-family: 'Arial', 'Helvetica', sans-serif; +} +``` + +Neste exemplo, se a fonte 'Arial' não estiver disponível, o navegador tentará usar 'Helvetica'. Se nenhuma das duas estiver disponível, será usada uma fonte padrão 'sans-serif'. + +**2. Font-Size** + + +A propriedade `font-size` controla o tamanho da fonte e pode ser definida em diferentes unidades, como pixels (px), em, rem, ou percentuais (%). + +Exemplo: + +```css +h1 { + font-size: 24px; /* Tamanho fixo */ +} + +p { + font-size: 1.5em; /* Relativo ao tamanho do elemento pai */ +} + +body { + font-size: 100%; /* Relativo ao tamanho padrão do navegador */ +} +``` + +Usar unidades relativas (`em`, `rem`, `%`) ajuda a criar designs responsivos, pois o tamanho da fonte se ajusta de acordo com a resolução ou configuração do usuário. + +**3. Font-Weight** + +A propriedade `font-weight` é usada para definir a espessura da fonte. Pode ser definida por palavras-chave (normal, bold, etc.) ou valores numéricos (100 a 900). + +Exemplo: + +```css +strong { + font-weight: bold; /* Negrito padrão */ +} + +h2 { + font-weight: 600; /* Espessura intermediária */ +} + +p { + font-weight: 300; /* Fonte mais leve */ +} +``` + +**4. Font-Style** + +A propriedade `font-style` é usada para aplicar estilos como itálico ou oblíquo ao texto. + +Exemplo: + +```css +em { + font-style: italic; +} + +.citation { + font-style: oblique; +} +``` + +**5. Font-Variant** + +A propriedade `font-variant` é usada para controlar variações de fonte, como o uso de maiúsculas pequenas (small-caps). + +Exemplo: + +```css +small { + font-variant: small-caps; +} +``` + +**6. Line-Height** + +A propriedade `line-height` ajusta a altura da linha do texto, influenciando o espaçamento vertical entre linhas. + +Exemplo: + +```css +p { + line-height: 1.5; +} +``` + +**7. Font-Importação com @font-face** + +O CSS permite importar fontes externas usando a regra `@font-face`. Isso é útil para usar fontes personalizadas em uma página. + +Exemplo: + +```css +@font-face { + font-family: 'CustomFont'; + src: url('CustomFont.woff2') format('woff2'); +} + +body { + font-family: 'CustomFont', sans-serif; +} +``` + +Neste exemplo, a fonte 'CustomFont' é importada de um arquivo `.woff2` e usada no corpo do documento. + +**8. Google Fonts** + +Outra forma popular de importar fontes é usando o Google Fonts. Basta adicionar o link da fonte no HTML e aplicá-la no CSS. + +HTML: +```html + +``` + +CSS: + +```css +body { + font-family: 'Roboto', sans-serif; +} +``` + +**Dicas de Acessibilidade** + +- Tamanho de fonte mínimo: Para melhorar a legibilidade, mantenha um tamanho de fonte mínimo de 16px para texto de parágrafo. +- Altura de linha: Use uma line-height de pelo menos 1.5 para facilitar a leitura. +- Contraste de cor: Certifique-se de que a cor da fonte tenha contraste suficiente com o fundo para atender às diretrizes de acessibilidade.",rw17301370383075596dd,rw17304726962139b6587,# Como adicionar fontes personalizadas no site? (Tutorial de HTML e CSS),Inteliogia,"[{""foreignRowId"":""rw17304726962139b6587"",""foreignRowDisplayName"":""Aprenda a adicionar fontes personalizadas ao seu site usando apenas HTML e CSS! Neste vídeo, você verá como usar fontes genéricas, fontes do Google Fonts e fontes offline.""}]",https://www.youtube.com/watch?v=V1uN8beSc04&ab_channel=Inteliogia-Dev%27sInsights,[Estilizando Fontes com CSS](https://www.devmedia.com.br/estilizando-fontes-com-css/24226),Personalize sua página aplicando estilos de fontes e explore o poder do CSS para criar uma tipografia única e envolvente!,rw17309914063027a4e65,Personalizando Fontes na Página +Seletores CSS,Transforme suas páginas com seletores CSS estilizando elementos HTML com precisão e eficiência para um design único.,Introdução ao HTML e CSS," +Os seletores CSS são fundamentais para estilizar páginas web, pois permitem selecionar e aplicar estilos a elementos HTML específicos. Eles facilitam o controle e a customização do design, permitindo a definição de cores, tamanhos, layouts e muito mais. + +**1. Seletores Básicos** + +- **Seletores de Elemento**: Alcançam todos os elementos HTML de um tipo específico, como `h1`, `p`, `div`, etc. + ```css + p { + color: blue; + } + ``` + +- **Seletores de Classe**: Começam com um ponto (`.`) e aplicam estilos a elementos que possuem a classe especificada. + ```css + .minha-classe { + font-size: 18px; + } + ``` + +- **Seletores de ID**: Usam o símbolo `#` e estilizam apenas um elemento com o ID especificado. + ```css + #meu-id { + background-color: yellow; + } + ``` + +**2. Seletores Combinadores** + +- **Selecionador Descendente (``)**: Alcança apenas os elementos filhos diretos de um contêiner. + ```css + div > p { + color: purple; + } + ``` + +- **Selecionador de Irmão Imediato (`+`)**: Estiliza o primeiro elemento que segue imediatamente outro. + ```css + h1 + p { + margin-top: 0; + } + ``` + +- **Selecionador de Irmão Geral (`~`)**: Alcança todos os elementos irmãos após um determinado elemento. + ```css + h1 ~ p { + color: gray; + } + ``` + +**3. Seletores de Atributo** + +Permitem selecionar elementos com base em atributos ou valores de atributos específicos. + +- **Existência de Atributo**: + ```css + [type] { + border: 1px solid black; + } + ``` + +- **Igualdade de Atributo**: + ```css + [type=""text""] { + color: blue; + } + ``` + +- **Prefixo de Atributo (`^=`)**: Alcança elementos cujo atributo começa com um valor específico. + ```css + [class^=""btn-""] { + padding: 10px; + } + ``` + +- **Sufixo de Atributo (`$=`)**: Seleciona elementos cujo atributo termina com um valor específico. + ```css + [class$=""-active""] { + font-weight: bold; + } + ``` + +**4. Seletores Pseudo-Classes** + +Estes permitem aplicar estilos com base no estado dos elementos, como hover, foco, ou posição em relação a outros elementos. + +- **:hover**: Estiliza o elemento quando o usuário passa o mouse sobre ele. + ```css + a:hover { + text-decoration: underline; + } + ``` + +- **:first-child**: Aplica estilos ao primeiro elemento filho. + ```css + p:first-child { + font-size: 20px; + } + ``` + +- **:nth-child()**: Aplica estilos a elementos em posições específicas (índice). + ```css + li:nth-child(odd) { + background-color: #f0f0f0; + } + ``` + +**5. Seletores Pseudo-Elementos** + +Criam e estilizam partes específicas de um elemento sem a necessidade de um novo elemento HTML. + +- **::before** e **::after**: Adicionam conteúdo antes ou depois de um elemento. + ```css + p::before { + content: ""Nota: ""; + font-weight: bold; + } + ``` + +- **::first-line**: Altera a primeira linha do texto dentro de um elemento. + ```css + p::first-line { + color: red; + } + ``` + +**6. Seletores de Grupo** + +Os seletores de grupo combinam múltiplos seletores, facilitando a aplicação de estilos a vários elementos ao mesmo tempo. +```css +h1, h2, h3 { + font-family: Arial, sans-serif; +} +``` + +Com esses seletores, é possível criar uma estrutura de CSS organizada e eficaz para estilizar elementos de forma granular ou abrangente. O uso estratégico dos seletores melhora a legibilidade e a manutenção do código, proporcionando flexibilidade para diversos dispositivos e navegadores. +",rw1730137044079bf6288,rw17304704919002a1f75,# CSS: Seletores e Especificidade,Cod3r Cursos,"[{""foreignRowId"":""rw17304704919002a1f75"",""foreignRowDisplayName"":""CSS: Entenda Seletores e Especificidade para aprimorar o controle sobre o estilo dos elementos na sua página.""}]",https://www.youtube.com/watch?v=dPL23aVRIlc&ab_channel=Cod3rCursos,"[CSS: Guia Prático de Seletores](https://blog.rocketseat.com.br/css-guia-pratico-de-seletores/) +[CSS: seletores avançados que facilitam o desenvolvimento de aplicações web](https://www.alura.com.br/artigos/css-seletores-avancados-aplicacoes-web)",Aprenda a aplicar estilos específicos aos elementos da página usando diferentes seletores CSS e experimente sua funcionalidade,rw1731003577211cc4820,Explorando Seletores CSS para Estilos Personalizados +Design responsivo,Descubra como o design responsivo transforma layouts para qualquer dispositivo e como unidades viewport ajustam elementos perfeitamente à tela.,Introdução ao HTML e CSS,"Viewport e Design Responsivo são conceitos fundamentais para garantir que um site seja visualizado de maneira apropriada em diferentes dispositivos, como desktops, tablets e smartphones. + +**1. Viewport** + +É a área visível de uma página web dentro de uma tela. O tamanho do viewport varia de acordo com o dispositivo, sendo menor em telas de smartphones e maior em monitores de computador. Para criar uma experiência de navegação ideal, o HTML permite definir o comportamento do viewport usando a tag ``, como no exemplo: + +```html + +``` + +Nesta configuração, `width=device-width` ajusta a largura da página para o tamanho do dispositivo, enquanto `initial-scale=1.0` define o nível de zoom inicial, garantindo que o conteúdo não fique ampliado ou reduzido. A definição correta do viewport é crucial para o Design Responsivo. + +**2. Design Responsivo** + +É uma abordagem de desenvolvimento web que visa adaptar o layout de um site às diferentes resoluções e tamanhos de tela. Ele usa técnicas como layouts flexíveis, media queries e imagens adaptáveis para ajustar o conteúdo e melhorar a experiência do usuário. + +Para implementar o design responsivo, as **Media Queries** do CSS são uma das ferramentas mais usadas. Elas permitem definir estilos específicos para diferentes larguras de tela. Por exemplo: + +```css +/* Estilos para telas menores, como smartphones */ +@media (max-width: 600px) { + body { + font-size: 14px; + } +} + +/* Estilos para tablets */ +@media (min-width: 601px) and (max-width: 1024px) { + body { + font-size: 16px; + } +} +``` + +Com essas queries, é possível ajustar elementos como o tamanho da fonte, a largura dos contêineres e a visibilidade de certos conteúdos. Além disso, o uso de unidades flexíveis, como porcentagens e `em`, em vez de pixels fixos, também ajuda a criar um layout fluido. + +**3. Imagens adaptáveis** + +Outro aspecto importante do design responsivo é o uso de imagens adaptáveis, que carregam tamanhos de imagem diferentes de acordo com o dispositivo, melhorando o desempenho e a velocidade de carregamento. Utilizando a tag ``, o navegador decide qual imagem carregar com base nas características da tela do usuário: + +```html + + + + + +``` + +Há mais alguns aspectos importantes sobre viewport e design responsivo que podem enriquecer o conteúdo: + +**4. Unidades Flexíveis e Fluídas** + +Além das unidades `px`, `em`, e `%`, é comum em design responsivo o uso de unidades como `rem` e `vw`/`vh`: + +- **rem**: É uma unidade relativa ao tamanho da fonte raiz do documento (normalmente definido no `html`), o que permite ajustes de escala em toda a página. +- **vw (viewport width) e vh (viewport height)**: São unidades relativas à largura e altura do viewport, respectivamente. `100vw` equivale à largura total do viewport e `100vh` à altura total. Essas unidades facilitam o ajuste de elementos conforme o tamanho da tela. + +Exemplo: + +```css +.container { + width: 80vw; /* 80% da largura do viewport */ + height: 50vh; /* 50% da altura do viewport */ +} +``` + +**5. Tipografia Responsiva** + +A tipografia responsiva melhora a legibilidade em diferentes dispositivos. Pode-se utilizar valores `em`, `rem`, `vw`, ou mesmo `clamp()`: + +```css +h1 { + font-size: clamp(1.5rem, 2.5vw, 3rem); /* escala a tipografia entre os limites */ +} +``` + +A função `clamp()` define um valor mínimo, intermediário (adaptável) e máximo para o tamanho da fonte. + +**6. Teste de Responsividade** + +O teste de responsividade é essencial para garantir a usabilidade e o visual em diferentes dispositivos. Ferramentas como o modo responsivo do DevTools no navegador, o **Screenfly** e o **BrowserStack** permitem visualizar como o layout se comporta em vários tamanhos de tela. + +**7. Performance e Carregamento Condicional** + +Em design responsivo, o carregamento condicional melhora a performance ao evitar o carregamento de recursos desnecessários. Além das imagens adaptáveis, pode-se carregar scripts e folhas de estilo específicos para dispositivos móveis: + +```html + +``` + +Essa prática ajuda a otimizar o site, melhorando o tempo de carregamento em dispositivos de menor capacidade. + +**8. Acessibilidade Responsiva** + +Design responsivo também deve considerar a **acessibilidade**. Isso inclui o uso de contrastes adequados, botões grandes o suficiente para toque, navegação intuitiva e textos com tamanho ajustável. Garantir que o site seja acessível tanto em dispositivos móveis quanto em desktops beneficia todos os usuários.",rw173013705844645778d,rw173047014175556eaeb,# Como deixar o Layout Responsivo no seu site,Alura,"[{""foreignRowId"":""rw173047014175556eaeb"",""foreignRowDisplayName"":""Aprenda responsividade na prática com este tutorial sobre como transformar seu site num layout responsivo através do uso de ferramentas de desenvolvedor do seu navegador, o visual studio code e códigos CSS: media screen, container, propriedades CSS e mais.""}]",https://www.youtube.com/watch?v=kyFiT4ofMwk&t=526s&ab_channel=Alura,"[Design Responsivo](https://developer.mozilla.org/pt-BR/docs/Learn/CSS/CSS_layout/Responsive_Design) +[Design responsivo para a web](https://www.freecodecamp.org/portuguese/news/design-responsivo-para-a-web-como-adaptar-um-site-a-celulares-e-tablets/)",Aprenda a adaptar sua página para qualquer dispositivo criando um design responsivo e intuitivo,rw1731004790634193480,Aplicando Design Responsivo na Página +Box model e Box sizing,Entenda como o Box Model organiza o espaço dos elementos e como o Box Sizing facilita o controle de larguras e alturas no layout.,Introdução ao HTML e CSS,"**1. Box Model** + +O Box Model define como elementos HTML são representados e espaçados na página. Cada elemento é considerado uma ""caixa"", com quatro áreas principais: + +- **Content**: É a área onde o conteúdo, como texto ou imagens, é exibido. A largura e a altura do elemento determinam o tamanho dessa área. +- **Padding**: Espaçamento interno entre o conteúdo e a borda. Ele amplia a área de clique ou visual do elemento, sem aumentar sua dimensão total. +- **Border**: É a linha ao redor do padding. A espessura, estilo e cor podem ser definidos para criar contornos visuais. +- **Margin**: Espaçamento externo ao redor da borda. Não afeta a área de clique ou visual do elemento, mas define o espaço entre elementos. + +Exemplo de estilo para box model: + +```css +.element { + width: 200px; + height: 100px; + padding: 10px; + border: 2px solid black; + margin: 20px; +} +``` + +**2. Box Sizing** + +O `box-sizing` é uma propriedade CSS que controla como o Box Model é calculado. Ela define se o padding e a borda são incluídos ou não na largura e altura total do elemento. + +- **Content-box**: Este é o valor padrão. Apenas o conteúdo é considerado na largura e altura definidas; o padding e a borda são adicionados externamente, aumentando a dimensão final do elemento. +- **Border-box**: Inclui o padding e a borda dentro da largura e altura definidas. Esse valor é útil para manter o tamanho total consistente, independentemente da adição de padding ou bordas. + +Exemplo de uso do box-sizing: + +```css +.element { + box-sizing: border-box; +} +``` + +Definir `box-sizing: border-box` é uma prática comum para facilitar o controle do layout, especialmente em designs responsivos. + +**3. Box Model em Layouts Responsivos** + +Quando se trabalha com layouts responsivos, é importante lembrar que valores de **margin** e **padding** afetam o espaçamento entre elementos em diferentes tamanhos de tela. Isso significa que o uso de unidades fluidas, como `%`, `vw`, ou até `rem`, pode ajudar a adaptar o espaçamento sem comprometer o alinhamento do layout em tamanhos de tela variados. + +**4. Reset Global de Box Sizing** + +Uma prática comum para garantir consistência em todos os elementos é aplicar um reset global de `box-sizing`. Definindo `box-sizing: border-box` para todos os elementos, inclusive pseudo-elementos, evita-se o problema de aumento inesperado do tamanho do elemento: + +```css +*, +*::before, +*::after { + box-sizing: border-box; +} +``` + +Dessa forma, o padding e a borda são sempre incluídos na largura e altura especificadas, facilitando o controle do layout. + +**5. Border-Box em Componentes Reutilizáveis** + +Ao criar componentes reutilizáveis, como cartões ou botões, o uso de `box-sizing: border-box` ajuda a garantir que o componente mantenha suas proporções e espaçamentos corretamente, mesmo quando novos estilos ou ajustes de padding são aplicados. +",rw17301371000848a4ab0,rw17304698234373039ff,# Um Dev Júnior tem que Saber Isso de CSS Box Model,DPW,"[{""foreignRowId"":""rw17304698234373039ff"",""foreignRowDisplayName"":""O Box Model é um conceito fundamental em CSS que todo desenvolvedor front-end e designer precisa dominar, pois ele influencia diretamente na construção de interfaces eficientes e bem estruturadas.""}]",https://www.youtube.com/watch?v=YNqrNqpq6-E&ab_channel=dpw,,Experimente ajustar padding border e margin para ver o impacto no tamanho e no layout de uma caixa,rw17310686110054613c9,Entendendo Box Model e Box Sizing com Desafio Visual +Flexbox e Grid,Descubra como Flexbox e Grid revolucionam layouts CSS com estruturas modernas responsivas e perfeitamente organizadas.,Introdução ao HTML e CSS," +O **Flexbox** tem como meta ser um modo mais eficiente para criar layouts, alinhar e distribuir espaços entre itens em um container, mesmo quando as dimensões destes itens são desconhecidas e/ou dinâmicas (daí o termo ""flex""). Vamos aprender os fundamentos do CSS Flexbox para alinhamento e posicionamento, e como utilizar suas funcionalidades corretamente. + +**O que é o Flexbox?** +Por muito tempo, as únicas ferramentas disponíveis para criar layouts em CSS e posicionar elementos com boa compatibilidade entre browsers eram float e position. Porém, essas ferramentas possuem algumas limitações muito frustrantes, especialmente no que diz respeito à responsividade. Algumas tarefas que consideramos básicas em um layout, como centralização vertical de um elemento-filho com relação a um elemento-pai ou fazer com que elementos-filhos ocupem a mesma quantidade de espaço, ou colunas terem o mesmo tamanho independente da quantidade de conteúdo interno, eram impossíveis ou muito difíceis de serem manejadas com floats ou position, ao menos de forma prática e flexível. + +**Principais Propriedades do Flexbox** + +**1. Container Flexível:** +Para iniciar o uso do Flexbox, adicione `display: flex` ao contêiner pai. + +Exemplo: +```css +.container { + display: flex; +} +``` + +**2. Direção dos Itens (flex-direction):** + Define a direção em que os itens são organizados no contêiner. + +- **`flex-direction: row`**: Organiza os itens em linha (padrão). +- **`flex-direction: column`**: Organiza os itens em coluna. +- **`flex-direction: row-reverse`**: Inverte a direção da linha. +- **`flex-direction: column-reverse`**: Inverte a direção da coluna. + +Exemplo: +```css +.container { + display: flex; + flex-direction: column; /* Tente trocar para row, row-reverse ou column-reverse */ +} +``` + +```html + + Item 1 + Item 2 + Item 3 + +``` + +**3. Alinhamento no Eixo Principal (justify-content):** +Controla como os itens são distribuídos ao longo do eixo principal (horizontal, se `flex-direction: row`). + +- **`justify-content: flex-start`**: Alinha os itens ao início. +- **`justify-content: flex-end`**: Alinha os itens ao final. +- **`justify-content: center`**: Centraliza os itens. +- **`justify-content: space-between`**: Distribui o espaço igualmente entre os itens. +- **`justify-content: space-around`**: Adiciona espaço ao redor de cada item. + +Exemplo: +```css +.container { + display: flex; + justify-content: space-between; /* Tente trocar para flex-start, flex-end, center ou space-around */ +} +``` +```html + + Item 1 + Item 2 + Item 3 + +``` + +**4. Alinhamento no Eixo Cruzado (align-items)**: Define como os itens são alinhados ao longo do eixo cruzado (vertical, se `flex-direction: row`). + +- **`align-items: stretch`**: Estica os itens para preencher o contêiner (padrão). +- **`align-items: flex-start`**: Alinha os itens ao topo. +- **`align-items: flex-end`**: Alinha os itens ao fundo. +- **`align-items: center`**: Centraliza os itens verticalmente. +- **`align-items: baseline`**: Alinha os itens à linha de base do texto. + + Exemplo: +```css +.container { + display: flex; + align-items: center; /* Tente trocar para flex-start, flex-end, stretch ou baseline */ + height: 200px; /* Altura do contêiner para visualizar o alinhamento */ +} +``` +```html + + Item 1 + Item 2 + Item 3 + + +``` + +Essas são apenas algumas das propriedades principais do Flexbox. Existem muitas outras que também ajudam a criar layouts ainda mais flexíveis e responsivos. Recomendo a leitura da documentação: [Conceitos básicos de flexbox](https://developer.mozilla.org/pt-BR/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox). + +**CSS Grid** é um sistema de layout bidimensional de grid (literalmente ""grades"") para CSS, onde podemos trabalhar com linhas e colunas juntas, o que significa que ele abre muitas possibilidades diferentes para construir sistemas de design mais complexos e organizados. O diferencial desse método de criação de layouts reside na possibilidade de se dividir uma página em grandes regiões e de se definir o relacionamento em termos de medidas, posicionamento e camadas entre os diferentes componentes da marcação HTML. + +**Principais Propriedades do Grid** + +**1. ```display: grid```**: +Define o elemento como um contêiner de grid, ativando o Grid Layout. +É a propriedade base para iniciar o uso do CSS Grid. + +Exemplo: +```typescript +.container { + display: grid; +} +``` +**2. ```grid-template-columns``` e ```grid-template-rows```**: Define o número e o tamanho das colunas e linhas do grid. Pode usar valores como px, %, fr (fração do espaço), auto, etc. +- grid-template-columns: define o layout das colunas. +- grid-template-rows: define o layout das linhas. + + +Exemplo: +```typescript +.container { + grid-template-columns: 1fr 2fr 1fr; /* 3 colunas */ + grid-template-rows: 100px auto; /* 2 linhas */ +} +``` + +**3. ```gap```, ```row-gap``` e ```column-gap```**: Define o espaçamento entre as linhas e colunas do grid. + +- gap: define o espaço uniforme entre todas as linhas e colunas. +- row-gap e column-gap: definem os espaçamentos separadamente. + +Exemplo: + +```typescript +.container { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 100px 100px; + gap: 10px; /* Espaçamento uniforme de 10px */ + row-gap: 20px; /* Espaçamento de 20px entre linhas */ + column-gap: 5px; /* Espaçamento de 5px entre colunas */ +} +``` + +**4. ```grid-column``` e ```grid-row```**: Controlam o posicionamento de um item específico no grid, definindo em quais linhas/colunas ele começa e termina. +```grid-column: start / end``` e ```grid-row: start / end``` são usadas para itens individuais no grid. + +```typescript +.item { + grid-column: 1 / 3; /* Ocupa da coluna 1 à 3 */ + grid-row: 2 / 4; /* Ocupa da linha 2 à 4 */ +} +``` + +**5. ```grid-template-areas```**: Permite criar áreas nomeadas no grid, facilitando o posicionamento intuitivo dos itens. Define o layout de forma declarativa, usando nomes de áreas. + +Exemplo: + +```typescript +.container { + grid-template-areas: + ""header header"" + ""sidebar main"" + ""footer footer""; +} + +.header { + grid-area: header; +} + +.sidebar { + grid-area: sidebar; +} + +.main { + grid-area: main; +} + +.footer { + grid-area: footer; +} +``` + +**Diferenças entre Flexbox e Grid** +- Enquanto o Flexbox é excelente para criar layouts unidimensionais, organizando elementos em uma única linha ou coluna, o CSS Grid oferece uma abordagem bidimensional, permitindo a estruturação simultânea de linhas e colunas. +- Cada um possui seu papel essencial no design moderno: o Flexbox brilha em situações em que é preciso alinhar e distribuir itens de forma simples e rápida, como em menus, barras de navegação ou componentes menores. Já o CSS Grid se destaca ao construir layouts mais complexos, como painéis de controle, grades de galeria ou a estrutura completa de uma página. +- Ambos trabalham juntos para criar designs responsivos e detalhados, tornando o desenvolvimento de interfaces mais eficiente e organizado, com maior controle sobre o posicionamento e a distribuição dos elementos na página.",rw1730137140936bdf782,rw1730468775715f5a925,# CSS Grid Layout e Flexbox - Quando Utilizar,Origamid,"[{""foreignRowId"":""rw1730468775715f5a925"",""foreignRowDisplayName"":""Aprenda a organizar e alinhar elementos na página de forma prática e eficiente, explorando o poder do CSS Grid Layout e do Flexbox para criar layouts responsivos e visualmente equilibrados.""}]",https://www.youtube.com/watch?v=x-4z_u8LcGc&t=1339s&ab_channel=Origamid,"[Flex vs Grid: Escolhendo o layout certo](https://codeparrot.ai/blogs/flex-vs-grid) +[Flexbox CSS: Guia Completo, Elementos e Exemplos](https://www.alura.com.br/artigos/css-guia-do-flexbox) +[CSS Grid Layout](https://developer.mozilla.org/pt-BR/docs/Web/CSS/CSS_grid_layout) +[Conceitos básicos de Grid Layout](https://developer.mozilla.org/pt-BR/docs/Web/CSS/CSS_grid_layout/Basic_concepts_of_grid_layout)",Explore Flexbox e Grid para criar layouts dinâmicos e responsivos que valorizam seu conteúdo,rw1731069503143b838b6,Aplicando Flexbox e Grid no Layout do Projeto +Fundamentos Next.js,O Next.js é um framework para criar aplicações web rápidas e escaláveis com React oferecendo renderização server-side e páginas estáticas que melhoram desempenho e SEO.,Next.js,"**Fundamentos do Next.js** explora como criar aplicações modernas e otimizadas com React, aproveitando recursos avançados como a renderização do lado do servidor (SSR) e a geração estática de páginas (SSG). Com um sistema de rotas simplificado, o Next.js facilita a navegação entre páginas e o uso de API routes, integrando dados facilmente. + +**Renderização Server-Side (SSR) e Geração Estática (SSG)** + +Esses recursos do Next.js ajudam a controlar o que o usuário vê e quando, melhorando a experiência e o desempenho: + +- **SSR**: Renderiza páginas no servidor, enviando-as prontas ao cliente. Ideal para conteúdo dinâmico e páginas que mudam com frequência. +- **SSG**: Gera páginas estaticamente durante a build, criando sites rápidos e seguros, especialmente para conteúdo que muda raramente. + +```typescript +// Exemplo de getServerSideProps para SSR +export async function getServerSideProps() { + const data = await fetchData(); + return { props: { data } }; +} + +// Exemplo de getStaticProps para SSG +export async function getStaticProps() { + const data = await fetchData(); + return { props: { data } }; +} +``` + +**Rotas Automáticas** + +As rotas são criadas automaticamente a partir dos arquivos na pasta `pages`, tornando a navegação prática e organizada. + +```typescript +// pages/about.tsx +export default function About() { + return Sobre nós; +} +``` + +**API Routes** + +Com API routes, Next.js permite criar endpoints diretamente na aplicação, facilitando a criação de APIs internas. + +```typescript +// pages/api/user.ts +export default function handler(req, res) { + res.status(200).json({ name: 'John Doe' }); +} +``` + +**Conclusão** + +Com seus recursos para SSR, SSG, roteamento e APIs internas, Next.js torna o desenvolvimento de aplicações web modernas mais eficiente, melhorando a experiência do usuário e a performance da aplicação.",rw173022821547674e4af,rw1730309558200da1b04,# Criando aplicações usando React e Next jS com Typescript - Aula 01 - Curso de React Next,CFBCursos,"[{""foreignRowId"":""rw1730309558200da1b04"",""foreignRowDisplayName"":""Neste vídeo, aprenderemos a criar uma aplicação web usando React e Next.js com TypeScript. Vamos explorar como configurar o ambiente de desenvolvimento e entender as vantagens de unir essas ferramentas, incluindo a criação de interfaces interativas e a utilização de renderização server-side para otimizar o desempenho e SEO. Além disso, abordaremos conceitos fundamentais do React, como componentização, Virtual DOM e estado, e veremos como o Next.js adiciona funcionalidades avançadas para melhorar a experiência do desenvolvedor e do usuário.""}]",https://www.youtube.com/watch?v=k9IG_tPonwo,[Next.js Documentation](https://nextjs.org/docs),Como configurar um projeto Next.js,rw173228144037772ee84,Iniciando aplicação em Next.js +Internet: Conceitos e fundamentos,Entenda o que é Node.js como ele revolucionou o desenvolvimento web ao permitir a execução de JavaScript no lado do servidor.,Node.js,"Caso você ainda não tenha instalado o Node.js, acesse o tópico de [Instalar Node.js](https://aceleradora-agil.com.br/nivelamento/rw17169041087123b2d76-Preparando%20a%20M%C3%A1quina/rw1727186657231c1af77-Instalar%20Node.js) e siga as instruções para preparar sua máquina antes de continuar. + +--- + +Os principais conceitos relacionados ao Node.js incluem: + +**Single-threaded e Assíncrono**: Node.js utiliza um modelo single-threaded com operações de I/O não bloqueantes, permitindo a execução de múltiplas operações simultaneamente sem prejudicar o desempenho. + +**Event-driven**: Esse ambiente é orientado a eventos, o que significa que ele responde a eventos (como cliques, chamadas de rede ou operações de leitura e escrita) de forma assíncrona, executando as operações assim que os recursos ficam disponíveis. + +**NPM (Node Package Manager)**: O NPM é o gerenciador de pacotes do Node.js e possibilita a instalação de bibliotecas e dependências para otimizar o desenvolvimento. Com ele, é possível acessar milhares de módulos prontos e personalizáveis para diferentes aplicações. + +**Ecossistema Flexível**: A arquitetura do Node.js permite que ele seja utilizado em várias soluções, desde APIs e microserviços até servidores completos e aplicações em tempo real. + +Esses conceitos tornam o Node.js ideal para aplicações que exigem respostas rápidas, como APIs, microserviços, e serviços de streaming em tempo real. +",rw1730305190028e89fd1,rw173030856205779a18c,# Curso de Node.JS - O que é Node.JS #01,Victor Lima - Ciência da Computação,"[{""foreignRowId"":""rw173030856205779a18c"",""foreignRowDisplayName"":""Nesta aula, você aprenderá que o Node.js é uma plataforma que executa código JavaScript no lado do servidor, ou seja, fora dos navegadores. Node.js não é uma linguagem de programação, biblioteca ou framework, mas sim uma plataforma para interpretar JavaScript.""}]",https://www.youtube.com/watch?v=LLqq6FemMNQ&list=PLJ_KhUnlXUPtbtLwaxxUxHqvcNQndmI4B&index=2,"[Node.JS: definição, características, vantagens e usos possíveis](https://www.alura.com.br/artigos/node-js-definicao-caracteristicas-vantagens-usos?utm_term=&utm_campaign=%5BSearch%5D+%5BPerformance%5D+-+Dynamic+Search+Ads+-+Artigos+e+Conteúdos&utm_source=adwords&utm_medium=ppc&hsa_acc=7964138385&hsa_cam=11384329873&hsa_grp=164240702375&hsa_ad=703853654617&hsa_src=g&hsa_tgt=aud-409949667484:dsa-2276348409543&hsa_kw=&hsa_mt=&hsa_net=adwords&hsa_ver=3&gad_source=1&gclid=Cj0KCQjwsoe5BhDiARIsAOXVoUv-94OfqoGx_iTc-sykU0JajBoD4MOkvUzbmhy_G3zwmymacZiKl-saAn_kEALw_wcB)",,, +Protocolo HTTP,No Node.js o módulo HTTP facilita a criação de servidores que manipulam requisições e respostas tornando possível desenvolver aplicações web dinâmicas e escaláveis.,Node.js,"Abaixo está um guia para iniciar o uso de HTTP com Node.js e o módulo HTTP. + +Para começar, certifique-se de que o Node.js está instalado em seu sistema. Siga as instruções de instalação no site oficial do [Node.js](https://nodejs.org/pt/download/package-manager). + +--- + +**1. Criando um servidor HTTP simples** + +1. Crie um novo arquivo: + + No diretório desejado, crie um arquivo chamado `server.js`. + +2. Importe o módulo HTTP: + + Importe o módulo HTTP usando a nova sintaxe: + + ```javascript + import http from 'http'; + ``` + +3. Crie o servidor: + + Use o método `createServer` para criar um servidor HTTP: + + ```javascript + const server = http.createServer((req, res) => { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('Hello, World!\n'); + }); + ``` + +4. Escolha a porta para o servidor escutar: + + Defina a porta e inicie o servidor com o código abaixo: + + ```javascript + const PORT = 3000; + server.listen(PORT, () => { + console.log(`Servidor rodando em http://localhost:${PORT}/`); + }); + ``` + +5. Execute o servidor: + + No terminal, navegue até o diretório onde salvou o server.js e execute: + + ```bash + node server.js + ``` + + Você verá uma mensagem informando que o servidor está em execução. + +**2. Testando o servidor** + +Abra seu navegador ou uma ferramenta como o Postman e acesse a seguinte URL: + +```bash +http://localhost:3000/ +``` + +Você deve ver a mensagem ""Hello, World!"". + +**3. Manipulando rotas** + +Você pode expandir seu servidor para responder a diferentes rotas. Veja como: + +```javascript +const server = http.createServer((req, res) => { + if (req.url === '/') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('Página Inicial\n'); + } else if (req.url === '/sobre') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('Página Sobre\n'); + } else { + res.statusCode = 404; + res.setHeader('Content-Type', 'text/plain'); + res.end('404 Não Encontrado\n'); + } +}); +``` + +**4. Conclusão** + +Neste guia, você aprendeu a criar um servidor HTTP simples usando Node.js com a sintaxe de import, além de manipular rotas. Esse é o primeiro passo para desenvolver aplicações web mais complexas com Node.js.",rw1730305252555aab804,rw173030548457336f6be,# Curso de Node.js - Protocolo HTTP #05,Victor Lima - Ciência da Computação,"[{""foreignRowId"":""rw173030548457336f6be"",""foreignRowDisplayName"":""Nesta aula, você aprenderá o que é o protocolo HTTP, que é o mecanismo que possibilita toda a comunicação entre servidor e cliente na WEB. Além disso, vai descobrir como construir seu próprio servidor HTTP usando Node.js e JavaScript, iniciando seus primeiros passos no desenvolvimento web com Node.js.""}]",https://www.youtube.com/watch?v=QnTCre0HHv8&list=PLJ_KhUnlXUPtbtLwaxxUxHqvcNQndmI4B&index=6,"[Node.js HTTP Module](https://www.w3schools.com/nodejs/nodejs_http.asp) +",,, +REST API,REST API é uma interface que permite interações entre sistemas usando HTTP.,Node.js,"API é uma sigla para Application Programming Interface. O termo REST API ou RESTFul API é usado para um aplicativo da web que expõe seus recursos a outros aplicativos pela Internet. A arquitetura REST se tornou o padrão de fato para a construção de APIs. + +--- + +**O que é arquitetura REST?** + +* REST significa Representational State Transfer. +* É uma arquitetura baseada em recursos, onde tudo que o servidor REST hospeda é um recurso. +* REST recomenda certas restrições arquitetônicas: Interface uniforme, Cliente-servidor, Capacidade de armazenamento em cache, Sistema em camadas, Código sob demanda. + +**Métodos HTTP** +* Os métodos HTTP mais comuns na arquitetura REST são: + * **POST**: Cria um novo recurso. + * **GET**: Recupera um recurso existente. + * **PUT**: Atualiza um recurso existente. + * **DELETE**: Exclui um recurso. + +**Serviços Web RESTful** + +Serviços web baseados na Arquitetura REST são conhecidos como serviços web RESTful. Esses serviços usam métodos HTTP para implementar a arquitetura REST.",rw17303052691599a76af,rw17303922044867583d9,# API com Node.JS - Passo 0 - Introdução (O que é uma REST API?),Maransatto,"[{""foreignRowId"":""rw17303922044867583d9"",""foreignRowDisplayName"":""Este vídeo apresenta uma introdução sobre REST API, abordando desde conceitos básicos até tipos de clientes, endpoints e restrições.""}]",https://www.youtube.com/watch?v=d_vXgK4uZJM&list=PLWgD0gfm500EMEDPyb3Orb28i7HK5_DkR,"[Node.js - RESTful API](https://www.tutorialspoint.com/nodejs/nodejs_restful_api.htm) +[Criando uma API RESTful com NodeJS e Express](https://medium.com/xp-inc/https-medium-com-tiago-jlima-developer-criando-uma-api-restful-com-nodejs-e-express-9cc1a2c9d4d8) +",Criando API REST com Node.js Express e bodyParser,rw1730469197801db3259,Criando sua primeira API REST +TypeORM,Este guia rápido mostra como instalar o TypeORM e configurá-lo com um banco de dados PostgreSQL em um projeto Node.js.,Node.js,"ORM (Mapeamento Objeto-Relacional) é uma ferramenta que ajuda programadores a trabalhar com bancos de dados de forma mais fácil e intuitiva. Ele faz a ligação entre as tabelas do banco de dados e as classes do código, permitindo que você trabalhe com dados usando objetos em vez de escrever comandos SQL complicados. + +TypeORM é um ORM para TypeScript e JavaScript, que permite a interação com bancos de dados de forma simples e eficiente. Ele suporta diversos bancos de dados, incluindo MySQL, PostgreSQL, SQLite e MongoDB, e é amplamente utilizado em projetos que utilizam Node.js. + +--- + +**Principais características do TypeORM** + +- **Suporte a múltiplos bancos de dados:** TypeORM funciona com vários sistemas de gerenciamento de banco de dados, facilitando a migração entre eles. + +- **Suporte a TypeScript:** O TypeORM é desenvolvido em TypeScript, oferecendo recursos de tipagem estática que ajudam na detecção de erros em tempo de desenvolvimento. + +- **Entity-Relationship:** Permite o mapeamento de entidades (tabelas) e seus relacionamentos (one-to-one, one-to-many, many-to-many), facilitando a manipulação de dados complexos. + +- **Migrations:** Oferece suporte a migrações, permitindo o versionamento do esquema do banco de dados e facilitando atualizações e rollbacks. + +- **Query Builder:** Inclui um poderoso construtor de consultas que permite a criação de queries de forma programática e flexível. + + +",rw1730305270222b120a7,rw173047838568373c5c5,# TypeORM #1 - Conhecendo e criando um primeiro projeto,Angelo Luz,"[{""foreignRowId"":""rw173047838568373c5c5"",""foreignRowDisplayName"":""Neste vídeo, apresenta um tutorial do TypeORM, um framework em TypeScript. Explore suas principais características, como suporte a múltiplos bancos de dados, tipagem estática e mapeamento de entidades. ""}]",https://www.youtube.com/watch?v=6o0Vw0665kw,[NPM OFFICIAL - TYPEORM](https://www.npmjs.com/package/typeorm),Utilizando Node.js com TyperORM e um banco da escolha da aluna,rw17304802690217eb318,Conectando a aplicação com o banco de dados +Migrations,As migrations facilitam a criação e manutenção da estrutura do banco de dados ao longo do desenvolvimento.,Node.js,"Migrations são uma maneira de gerenciar alterações no esquema do banco de dados ao longo do tempo, garantindo que diferentes versões do banco estejam sincronizadas com as mudanças feitas no código. Elas permitem criar, alterar ou remover tabelas, colunas e restrições de forma controlada, evitando a necessidade de gerenciar manualmente cada mudança no banco de dados. + +--- + +**Configuração do TypeORM:** + +Certifique-se de que seu projeto possui o arquivo `data-source.ts` configurado. Esse arquivo geralmente está na raiz do projeto e define a conexão com o banco de dados. + +**Como cria:** + +Com o TypeORM, é possível gerar migrations automaticamente, com base nas mudanças feitas nas entities (entidades) ou criar scripts manualmente para alterações mais específicas. + +Para criar uma migration, você pode usar o comando: + +```bash +npx typeorm migration:create -n MigrationName +``` + +**Métodos up e down** + +O arquivo gerado terá um método up e outro down. O método up é usado para definir o que será feito (ex. criação ou alteração de tabelas), e o método down para reverter essas ações, caso seja necessário. + + +**Rodar a Migration:** + +Após criar a migration, execute o comando abaixo para aplicá-la ao banco de dados: + +```bash +npx typeorm migration:run +```",rw1730305280757a1a95b,rw1730478678431b72962,# Curso NodeJS - Migrations #13,Programar na web,"[{""foreignRowId"":""rw1730478678431b72962"",""foreignRowDisplayName"":""Neste vídeo, abordaremos as migrations, uma ferramenta essencial do TypeORM que facilita a criação de tabelas, colunas e relacionamentos no nosso banco de dados.\n\n""}]",https://www.youtube.com/watch?v=cmzqqBVJaec&t=8s,,,, +Variáveis e Constantes,Aprenda a usar variáveis e constantes para armazenar valores e entender seus escopos em React e Next.js.,Next.js,"Variáveis e constantes são essenciais para guardar informações em código, sendo definidas com `let`, `const` ou `var`. No desenvolvimento com Next.js e TypeScript, conhecer seus escopos é crucial para evitar erros e melhorar a estrutura do código. + +**Tipos de Escopo:** + +**Escopo Global:** Variáveis definidas fora de funções, acessíveis em todo o código. + +```typescript +let nomeGlobal = ""Aplicativo""; // Escopo global +``` + +**Escopo de Função:** Variáveis criadas dentro de uma função, só acessíveis dentro dela. + +```typescript +function mostrarNome() { + let nomeFuncao = ""Next.js""; // Escopo de função + console.log(nomeFuncao); +} +``` + +**Escopo de Bloco:** Usado com `let` e `const`, restringindo variáveis ao bloco `{ }` onde foram definidas. É importante para proteger variáveis de acessos externos acidentais. + +```typescript +if (true) { + let nomeBloco = ""React""; // Escopo de bloco + console.log(nomeBloco); +} +``` + +**Constantes (`const`):** Usadas para valores que não mudam. Importante para manter dados consistentes ao longo do código. + +```typescript +const PI = 3.14; +PI = 3.1415; // Erro: `const` não permite reatribuição +``` + +**Exemplo Prático:** + +Em uma aplicação Next.js, constantes e variáveis controlam dados e estados do usuário. + +```typescript +const appName = ""MeuApp""; // constante, nunca muda +let contador = 0; // variável, pode ser alterada + +function incrementar() { + contador += 1; + console.log(contador); +} +``` + +**Conclusão** + +Em Next.js e React com TypeScript, compreender e aplicar corretamente os escopos de variáveis e constantes organiza o código e reduz erros. +",rw1730305470024733aba,rw173022851922113f6a4,# Entendendo o escopo de variáveis e constantes em React Next JS - Aula 03 - Curso de React Next,CFBCursos,"[{""foreignRowId"":""rw173022851922113f6a4"",""foreignRowDisplayName"":""Neste vídeo, exploramos os conceitos de escopo de variáveis e constantes ao trabalhar com React e Next.js, utilizando TypeScript. A aula aborda como e onde declarar `const`, `let` e `var`, e explica a importância dos escopos local e global para garantir a segurança e o desempenho do código. Veremos como esses conceitos influenciam o comportamento das variáveis e como aplicá-los corretamente para evitar erros comuns e melhorar a organização da aplicação.""}]",https://www.youtube.com/watch?v=N5DCZWR_CWA,"[MDN Web Docs - Escopo](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Grammar_and_types#Escopo_de_vari%C3%A1veis) +[MDN Web Docs - Constantes](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Statements/const) +","Aprendendo a criar variáveis e exibir nas Tags, Crie uma função que calcule o IMC com base no peso e na altura e descubra a classificação correspondente","rw1732543930047f3166d,rw1732544420430568ad9","Criando Variáveis,Calculando o IMC " +Funções + Next.js,Funções permitem modularizar e reutilizar código executando blocos específicos conforme necessário.,Next.js,"Funções são blocos de código que executam tarefas específicas, sendo reutilizáveis e ideais para modularização em React com Next.js. Elas ajudam a reduzir a repetição e tornam o código mais organizado. Em TypeScript, funções podem ter tipagens explícitas para parâmetros e retornos, garantindo maior segurança e previsibilidade. + +**Definindo Funções** + +Uma função é declarada com a palavra-chave `function`, seguida pelo nome da função, parâmetros opcionais e o corpo da função. No exemplo a seguir, a função `saudacao` exibe uma mensagem ao ser chamada. + +```typescript +function saudacao(nome: string): void { + console.log(`Olá, ${nome}!`); +} + +saudacao(""João""); // Olá, João! +``` + +**Funções com Retorno** + +Funções podem retornar valores utilizando a palavra-chave `return`. O exemplo abaixo mostra a função `soma`, que aceita dois números como parâmetros e retorna a soma deles. + +```typescript +function soma(a: number, b: number): number { + return a + b; +} + +let resultado = soma(5, 3); // 8 +``` + +**Funções Anônimas e Arrow Functions** + +Funções também podem ser declaradas anonimamente e atribuídas a variáveis. As Arrow Functions (`=>`) oferecem uma sintaxe mais concisa, especialmente útil em React para evitar problemas com o `this`. + +```typescript +const multiplicacao = (x: number, y: number): number => x * y; + +console.log(multiplicacao(4, 2)); // 8 +``` + +**Funções Assíncronas** + +Funções assíncronas (`async`) permitem operações assíncronas, como chamadas de API, com a palavra-chave `await`, facilitando o uso de Promises. + +```typescript +async function fetchData(url: string): Promise { + const response = await fetch(url); + return response.json(); +} + +fetchData(""https://api.exemplo.com/dados"") + .then(data => console.log(data)) + .catch(error => console.error(error)); +``` + +**Conclusão** + +Funções são essenciais para criar código modular e eficiente, facilitando a leitura e manutenção. Em React e Next.js, elas tornam o desenvolvimento mais organizado e permitem a reutilização de lógica em diferentes componentes. +",rw173030547906927cbfb,rw1730381347511d42889,# Aprendendo como criar FUNÇÕES em React Next JS - Aula 04 - Curso de React Next,CFBCursos,"[{""foreignRowId"":""rw1730381347511d42889"",""foreignRowDisplayName"":""Este vídeo ensina como criar funções em React usando Next.js com TypeScript, abordando os conceitos e regras essenciais para escrever funções eficientes e bem estruturadas no contexto de aplicações React. A aula cobre a definição e o uso de funções comuns, funções de seta (arrow functions) e o papel de cada tipo de função na organização e reutilização do código. Além disso, demonstra como o TypeScript facilita a definição de tipos para parâmetros e valores de retorno, aumentando a segurança e clareza do código.""}]",https://www.youtube.com/watch?v=nWBgsikNl08,"[Funções em TypeScript](https://www.typescriptlang.org/docs/handbook/functions.html) +[Funções Assíncronas](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Using_promises)",,, +CSS + Next.js,Entenda como aplicar estilos em componentes usando CSS e Next.js,Next.js,"Quando trabalhamos com Next.js, temos várias opções para adicionar e organizar o CSS no projeto, o que facilita a criação de estilos modulares, globais e até escopados. Next.js oferece suporte nativo para métodos variados, desde CSS Modules e Styled JSX até bibliotecas como Styled-Components e frameworks de utilitários como o Tailwind CSS. Essas ferramentas permitem flexibilidade e controle no estilo dos componentes. + +**1. CSS Modules** +CSS Modules permitem a modularização e o escopo do CSS diretamente ao componente, evitando conflitos de estilo na aplicação. No Next.js, basta criar um arquivo `[componentName].module.css` e importá-lo no componente: + +```jsx +import styles from './Button.module.css'; + +function Button() { + return Click me; +} +``` + +**2. CSS Global** +Arquivos CSS globais podem ser usados para definir estilos que afetam toda a aplicação. Em Next.js, adicione estilos globais no arquivo `styles/globals.css` e importe-o no arquivo `_app.js`: + +```javascript +// pages/_app.js +import '../styles/globals.css'; + +function MyApp({ Component, pageProps }) { + return ; +} + +export default MyApp; +``` + +**3. Styled JSX** +O Next.js suporta Styled JSX nativamente, permitindo adicionar CSS escopo diretamente ao componente. Isso mantém o CSS isolado e facilita o estilo autônomo de cada componente: + +```jsx +function Component() { + return ( + + Styled JSX Example + {` + p { + color: blue; + } + `} + + ); +} +``` + +**4. Styled-Components e Emotion** +Next.js é compatível com bibliotecas CSS-in-JS como Styled-Components e Emotion, facilitando a criação de componentes estilizados diretamente com JavaScript. Para configurar, é necessário instalar o plugin Babel correspondente: + +```bash +npm install styled-components +npm install --save-dev babel-plugin-styled-components +``` + +Em seguida, configure o `.babelrc` e utilize os estilos no componente: + +```jsx +import styled from 'styled-components'; + +const Button = styled.button` + background: blue; + color: white; +`; + +function Component() { + return Click me; +} +``` + +**5. Tailwind CSS** +Tailwind CSS é um framework de utilitários de CSS muito popular que funciona bem com Next.js, permitindo aplicar estilos diretamente como classes utilitárias e configurações personalizadas. Para integrar, configure o `postcss.config.js` e `tailwind.config.js` após a instalação. +",rw1730305490354a90f72,rw173038059683403a76d,"# Como usar TAILWIND e classes CSS puras em React Next JS ",CFBCursos,"[{""foreignRowId"":""rw173038059683403a76d"",""foreignRowDisplayName"":""Neste vídeo você vai aprender sobre como usar o TAILWIND e classes CSS puras em React, Next e Typescript para aplicar formatação em nossos projetos.""}]",https://www.youtube.com/watch?v=IkYFn5Ums1Y,[CSS - Next.js Docs](https://nextjs.org/docs/app/building-your-application/styling),,, +Componentes + Next.js,Criando componentes reutilizáveis e interface modular flexível.,Next.js,"Next.js facilita o uso de componentes no desenvolvimento, permitindo a criação de interfaces dinâmicas e reutilizáveis. Com ele, é possível estruturar os componentes de várias formas, integrando-os com CSS escopo, bibliotecas de UI e otimizações de performance específicas. + +**1. Componentes Funcionais** +Os componentes funcionais são a principal abordagem no Next.js, permitindo a utilização de hooks do React para gerenciar estado e ciclo de vida: + +```jsx +function Button({ label }) { + return {label}; +} +export default Button; +``` + +**2. Componentes Dinâmicos** +Next.js permite carregar componentes dinamicamente para otimizar a performance da aplicação. Isso é feito usando `next/dynamic`, ideal para carregar componentes pesados de forma assíncrona: + +```jsx +import dynamic from 'next/dynamic'; + +const Chart = dynamic(() => import('../components/Chart'), { ssr: false }); + +function Dashboard() { + return ; +} +``` + +**3. Componentes com Estilo** +O Next.js suporta diversas abordagens para estilizar componentes, incluindo CSS Modules, Styled JSX e bibliotecas CSS-in-JS como Styled-Components e Emotion, permitindo estilos personalizados e escopados a cada componente. + +**4. Componentes Reutilizáveis** +É comum criar componentes reutilizáveis para otimizar a consistência do design e simplificar a manutenção. Botões, cards e modais são bons exemplos de componentes que podem ser usados em várias partes do projeto. + +**5. Componentes Padrão para Páginas e Layout** +Next.js facilita a criação de layouts que se aplicam a várias páginas. O layout pode ser envolvido no arquivo `_app.js` para fornecer uma estrutura comum, como cabeçalhos e rodapés, em toda a aplicação: + +```jsx +// pages/_app.js +import Layout from '../components/Layout'; + +function MyApp({ Component, pageProps }) { + return ( + + + + ); +} + +export default MyApp; +```",rw17303055001178b3f26,rw1730385036838928c85,"# Criando COMPONENTES em React e Next ",CFBCursos,"[{""foreignRowId"":""rw1730385036838928c85"",""foreignRowDisplayName"":""Nesta aula vamos aprender como criar componentes em React, Next e Typescript.""}]",https://www.youtube.com/watch?v=_II0dYvxiFI,[Next.js - Docs](https://nextjs.org/docs),Organize seu projeto criando um componente para exibir informações pessoais e use-o na página Home,rw173255101957441e7dd,Criando componentes +Componentes + props,Flexibilizando componentes com props passando propriedades.,Next.js,"No Next.js, componentes e props trabalham juntos para criar interfaces dinâmicas e reutilizáveis, permitindo que dados sejam passados e manipulados entre componentes de forma eficiente. + +**1. Passando Props para Componentes** +As props permitem passar informações dos componentes pai para os componentes filhos, garantindo que os dados sejam dinâmicos e adaptáveis. No exemplo abaixo, uma prop `label` é passada para personalizar o texto do botão: + +```jsx +function Button({ label }) { + return {label}; +} + +export default Button; +``` + +**2. Prop Types e Validação de Props** +Embora o Next.js suporte TypeScript para uma validação mais rigorosa, a biblioteca `prop-types` também pode ser usada para definir o tipo das props, ajudando a evitar erros: + +```jsx +import PropTypes from 'prop-types'; + +function Button({ label }) { + return {label}; +} + +Button.propTypes = { + label: PropTypes.string.isRequired, +}; + +export default Button; +``` + +**3. Desestruturação de Props** +Desestruturar as props permite acessar diretamente os valores e deixar o código mais limpo. Isso é particularmente útil quando há várias props: + +```jsx +function Card({ title, content, author }) { + return ( + + {title} + {content} + By {author} + + ); +} +``` + +**4. Props com Valores Padrão** +Props podem ter valores padrão no caso de não serem fornecidas, o que é útil para definir comportamentos consistentes: + +```jsx +function Button({ label = 'Click me' }) { + return {label}; +} +``` + +**5. Children como Prop** +A prop `children` permite passar componentes ou elementos diretamente entre as tags de um componente, facilitando a criação de estruturas flexíveis e layouts: + +```jsx +function Container({ children }) { + return {children}; +} + +// Uso + + Texto dentro do container + +```",rw17303055178849abcf2,rw1730385453771961ca5,"# Criando COMPONENTES com PROPS em React eNext ",CFBCursos,"[{""foreignRowId"":""rw1730385453771961ca5"",""foreignRowDisplayName"":""Nesta aula vamos continuar a aprender sobre como criar componentes em React, Next e Typescript. Vamos aprender o que são props e como podemos utilizar props para enviar funções e variáveis para um componente.""}]",https://www.youtube.com/watch?v=X_nGc0irnkM,[Next.js - Docs](https://nextjs.org/docs),Personalize o componente UserInfo para exibir informações de diferentes usuários utilizando props,rw1732552610168bb1015,Criando componente UserInfo com Props +Renderização,Renderização condicional em React é uma técnica essencial para exibir ou ocultar componentes com base em condições específicas do código.,Next.js,"A renderização condicional em React é uma técnica essencial para exibir ou ocultar componentes com base em condições específicas do código, proporcionando interfaces mais dinâmicas e intuitivas. Em uma loja virtual, por exemplo, faz sentido mostrar o preço com desconto apenas quando o produto realmente possui um desconto; caso contrário, esse campo se torna irrelevante. A renderização condicional ajuda a evitar elementos desnecessários, deixando a interface mais clara. + +No React, uma das maneiras mais práticas de implementar isso é com o operador ternário. Com ele, podemos definir condições diretamente no JSX, como no exemplo abaixo, em que o preço com desconto só aparece se o valor do desconto for maior que zero: + +```jsx +{desconto > 0 ? `Preço com desconto: ${precoComDesconto}` : null} +``` + +Para casos onde não precisamos de uma alternativa “falsa”, podemos simplificar com o operador `&&`. Esse operador permite exibir um componente apenas quando a condição é verdadeira, como neste exemplo: + +```jsx +{desconto > 0 && `Preço com desconto: ${precoComDesconto}`} +``` + +A renderização condicional também é útil para aplicar estilos dinamicamente. Suponha que queremos destacar produtos com desconto com uma borda vermelha. Podemos ajustar as classes CSS com base em uma condição diretamente no JSX: + +```jsx +className={`border ${desconto > 0 ? 'border-red-700' : 'border-blue-700'}`} +``` + +Com essas abordagens, é possível alcançar um código mais limpo e uma interface mais objetiva, onde apenas o conteúdo relevante é exibido em cada situação. A renderização condicional torna a aplicação mais flexível e interativa, ajustando elementos e estilos de maneira eficiente. ",rw1730305525617ed167f,rw1730385045868cb4220,# Renderização Condicional em Next.js,CFBCursos,"[{""foreignRowId"":""rw1730385045868cb4220"",""foreignRowDisplayName"":""Renderização condicional em React permite exibir ou ocultar componentes com base em condições, criando uma interface mais intuitiva. Usando operadores como `&&` e a operação ternária, é possível exibir um componente conforme a condição (verdadeira ou falsa). Isso também possibilita mudanças dinâmicas de estilo, personalizando a interface para o usuário e melhorando a experiência interativa.""}]",https://www.youtube.com/watch?v=ZSt8_kGWFJc,[Build it better: Next.js Conditional Rendering](https://medium.com/@brandonlostboy/build-it-better-next-js-conditional-rendering-be5617431cef),,, +Direcionamento de Páginas,React Router permite a criação de rotas em aplicações React possibilitando navegação fluida entre componentes sem recarregar a página. Isso facilita a organização e manutenção do código.,Next.js,"**O que é o React Router?** +O React Router é uma biblioteca que permite criar e gerenciar rotas em aplicações React. Ele exibe componentes específicos com base na URL acessada pelo usuário, facilitando a construção de interfaces dinâmicas e organizadas. + +**Estrutura de Páginas** +A seguir, criaremos uma estrutura básica com duas páginas: **Produtos** e **Teste**. + +1. **Criando a Pasta de Páginas** + No diretório `src`, crie uma pasta chamada `pages`. Dentro dela, crie subpastas chamadas `produtos` e `teste`. + +2. **Página de Produtos** + Crie o arquivo `produtos.tsx` dentro da pasta `produtos`: + + ```tsx + // src/pages/produtos/produtos.tsx + export default function Produtos() { + return ( + + Lista de Produtos + {/* Aqui podem ser adicionados cards dos produtos */} + + ); + } + ``` + +3. **Página de Teste** + Crie o arquivo `teste.tsx` dentro da pasta `teste`: + + ```tsx + // src/pages/teste/teste.tsx + export default function Teste() { + return ( + + Página de Teste + Esta é uma página para testar a navegação. + + ); + } + ``` + +**Adicionando Navegação** +Agora configuraremos a navegação entre as páginas usando o componente `Link` do React Router. + +1. **Componente de Navegação `Topo`** + Crie um componente `Topo` no diretório `src/components`: + + ```tsx + // src/components/Topo.tsx + import { Link } from 'react-router-dom'; + + export default function Topo() { + return ( + + + Home + Produtos + Teste + + + ); + } + ``` + +2. **Integrando a Navegação no `App.tsx`** + Atualize o arquivo `App.tsx` para incluir as rotas e o componente `Topo`: + + ```tsx + // src/App.tsx + import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; + import Topo from './components/Topo'; + import Produtos from './pages/produtos/produtos'; + import Teste from './pages/teste/teste'; + + function App() { + return ( + + + + Bem-vindo à Home} /> + } /> + } /> + + + ); + } + + export default App; + ``` + +**Testando a Navegação** +- Acesse **Home** para visualizar a mensagem de boas-vindas. +- Clique em **Produtos** para abrir a lista de produtos. +- Clique em **Teste** para exibir a página de teste. + +**Conclusão** +Com o React Router configurado, sua aplicação ganha uma navegação simples e eficiente. Essa estrutura pode ser expandida conforme as necessidades do projeto, permitindo a criação de interfaces mais completas e organizadas. ",rw173030553294685cacb,rw1730385685387455da6,# Criando Links e Redirecionamento de Página no Next.js,CBFCursos,"[{""foreignRowId"":""rw1730385685387455da6"",""foreignRowDisplayName"":""O vídeo introduz um novo curso de React, focando na criação e navegação entre páginas em uma aplicação. O professor Bruno explica como:\n\n- **Criar a estrutura de pastas:** Os alunos são orientados a criar pastas para `produtos` e `teste`, onde desenvolverão as páginas correspondentes.\n- **Construir componentes de página:** Cada página (`produtos.tsx` e `teste.tsx`) é criada para exportar funções que retornam conteúdo específico.\n- **Navegação entre páginas:** É demonstrado o uso da tag `link` para permitir que os usuários naveguem entre a página inicial, a de produtos e a de teste.\n- **Importar um menu de navegação:** O menu é adicionado ao topo de cada página, facilitando a transição entre elas.\n\nO vídeo destaca a importância de organizar a aplicação, garantindo que, ao final, as páginas estejam interconectadas e funcionais.""}]",https://www.youtube.com/watch?v=Ru1Xt-xdZy4,,Crie uma navegação simples entre páginas utilizando o Reat Router no Next.js,rw1732639866885f3bd9f,Navegação com React Router +Listas,Neste conteúdo abordamos como criar listas dinâmicas em React com Next.js e TypeScript com foco em preencher um elemento usando dados variáveis.,Next.js,"Neste conteúdo, abordamos como criar listas dinâmicas em React utilizando Next.js e TypeScript, com foco em preencher um elemento `` usando dados variáveis. O exemplo inicial mostra uma lista de cursos, que começa como uma lista estática e, em seguida, é dinamizada para que seja preenchida automaticamente a partir de dados externos, como os de uma API. Essa abordagem torna o desenvolvimento mais eficiente e facilita futuras atualizações. + +## Estrutura Inicial + +Primeiramente, montamos o `` com opções definidas diretamente no código, o que é funcional, mas limitado para listas maiores ou dados que mudam constantemente. Essa abordagem exige que cada opção seja inserida manualmente no HTML, tornando a manutenção do código mais trabalhosa. + +### Transformando em Lista Dinâmica + +Para maior flexibilidade, sugerimos transformar essas opções estáticas em um array de dados, onde cada item representa um curso. Essa mudança simplifica a atualização do conteúdo e melhora a manutenção. + +## Gerando as Opções com `.map()` + +Para preencher as opções no ``, utilizamos o método `.map()` do JavaScript. Esse método itera sobre o array e retorna uma `` para cada curso, associando o valor e o texto do curso automaticamente. Essa implementação pode ser feita diretamente no JSX ou através de uma função externa, tornando o código mais organizado e de fácil manutenção. + +### Expandindo para Arrays de Objetos JSON + +Após entender o uso de arrays simples, o exemplo se expande para arrays de objetos JSON, formato comum em respostas de APIs. Esse formato permite que cada curso tenha múltiplos atributos, como nome, código e categoria. No exemplo, cada objeto do array possui uma chave específica que identifica o curso. O `.map()` é ajustado para acessar a chave `curso` em cada objeto, de modo que o `` exiba dados mais completos e informativos. + +## Conclusão + +Essa técnica de uso de dados dinâmicos, seja via API ou outra fonte, permite que o conteúdo do `` seja atualizado automaticamente sempre que a lista de cursos mudar, tornando o código mais eficiente, flexível e escalável. Isso facilita a manutenção e permite um desenvolvimento mais ágil, especialmente quando se trabalha com dados dinâmicos. +",rw1730305540107e95fd7,rw1730386588439f1bcef,# Trabalhando com Listas em React Next,CBFCursos,"[{""foreignRowId"":""rw1730386588439f1bcef"",""foreignRowDisplayName"":""O vídeo é uma aula do professor Bruno sobre como manipular listas em projetos de Next.js com TypeScript. Ele ensina a preencher um elemento `` de forma dinâmica, utilizando dados de um array de cursos. Através de exemplos práticos, o professor demonstra como usar o método `.map()` para gerar opções a partir de listas, abordando também o uso de objetos JSON para tornar o preenchimento ainda mais eficiente. A aula explora diferentes abordagens e finaliza com a promessa de conteúdos futuros sobre o consumo de APIs.""}]",https://www.youtube.com/watch?v=vub097QVdjs,,,, +Axios,Axios é uma biblioteca JavaScript para fazer requisições HTTP com suporte a Promises permite comunicação entre cliente e servidor simplificando operações com APIs.,React.js,"O **Axios** é uma biblioteca JavaScript baseada em promises que auxilia a pessoa desenvolvedora a realizar requisições HTTP. Ele tem funcionalidades semelhantes à Fetch API, com alguns diferenciais: + +**1. Facilidade na manipulação de JSON** - reduz a quantidade de código; +**2. Funções específicas para métodos HTTP** - como get, post, delete, etc; +**3. Usabilidade tanto no cliente como no servidor** - funciona em ambos os ambientes. + + +O **Axios** será usado nos exemplos abaixo, simulando uma API de postagem de artigos, para realizar operações **CRUD** com a **API JSON** Placeholder, simplificando o envio e recebimento de dados via HTTP. Em uma requisição `GET`, ele busca dados específicos de um post e exibe no componente React, aproveitando `useEffect` para executar a chamada ao montar o componente. + +Para criar um novo post, utiliza `axios.post`, enviando `title` e `body` como dados. A atualização de um post é feita com `axios.put`, alterando o conteúdo conforme especificado, enquanto `axios.delete` remove o post e ajusta a interface. Além disso, o Axios facilita o tratamento de erros com `.catch`, exibindo mensagens em caso de falhas. + +A versão `async/await` melhora a leitura do código, e o Custom Hook centraliza as operações de requisição, tornando o código mais reutilizável e organizado. + + +Instalação do Axios: +Para começar, instale o Axios no projeto: + +```typescript +npm install axios +``` + +Utilizando Axios com a API JSON Placeholder: +Neste exemplo, utilizamos a API JSON Placeholder para buscar e manipular dados de postagens. + +Requisição GET (Buscar dados): +Exemplo para buscar dados de um post específico com `axios.get`: +```typescript +import React, { useEffect, useState } from ""react""; +import axios from ""axios""; + +const baseUrl = ""https://jsonplaceholder.typicode.com/posts""; + +export function Post() { + const [post, setPost] = useState(null); + + useEffect(() => { + axios.get(`${baseUrl}/1`).then(({ data }) => setPost(data)); + }, []); + + if (!post) return null; + + return ( + + {post.title} + {post.body} + + ); +} +``` +Requisição POST (Criar dados): Para criar um novo post: + +```typescript +function handleCriarPost() { + axios.post(baseUrl, { + titulo: ""Novo Post"", + corpo: ""Conteúdo do novo post"", + }).then(({ data }) => setPost(data)); +} +``` +Requisição PUT (Atualizar dados): Para atualizar o post: +```typescript +function handleAtualizarPost() { + axios.put(`${baseUrl}/1`, { + titulo: ""Post Atualizado"", + corpo: ""Conteúdo atualizado"", + }).then(({ data }) => setPost(data)); +} +``` + +Requisição DELETE (Excluir dados): Para excluir o post: + +```typescript +function handleExcluirPost() { + axios.delete(`${baseUrl}/1`).then(() => { + alert(""Post deletado!""); + setPost(null); + }); +} +``` + +Tratamento de Erros: Use o .catch para capturar e exibir erros: + +```typescript +axios.get(`${baseUrl}/1`).then(({ data }) => setPost(data)).catch((error) => setError(error.message)); +``` + +Usando Async/Await: Outra forma de escrever o código usando async/await: + + +```typescript +useEffect(() => { + async function buscarPost() { + try { + const { data } = await axios.get(`${baseUrl}/1`); + setPost(data); + } catch (error) { + setError(error.message); + } + } + buscarPost(); +}, []); +``` +Criando um Custom Hook (Opcional): Centralize as requisições em um Hook customizado: + +```typescript +import { useState, useEffect } from ""react""; +import axios from ""axios""; + +export function useAxios() { + const [dados, setDados] = useState(null); + const [carregando, setCarregando] = useState(true); + const [erro, setErro] = useState(null); + + useEffect(() => { + async function buscarDados() { + try { + const resposta = await axios.get(`${baseUrl}/1`); + setDados(resposta.data); + } catch (error) { + setErro(error.message); + } finally { + setCarregando(false); + } + } + buscarDados(); + }, []); + + return { dados, carregando, erro }; +} + +``` +",rw173038051978684a925,rw17303826775236dc6f9,# React.Js e Axios - Consumir dados de API com React e Axios,Matheus Battisti - Hora de Codar,"[{""foreignRowId"":""rw17303826775236dc6f9"",""foreignRowDisplayName"":""Neste vídeo você vai aprender a usar o Axios, uma biblioteca Javascript , Promise Based, que permite fazer requisições HTTP de forma facilitada. Grandes projetos são feitos com React e Axios, também utilizaremos React Router Dom para criar as rotas (páginas) da nossa aplicação.""}]",https://www.youtube.com/watch?v=NbhoeLj6lBs,"[React - Manipulando dados com Axios](https://dev.to/nascimento_/react-manipulando-dados-com-axios-2ac6) +[ReactJS: Consumo de APIs com Axios](https://medium.com/@filipefilpe/reactjs-consumo-de-apis-com-axios-a21247749301)",,, +Componentes,Um Component em React é como uma função JavaScript que retorna elementos de interface.,React.js,"**O que é um Componente?** + +Em React, um **Componente** é uma **parte independente e reutilizável de código** que representa uma parte da interface do usuário (UI). Componentes permitem dividir a interface em pedaços menores e mais gerenciáveis, onde cada Componente pode ter suas próprias funcionalidades e estilo. + +Pense nos Componentes como **blocos de construção** de uma aplicação. Assim como você monta um quebra-cabeça com várias peças, uma aplicação em React é construída com vários Componentes menores que juntos criam toda a interface. + +Usando o exemplo de uma postagem, podemos criar um Componente chamado `Postagem`, que representa o layout e o conteúdo de cada postagem individual na nossa aplicação. + +**Por que usar Componentes?** + +- **Reutilização**: Componentes podem ser usados várias vezes em diferentes partes da aplicação. +- **Organização**: Eles ajudam a organizar o código, separando funcionalidades e responsabilidades. +- **Modularidade**: Mudanças em um Componente não afetam outros, o que facilita a manutenção. + +Tipos de Componentes em React + +No React, existem dois tipos principais de Componentes: + +**1. Componentes de Função** +**2. Componentes de Classe** + +Embora ambos sirvam para a mesma finalidade (ou seja, retornar a interface que queremos exibir), há diferenças na forma como são escritos e como manipulam dados. A abordagem recomendada atualmente é usar **Componentes de função** junto com os **Hooks**. + +Vamos ver a diferença entre eles com o exemplo da `Postagem`. + +**1. Componentes de Função** + +Componentes de função são **simples e diretos**. Eles são definidos como funções JavaScript e **retornam HTML** que queremos exibir na tela. Este tipo de Componente é amplamente preferido no React moderno, especialmente desde que os Hooks foram introduzidos, permitindo adicionar funcionalidades adicionais sem precisar de classes. + +Exemplo: Componente de Função `Postagem` + +Imagine que queremos criar um Componente para exibir uma postagem em um feed. Abaixo está um exemplo de um **Componente de função** chamado `Postagem`. + +```javascript +import React from 'react'; + +function Postagem(props) { + return ( + + {props.autor} + {props.conteudo} + Curtidas: {props.curtidas} + + ); +} + +export default Postagem; +``` + +**Explicação** + +1. **`props`**: No React, **Props** são parâmetros que você pode passar para componentes, como se fossem argumentos de uma função. No exemplo acima, `Postagem` usa `props` para exibir o `autor`, o `conteudo` e o número de `curtidas` da postagem. +2. **Sintaxe Simples**: O Componente de função é escrito como uma função JavaScript que retorna o HTML que queremos exibir. Isso torna o código mais enxuto e fácil de ler. + +**Usando o Componente de Função `Postagem`** + +Para usar `Postagem`, basta renderizá-lo e passar as informações que queremos exibir: + +```javascript +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import Postagem from './Postagem'; + +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render( + +); +``` + +Aqui, renderizamos `Postagem` com as props `autor`, `conteudo` e `curtidas`. Essas Props vão preencher as partes correspondentes dentro do nosso componente. + +**2. Componentes de Classe** + +Componentes de classe eram o padrão antes dos componentes de função se tornarem populares com o React moderno e são baseados em classes JavaScript. Esse tipo de Componente pode ser um pouco mais complexo de entender, pois usa a palavra-chave `class` e precisa de um método `render()` para retornar o HTML. + +Exemplo: Componente de Classe `Postagem` + +Veja abaixo o mesmo exemplo `Postagem`, mas como um **Componente de classe**: + +```javascript +import React, { Component } from 'react'; + +class Postagem extends Component { + render() { + return ( + + {this.props.autor} + {this.props.conteudo} + Curtidas: {this.props.curtidas} + + ); + } +} + +export default Postagem; +``` + +**Explicação** + +1. **`this.props`**: Em Componentes de classe, usamos `this.props` para acessar os valores passados como Props. +2. **Método `render()`**: O método `render()` é obrigatório e serve para retornar o HTML que queremos exibir. +3. **Sintaxe Mais Completa**: Embora componentes de classe ofereçam mais funcionalidades, eles tendem a ser mais verbosos e menos intuitivos para iniciantes. + +**Usando o Componente de Classe `Postagem`** + +O uso do Componente de classe `Postagem` é o mesmo que o componente de função: + +```javascript +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import Postagem from './Postagem'; + +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render( + +); +``` + +**Diferença entre Componentes de Função e de Classe** + +Componentes de função e Componentes de classe em React têm diferenças importantes. Componentes de função são mais simples e diretos: escritos como funções JavaScript, acessam `props` diretamente e permitem o uso de Hooks, facilitando o gerenciamento de estados e funcionalidades. Já componentes de classe usam `this.props` e requerem o método `render()` para retornar HTML, o que os torna mais complexos. No React moderno, Componentes de função são preferidos por sua simplicidade e por serem o padrão em novos projetos. + +**Qual Usar?** + +Atualmente, **Componentes de função** são amplamente recomendados por serem mais simples e permitirem o uso de Hooks, que são uma das funcionalidades mais poderosas do React moderno. Com os Hooks, é possível gerenciar estados, ciclos de vida e outras funcionalidades avançadas sem precisar de classes. +",rw17303805251492d2538,rw1730480888550084053,# Curso React: Criando Componentes no React - #04,Matheus Battisti - Hora de Codar,"[{""foreignRowId"":""rw1730480888550084053"",""foreignRowDisplayName"":""Neste vídeo, vamos expandir nossos conhecimentos em React, criando Componentes e entendendo suas finalidades. Assim, tornaremos nossa aplicação mais reutilizável, além de melhorar a organização e facilitar a manutenção do código.""}]",https://www.youtube.com/watch?v=-wrsG0IGc-M,"[React Components](https://www.w3schools.com/react/react_components.asp) +",,, +Hooks,Aprenda a usar Hooks em React como useState useEffect useParams e useNavigate para tornar seus componentes mais dinâmicos e interativos.,React.js,"**Hooks em React: Aprendendo com um Exemplo Prático** + +No React, **Hooks** são funções que permitem usar funcionalidades como estado e ciclo de vida em componentes de função, sem precisar recorrer a componentes de classe. Vamos explorar alguns dos Hooks mais comuns: `useState`, `useEffect`, `useParams` e `useNavigate`, usando o exemplo de uma postagem. + +**O que são Hooks?** + +Os Hooks permitem que você “conecte” funcionalidades como estado e ciclo de vida aos componentes de função. Eles tornaram os componentes de função ainda mais poderosos, permitindo lidar com lógica complexa sem a necessidade de classes. + + +**Principais Hooks** + +**1. `useState`: Gerenciando Estado** + +O `useState` é um dos Hooks mais utilizados e permite que componentes de função tenham **estado** próprio, como se fossem variáveis que guardam informações que podem mudar. Para o exemplo da nossa postagem, vamos usar `useState` para armazenar o número de curtidas de uma postagem. + +```javascript +import React, { useState } from 'react'; + +function Postagem({ autor, conteudo }) { + const [curtidas, setCurtidas] = useState(0); + + const adicionarCurtida = () => { + setCurtidas(curtidas + 1); + }; + + return ( + + {autor} + {conteudo} + Curtidas: {curtidas} + Curtir + + ); +} + +export default Postagem; +``` + +**Explicação**: Usamos `useState` para criar uma variável de estado chamada `curtidas`. Com a função `setCurtidas`, conseguimos atualizar o número de curtidas cada vez que o botão é clicado. Assim, cada clique aumenta o valor de `curtidas` em 1, alterando o conteúdo do componente em tempo real. + +**2. `useEffect`: Executando Efeitos Colaterais** + +O `useEffect` permite realizar **efeitos colaterais** em componentes, como chamadas de API, manipulação de dados, ou atualização do DOM. No caso da nossa postagem, vamos simular uma **chamada para uma API** que carrega o conteúdo da postagem assim que o componente for exibido na tela. + +```javascript +import React, { useState, useEffect } from 'react'; + +function Postagem({ autor }) { + const [conteudo, setConteudo] = useState(''); + + useEffect(() => { + // Simulando uma chamada para buscar o conteúdo de uma postagem + const fetchData = async () => { + const resposta = await fetch('/api/postagem'); + const dados = await resposta.json(); + setConteudo(dados.conteudo); + }; + fetchData(); + }, []); + + return ( + + {autor} + {conteudo} + + ); +} + +export default Postagem; +``` + +**Explicação**: Neste exemplo, usamos `useEffect` para carregar o conteúdo da postagem uma única vez, logo após o componente ser montado na tela. Ao incluir um array vazio (`[]`) como segundo argumento de `useEffect`, estamos dizendo ao React que queremos que este efeito seja executado apenas uma vez, assim que o componente aparecer. + +**3. `useParams`: Acessando Parâmetros da URL** + +O `useParams` é utilizado em **rotas dinâmicas**, permitindo que componentes acessem parâmetros da URL. Em uma aplicação onde cada postagem tem seu próprio ID, podemos usar `useParams` para capturar esse ID e carregar a postagem correspondente. + +Para isso, vamos supor que estamos usando o React Router para navegação, e que temos uma rota para exibir uma postagem específica usando seu ID. + +```javascript +import React, { useState, useEffect } from 'react'; +import { useParams } from 'react-router-dom'; + +function Postagem() { + const { id } = useParams(); + const [conteudo, setConteudo] = useState(''); + + useEffect(() => { + // Carregando o conteúdo da postagem com base no ID + const fetchData = async () => { + const resposta = await fetch(`/api/postagem/${id}`); + const dados = await resposta.json(); + setConteudo(dados.conteudo); + }; + fetchData(); + }, [id]); + + return ( + + Postagem #{id} + {conteudo} + + ); +} + +export default Postagem; +``` + +**Explicação**: Usamos `useParams` para capturar o `id` da postagem da URL atual. A partir daí, fazemos uma chamada de API que carrega o conteúdo da postagem com base nesse ID, permitindo exibir diferentes conteúdos dependendo do ID da URL. + +**4. `useNavigate`: Navegação Programática** + +O `useNavigate` permite que um componente **redirecione o usuário** para uma rota específica. Esse Hook é útil para redirecionamentos após ações, como enviar uma postagem ou salvar uma edição. Neste exemplo, vamos adicionar um botão para redirecionar o usuário para a página inicial após clicar em ""Voltar"". + +```javascript +import React from 'react'; +import { useNavigate } from 'react-router-dom'; + +function Postagem({ autor, conteudo }) { + const navigate = useNavigate(); + + const voltarParaHome = () => { + navigate('/'); + }; + + return ( + + {autor} + {conteudo} + Voltar para a Home + + ); +} + +export default Postagem; +``` + +**Explicação**: Com `useNavigate`, podemos programar a navegação dentro do componente. Neste caso, ao clicar no botão ""Voltar para a Home"", o usuário é redirecionado para a página inicial (`'/'`), oferecendo uma navegação prática e intuitiva. + + + +**Conclusão** + +Os Hooks tornam os componentes de função do React mais poderosos e fáceis de usar, permitindo o gerenciamento de estados (`useState`), a execução de efeitos colaterais (`useEffect`), o acesso a parâmetros da URL (`useParams`) e a navegação programática (`useNavigate`). Esses recursos ajudam a criar uma experiência mais dinâmica e intuitiva para os usuários. Ao dominar esses Hooks, você terá um controle muito maior sobre o comportamento e a interatividade dos componentes da sua aplicação.",rw173038056720390e1fe,rw1730480890516130743,# Aprenda REACT HOOKS em 30 minutos | Tutorial sobre Hooks,Fernanda Kipper | Dev,"[{""foreignRowId"":""rw1730480890516130743"",""foreignRowDisplayName"":""Nesse vídeo vamos entender o que são os React Hooks, como utilizá-los e como criar os nossos próprios Hooks. Além disso, aprenderemos os principais Hooks oferecidos pelo React como o useState e useEffect.""}]",https://www.youtube.com/watch?v=Fc-___dblSI,[Usando Hooks com React Router](https://blog.logrocket.com/using-hooks-react-router/),,, +One-way Data Flow,O One-way Data Flow em React garante que os dados fluam do componente pai para os filhos tornando o estado mais previsível e o código mais fácil de manter.,React.js," +**One-way Data Flow em React.js: O que é e como funciona** + +O conceito de *One-way Data Flow* é uma das bases do funcionamento do React.js. Neste artigo, você, pessoa desenvolvedora, entenderá o que é esse fluxo de dados unidirecional, seus benefícios e como ele se aplica em exemplos práticos, incluindo um exemplo de postagem de artigo em JavaScript. + +**O que é o One-way Data Flow?** + +*One-way Data Flow* significa que os dados em uma aplicação React fluem em uma única direção: do componente pai para os componentes filhos. Essa abordagem simplifica o gerenciamento do estado, tornando mais fácil rastrear como os dados se movem pela aplicação. Em um componente React, o estado é geralmente mantido em um componente superior e é passado para os componentes filhos por meio de *Props*. + +**Por que o One-way Data Flow é importante?** + +**1. Previsibilidade:** Com os dados fluindo em uma única direção, o estado da aplicação é mais fácil de prever e depurar. Se algo não estiver funcionando corretamente, é mais simples identificar de onde a alteração no estado está vindo. +**2. Melhor organização de código:** O fluxo unidirecional ajuda a manter uma separação clara entre a lógica do componente e a interface. +**3. Manutenção e escalabilidade:** A aplicação se torna mais fácil de manter e escalar, pois o fluxo de dados é bem definido e controlado. + +**Exemplo Prático: Postagem de Artigo** + +Para ilustrar o conceito de *One-way Data Flow*, vamos criar um exemplo em que um componente pai, `FormularioArtigo`, recebe um estado de um artigo e o passa para um componente filho, `VisualizacaoArtigo`. + +**1. Criando o componente pai `FormularioArtigo`:** +```javascript +import React, { useState } from 'react'; +import VisualizacaoArtigo from './VisualizacaoArtigo'; + +const FormularioArtigo = () => { + const [artigo, setArtigo] = useState({ + titulo: '', + conteudo: '' + }); + + const lidarMudanca = (evento) => { + const { name, value } = evento.target; + setArtigo({ + ...artigo, + [name]: value + }); + }; + + return ( + + Poste um artigo + + + + + ); +}; + +export default FormularioArtigo; +``` + +**2. Criando o componente filho `VisualizacaoArtigo`:** +```javascript +import React from 'react'; + +const VisualizacaoArtigo = ({ artigo }) => { + return ( + + Pré-visualização do Artigo + {artigo.titulo} + {artigo.conteudo} + + ); +}; + +export default VisualizacaoArtigo; +``` + +**Explicação do exemplo** + +Este exemplo destaca o fluxo unidirecional de dados. Quando o estado no componente pai é atualizado, as mudanças são propagadas para os componentes filhos. Isso mantém a estrutura da aplicação organizada e fácil de seguir. + +- O estado do artigo é gerenciado no componente pai `FormularioArtigo` e atualizado sempre que a pessoa usuária digita no campo de entrada. +- O componente `VisualizacaoArtigo` recebe o estado do artigo como uma *Prop*, exibindo o título e o conteúdo. +- Com o *One-way Data Flow*, os dados são passados de `FormularioArtigo` para `VisualizacaoArtigo`, mantendo a direção do fluxo de dados clara e previsível. + + +**Conclusão** + +O *One-way Data Flow* é um dos principais motivos pelos quais React.js é uma escolha popular para o desenvolvimento de interfaces de usuário. Ele simplifica o controle do estado e melhora a previsibilidade do comportamento da aplicação. Em projetos mais complexos, você pode combinar essa abordagem com ferramentas como Redux ou Context API para gerenciar o estado de forma mais eficiente. +",rw17303806036144fb980,rw1730480897661541054,# Fluxo de dados unidirecional com React e Remix: como manter seus dados consistentes,RemixJS Brasil,"[{""foreignRowId"":""rw1730480897661541054"",""foreignRowDisplayName"":""Neste vídeo, você vai aprender o que é o fluxo de dados unidirecional e como implementá-lo em React e Remix para garantir a atualização consistente dos dados e melhorar a sincronização no front-end.""}]",https://www.youtube.com/watch?v=raV2nn6HLdw,[O que é fluxo de dados unidirecional no React?](https://www.educative.io/answers/what-is-unidirectional-data-flow-in-react),,, +React DOM,Explore como o ReactDOM permite a interação eficiente com o DOM em aplicações React Aprenda sobre seus métodos principais e casos de uso para otimizar seu desenvolvimento.,React.js,"**O que é ReactDOM?** + +`ReactDOM` é um pacote que gerencia a renderização dos elementos e componentes React na página da web, manipulando o DOM de forma eficiente. A principal vantagem é que ele trabalha junto com o DOM virtual, uma representação leve do DOM real, que permite atualizações rápidas e otimizadas, refletindo mudanças de forma mais eficiente no navegador. + +**Como Usar o ReactDOM?** + +Para utilizar `ReactDOM`, primeiro é necessário instalar o pacote em seu projeto React usando o seguinte comando: +```bash +npm install react-dom +``` + +Após a instalação, importe o `ReactDOM` no arquivo do seu aplicativo: +```javascript +import ReactDOM from 'react-dom'; +``` + +**Por que o ReactDOM é usado?** + +Antes do React, a manipulação direta do DOM resultava em atualizações demoradas, pois o navegador precisava recalcular e redesenhar a página a cada modificação. Com o `ReactDOM` e o DOM virtual, a atualização é feita de forma mais rápida, pois apenas as partes que realmente mudaram são alteradas no DOM real. + +**Métodos Importantes do ReactDOM** + +Alguns dos métodos mais relevantes do `ReactDOM` incluem: + +**- `ReactDOM.render()`:** Renderiza um componente ou elemento React em um contêiner DOM. Exemplo: + ```javascript + import ReactDOM from 'react-dom'; + import App from './App'; + + ReactDOM.render(, document.getElementById('root')); + ``` + +**- `findDOMNode()`:** Retorna o nó DOM onde um componente específico foi renderizado. Embora útil, é menos usado e, em muitos casos, substituído pelo uso de refs. + **- `unmountComponentAtNode()`:** Remove um componente React do DOM. +**- `hydrate()`:** Usado para renderizar componentes no lado do servidor, permitindo uma transição suave para a interatividade no lado do cliente. +**- `createPortal()`:** Renderiza um componente em um nó DOM fora da hierarquia atual do componente pai. Ideal para criar modais e elementos de sobreposição. + +**Características do ReactDOM** + + **- Algoritmo Diff Eficiente:** Modifica apenas as subárvores do DOM que realmente precisam de atualização. +**- Observáveis:** Permite a manipulação eficiente do DOM. +**- Usabilidade no Lado do Cliente e Servidor:** Oferece suporte tanto para renderização do lado do cliente quanto para server-side rendering (SSR). + +**Caso de Uso** + +Imagine que você deseja renderizar um aplicativo React no elemento DOM raiz da sua página. Aqui está como o `ReactDOM` é utilizado para esse caso: + +**Exemplo de Código:** +```javascript +import React from 'react'; +import ReactDOM from 'react-dom'; + +const App = () => { + return ( + + Olá, pessoa desenvolvedora! + Bem-vinda ao uso do ReactDOM! + + + ); +}; + +// Renderizando o componente App no elemento com id 'root' +ReactDOM.render(, document.getElementById('root')); +``` + + +**Conclusão** + +O `ReactDOM` é uma ferramenta indispensável para a pessoa desenvolvedora que busca renderizar e gerenciar componentes de forma eficiente no DOM. Ele traz métodos poderosos que, junto ao DOM virtual, garantem uma aplicação mais rápida e interativa, seja no lado do cliente ou na renderização do lado do servidor. +",rw17303806518422c6086,rw1730480899480877480,# Introdução ao React #2. O React e o ReactDOM.,web3escola,"[{""foreignRowId"":""rw1730480899480877480"",""foreignRowDisplayName"":""Nesta aula iremos ver a função das duas bibliotecas que compõe o React: React e ReactDOM.""}]",https://www.youtube.com/watch?v=Eqd4w1U4ugI,[React JS ReactDOM](https://www.geeksforgeeks.org/reactjs-reactdom/),,, +Refs,Refs no React permitem acessar diretamente elementos do DOM para manipulações fora do ciclo de renderização.,React.js,"**O que são Refs no React?** + +Refs são uma função fornecida pelo React para acessar o elemento DOM e os elementos React criados em componentes. Elas são úteis em situações onde uma pessoa desenvolvedora deseja alterar o valor de um componente filho, sem recorrer ao uso de Props e State. Para entender mais sobre como implementar e usar Refs corretamente no React, recomenda-se conferir o Curso ReactJS, que inclui exemplos práticos e casos de uso. + +As Refs permitem que a pessoa desenvolvedora interaja com esses elementos fora do fluxo de trabalho de renderização típico do React. Elas possuem ampla funcionalidade, pois é possível usar retornos de chamada com elas. + +**Criando Refs no React** + +As referências do React podem ser criadas usando a função `React.createRef()` e anexadas a um elemento React por meio do atributo `Ref`. + +Quando um componente de classe é construído, as Refs são normalmente atribuídas a uma propriedade de instância, permitindo que sejam referenciadas no componente. + +**Exemplo** + +```javascript +class MeuComponente extends React.Component { + constructor(props) { + super(props); + this.minhaRef = React.createRef(); + } + + render() { + return ; + } +} +``` + +**Acessando Refs no React** + +No React, quando uma referência é passada para um elemento na renderização usando o atributo `Ref`, o elemento DOM subjacente ou o componente React se torna acessível na propriedade atual da referência. + +```javascript +const node = this.minhaRef.current; +``` + +Agora, veremos como a pessoa desenvolvedora pode usar Refs em seu código, o que ajudará a entender melhor o caso de uso de Refs. + +**Exemplo** + +Neste exemplo, a pessoa desenvolvedora usa o valor alvo do evento para obter o valor. + +```javascript +// Arquivo - App.js + +// Sem Refs +class App extends React.Component { + constructor() { + super(); + this.state = { frases: """" }; + } + + atualizar(e) { + this.setState({ frases: e.target.value }); + } + + render() { + return ( + + Fulano diz{"" ""} + + + {this.state.frases} + + ); + } +} + +ReactDOM.render(, document.getElementById(""root"")); +``` + +**Mais exemplos de Refs no React** + +Vamos dar uma olhada em alguns exemplos de código React que usam Refs. Os exemplos proporcionarão uma melhor experiência de aprendizado sobre Refs no React. + +**Exemplo 1** + +Neste exemplo, a pessoa desenvolvedora usa Refs para adicionar uma função de retorno de chamada indiretamente com a ajuda da função `atualizar` e do manipulador de eventos `onChange`. + +```javascript +// Usando Refs +class App extends React.Component { + constructor() { + super(); + this.state = { frases: """" }; + } + + atualizar(e) { + this.setState({ frases: this.refs.qualquer.value }); + } + + render() { + return ( + + Fulano diz{"" ""} + + + {this.state.frases} + + ); + } +} + +ReactDOM.render(, document.getElementById('root')); +``` + +**Exemplo 2** + +Neste exemplo, a pessoa desenvolvedora define diretamente a função de retorno de chamada dentro de Ref. + +```javascript +// Arquivo - App.js + +// Callback usado dentro de ref +class App extends React.Component { + constructor() { + super(); + this.state = { frases: """" }; + } + + atualizar(e) { + this.setState({ frases: this.a.value }); + } + + render() { + return ( + + Fulano diz{"" ""} + { + this.a = callback; + }} + onChange={this.atualizar.bind(this)} + /> + + {this.state.frases} + + ); + } +} + +ReactDOM.render(, document.getElementById(""root"")); +``` + +**Por que usar `useRef` em vez de `createRef` em Componentes de Função?** + +Para superar as desvantagens de `createRef`, recomenda-se usar `useRef`. Este é um tipo de Hook usado para criar uma referência que contém um valor. Quando o valor é atualizado usando o componente de função, ele não é renderizado novamente, evitando renderizações desnecessárias e otimizando o desempenho. O `useRef` armazena um valor mutável que persiste em renderizações diferentes. + +```javascript +import { useRef } from 'react'; + +const Refs = () => { + let demoRef = useRef(null); + + function mudar() { + console.log(demoRef.current); + demoRef.current.style.backgroundColor = ""yellow""; + } + + return ( + + Mudar Cor + Mudar + + ); +}; +``` + +Basicamente, `createRef` é projetado para componentes de classe. Em cada renderização, `createRef` cria uma nova referência, o que não é adequado para componentes de função. + +**Quando usar Refs** + +Usar Refs fornece muitos benefícios e melhora a experiência de desenvolvimento. Elas são úteis em: + +- Uso com bibliotecas de terceiros. +- Animações. +- Gerenciamento de foco, reprodução de mídia e seleção de texto. + +**Quando não usar Refs** + +As Refs não devem ser usadas em: + +- Componentes funcionais, pois eles não têm instâncias. +- Situações que podem ser feitas declarativamente. +- Usar bibliotecas ou estruturas que fornecem seus próprios métodos de gerenciamento, como Redux ou MobX. + +**Conclusão** + +As Refs do React são úteis para interagir com a estrutura DOM dos componentes. Elas permitem acessar e manipular diretamente os elementos do DOM. Este guia ensina o propósito das Refs no React, como criá-las e como utilizá-las com exemplos práticos. +",rw173038068290709a104,rw1730480902069221187,# Entendendo Refs e forwardRef no ReactJS: Quando e Como Utilizar?,Dev Junior Alves,"[{""foreignRowId"":""rw1730480902069221187"",""foreignRowDisplayName"":""Neste vídeo, vou te mostrar como utilizar Refs para acessar elementos diretamente e como o forwardRef ajuda a criar componentes reutilizáveis que expõem seu DOM interno. Vamos explorar juntos a teoria e exemplos práticos para que você aprenda a aplicar essas técnicas no seu código e otimizar suas aplicações!""}]",https://www.youtube.com/watch?v=tJZX6U5SxOM,[ReactJS Refs](https://www.geeksforgeeks.org/reactjs-refs/),,, +Rendering,Render é o processo em que o React atualiza a interface com base no estado e nas props. Ele acontece inicialmente e sempre que o estado muda.,React.js,"**Renderização em React** + +React é uma biblioteca poderosa e amplamente utilizada para a criação de interfaces de usuário. No coração do React, existe um conceito simples, mas fundamental: a interface de usuário é uma função do estado, representada pela fórmula `v = f(s)`. No entanto, a simplicidade dessa equação esconde uma complexidade que, muitas vezes, causa confusão: quando e como o React atualiza a interface? + +**O que é Renderização?** + +De forma resumida, renderização é o processo pelo qual o React chama uma função de componente para atualizar a visualização. Quando um componente é renderizado, o React cria um instantâneo que captura o estado atual, as propriedades (props) e a descrição da interface de usuário (IU). A partir desse instantâneo, a interface é atualizada conforme necessário. + +**Processo de Renderização Inicial** + +Para que a interface inicial de um aplicativo React seja exibida, a renderização começa na raiz da aplicação. Esse processo envolve a criação de um ""root"" com `createRoot` e a chamada de `render` para exibir o componente principal: + +```javascript +// Arquivo index.js +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './App'; + +const elementoRaiz = document.getElementById('raiz'); +const raiz = createRoot(elementoRaiz); +raiz.render(); +``` + +Esse processo é gerenciado automaticamente em aplicativos criados com ferramentas como `create-react-app` ou `next.js`. + +**Renderizações Subsequentes** + +O que torna o React realmente interessante é a forma como ele lida com renderizações subsequentes. A regra principal é que o React só renderiza novamente um componente quando o estado é alterado. Essa atualização acontece quando a função de atualização de estado (`useState`) é chamada e o React detecta que o novo estado é diferente do anterior. + +**Exemplo Prático de Renderização** + +Imagine um botão que, ao ser clicado, altera o estado para exibir diferentes saudações: + +```javascript +import React, { useState } from 'react'; + +function Saudacao() { + const saudacoes = ['Olá!', 'Bonjour!', 'Hello!', 'Hola!']; + const [indice, setIndice] = useState(0); + + const aoClicar = () => { + setIndice((indiceAnterior) => (indiceAnterior + 1) % saudacoes.length); + }; + + return ( + + {saudacoes[indice]} + Próxima Saudação + + ); +} + +export default Saudacao; +``` + +Nesse exemplo, sempre que o botão é pressionado, a função `aoClicar` atualiza o estado usando `setIndice`. Se o novo índice for diferente do anterior, o React renderiza o componente novamente, exibindo a nova saudação. + +**Como o React Garante Eficiência na Renderização?** + +O React utiliza um processo chamado ""batching"" para otimizar as renderizações. Quando múltiplas chamadas de atualização de estado ocorrem em um único manipulador de eventos, o React agrupa essas atualizações e calcula o estado final antes de renderizar novamente. + +**Exemplo de Atualizações em Batch** + +```javascript +import React, { useState } from 'react'; + +function Contador() { + const [contador, setContador] = useState(0); + + const aoClicar = () => { + setContador(1); + setContador(2); + setContador((valorAnterior) => valorAnterior + 3); + }; + + return ( + + Contador: {contador} + Incrementar + + ); +} + +export default Contador; +``` + +Aqui, o React processa as chamadas de `setContador(1)`, `setContador(2)` e `setContador((valorAnterior) => valorAnterior + 3)` em batch e só renderiza o componente uma vez. O valor final exibido será `5`, pois `2 + 3 = 5`. + +**Comportamento em Atualizações Complexas** + +Se várias chamadas de atualização de estado forem feitas, o React usa a última chamada direta, ignorando as anteriores, a menos que uma função de callback que utilize o valor atual do estado seja passada. Isso garante que a renderização só ocorra quando realmente necessário, evitando renderizações desnecessárias e mantendo a performance da aplicação. + +**Renderizações em Componentes Aninhados** + +Outro aspecto importante é o comportamento de componentes aninhados. Mesmo que um componente filho não tenha estado ou props, ele pode ser renderizado novamente se fizer parte de um componente pai que teve seu estado alterado. + +```javascript +function ComponentePai() { + const [contador, setContador] = useState(0); + + return ( + + Contagem no Pai: {contador} + setContador(contador + 1)}>Incrementar Contagem + + + ); +} + +function ComponenteFilho() { + console.log('Componente Filho renderizado!'); + return Eu sou um componente filho!; +} +``` + +Nesse exemplo, sempre que o estado `contador` no `ComponentePai` é atualizado, o `ComponenteFilho` também é renderizado, mesmo que ele não tenha estado próprio. O React, porém, tenta minimizar renderizações desnecessárias sempre que possível. + +**Conclusão** + +Compreender como a renderização funciona no React ajuda a desenvolver aplicações mais eficientes e evitar armadilhas comuns. Lembrar que o React só re-renderiza componentes quando o estado muda e que ele agrupa atualizações para renderizar de forma otimizada são práticas essenciais para uma codificação mais consciente e performática. +",rw17303807028326d25e2,rw1730480905287b8eed4,"# Curso React: Renderização condicional (if) ",Matheus Battisti - Hora de Codar,"[{""foreignRowId"":""rw1730480905287b8eed4"",""foreignRowDisplayName"":""A proposta deste vídeo é mostrar como podemos exibir JSX diferente baseado em uma condição, ou seja, um if. Utilizaremos uma técnica chamada de renderização condicional no React, que deixa nosso código limpo e permite exibir dados de forma dinâmica, baseados em uma condição.\n""}]",https://www.youtube.com/watch?v=7ewepbLCvHc&list=PLnDvRpP8BneyVA0SZ2okm-QBojomniQVO&index=13,[O guia interativo para renderização em React](https://ui.dev/why-react-renders),,, +Router,Domine conceitos essenciais como rotas componentes de navegação e rotas aninhadas para criar experiências interativas e fluídas.,React.js,"**Introdução** + +O React Router é uma biblioteca essencial para gerenciar o roteamento em aplicações React, permitindo a criação de navegações dinâmicas em aplicações de página única (SPAs). Ele facilita a definição de rotas que conectam URLs a componentes específicos, proporcionando uma experiência de navegação fluida e organizada. Com funcionalidades como rotas aninhadas e roteamento condicional, o React Router se destaca por sua flexibilidade e facilidade de uso. Ao integrar-se perfeitamente com o React, ele é a escolha ideal para quem deseja construir interfaces interativas. Aprender a utilizá-lo é fundamental para qualquer pessoa desenvolvedora que busca criar aplicações web modernas. + +**O que é o React Router?** + +Muitos sites modernos são conhecidos como aplicações de página única (SPAs, do inglês ""single-page applications""). Embora pareçam ter várias páginas, na verdade, eles contêm componentes renderizados como se fossem páginas separadas. O que o React Router faz é renderizar condicionalmente determinados componentes, dependendo da rota utilizada no URL (por exemplo, `/` para a página inicial, `/about` para a página de informações etc.). + +Por exemplo, podemos utilizar o React Router para conectar com URLs como `www.knit-with-scrimba.com/`, `www.knit-with-scrimba.com/about` ou `www.knit-with-scrimba.com/shop`. + +**Como usar o React Router** + +Para começar a utilizar o React Router, primeiro é necessário instalá-lo usando o NPM: + +```bash +npm install react-router-dom +``` + +Como alternativa, você pode usar um playground no Scrimba, que já possui o código completo escrito. + +Em seguida, você precisa importar `BrowserRouter`, `Route` e `Switch` do pacote `react-router-dom`: + +```javascript +import React, { Component } from 'react'; +import { BrowserRouter, Route, Switch } from 'react-router-dom'; +``` + +No exemplo a seguir, faremos a ligação da página de entrada com duas outras ""páginas"" (que são, na verdade, componentes) chamadas `Shop` e `About`. + +Primeiro, é preciso configurar sua aplicação para funcionar com o React Router. Tudo que for renderizado deve estar dentro do elemento ``, então envolva seu App com essas tags primeiro. Esse componente gerencia a lógica de exibição dos vários componentes fornecidos. + +```javascript +// index.js +ReactDOM.render( + + + , + document.getElementById('root') +); +``` + +Em seguida, no seu componente `App`, adicione o elemento `Switch`. Este elemento garante que apenas um componente seja renderizado por vez. Caso não utilize o `Switch`, poderá acabar exibindo um componente padrão de erro, que criaremos depois. + +```javascript +function App() { + return ( + + + + + + ); +} +``` + +Agora, é hora de adicionar suas tags ``. Esses elementos servem como links entre os componentes e devem ser colocados entre as tags ``. + +Para informar às tags `` quais componentes elas devem carregar, adicione um atributo `path` e o nome do componente que deseja carregar no atributo `component`. + +```javascript + +``` + +A maioria dos URLs da página inicial é composta pelo nome do site seguido de `/`, por exemplo, `www.knit-with-scrimba.com/`. Neste caso, adicionamos o atributo `exact` à tag `Route`. Isso é necessário, pois outros URLs também podem conter `/`. Se não indicarmos à aplicação que ela deve procurar somente por `/`, ela carregará a primeira correspondência da rota, resultando em um bug complicado de resolver. + +```javascript +function App() { + return ( + + + + + + + + ); +} +``` + +Em seguida, importe os componentes na aplicação. É recomendável organizá-los em uma pasta chamada ""components"" para manter o código limpo e legível. + +```javascript +import Home from './components/Home'; +import About from './components/About'; +import Shop from './components/Shop'; +``` + +Agora, vamos abordar a mensagem de erro que mencionamos anteriormente, que será exibida se o usuário digitar um URL incorreto. Essa mensagem é simplesmente uma tag `` normal, mas sem o atributo `path`. O componente `Error` conterá uma mensagem simples, como `Oops! Página não encontrada!`. Não se esqueça de importá-lo na aplicação. + +```javascript +function App() { + return ( + + + + + + + + + ); +} +``` + +Até este ponto, seu site só pode ser navegado digitando os URLs. Para adicionar links clicáveis, utilize o elemento `Link` do React Router e crie um novo componente `Navbar`. Novamente, não se esqueça de importar este novo componente na aplicação. + +Adicione um `Link` para cada componente na aplicação e utilize `to=""URL""` para vincular aos URLs mencionados. + +```javascript +function Navbar() { + return ( + + Home + Sobre Nós + Comprar Agora + + ); +} +``` + +Agora, seu site terá links clicáveis, permitindo a navegação pela sua aplicação de página única! + +**Conclusão** + + O React Router é uma ferramenta indispensável para qualquer pessoa desenvolvedora que queira implementar navegação eficiente em aplicações React. Ele não apenas simplifica a gestão de rotas, mas também melhora a experiência do usuário, permitindo que as interações sejam rápidas e sem recarregamentos desnecessários. Com suas diversas funcionalidades, como rotas aninhadas e suporte a parâmetros na URL, o React Router se adapta a diferentes necessidades de projetos. Aprender a usá-lo é um passo crucial para construir aplicações web modernas e responsivas. +",rw1730380721158da9173,rw173048090692264cb7a,# React Router: O guia completo para navegação em aplicativos React,Matheus Battisti - Hora de Codar,"[{""foreignRowId"":""rw173048090692264cb7a"",""foreignRowDisplayName"":""Neste vídeo, você verá como configurar o React Router e criar rotas para diferentes páginas no seu aplicativo! Vamos explorar juntos como passar parâmetros de rota e tratar erros de forma prática. No final, você estará pronto para criar uma experiência de navegação incrível para seus usuários. ""}]",https://www.youtube.com/watch?v=7b42lVMdEjE,[Aprenda React Router em 5 minutos - um tutorial para iniciantes](https://www.freecodecamp.org/portuguese/news/aprenda-react-router-em-5-minutos-um-tutorial-para-iniciantes/),,, +State,Entenda o State em React e como ele permite gerenciar dados dinâmicos em suas aplicações.,React.js,"**Compreendendo o State em React** + +O conceito de **State** é fundamental em aplicações React, pois permite que a pessoa desenvolvedora armazene e gerencie dados que podem mudar ao longo do tempo. O State é um objeto que representa a parte da interface que deve ser atualizada quando os dados mudam. Através do State, é possível criar interfaces interativas e dinâmicas, onde os componentes respondem a ações da pessoa usuária, como cliques e preenchimento de formulários. + +**O que é State?** + +No React, cada componente pode ter seu próprio State. Esse estado é isolado e pode ser manipulado de maneira independente, permitindo que componentes distintos mantenham informações diferentes. O State é especialmente útil em situações onde a interface precisa refletir dados em tempo real, como contadores, formulários, listas de tarefas e muito mais. + +**Usando o Hook useState** + +Para criar um State, a pessoa desenvolvedora pode utilizar o hook `useState`, que retorna um par de valores: o estado atual e uma função para atualizá-lo. Aqui está um exemplo básico: + +```javascript +import React, { useState } from 'react'; + +function Contador() { + const [contagem, setContagem] = useState(0); + + const incrementar = () => { + setContagem(contagem + 1); + }; + + return ( + + Contagem: {contagem} + Incrementar + + ); +} +``` + +Neste exemplo, a função `Contador` cria um estado chamado `contagem`, inicializado em zero. Ao clicar no botão, a função `incrementar` é chamada, atualizando o estado e, consequentemente, a interface. Essa capacidade de reagir a eventos e atualizar a UI é o que torna o State tão poderoso. + +**Atualizações Assíncronas do State** + +Um aspecto importante do State em React é que ele é assíncrono. Isso significa que as atualizações do estado podem não acontecer imediatamente após a chamada da função de atualização. Para lidar com isso, a pessoa desenvolvedora deve evitar depender do estado atual diretamente após uma atualização. A abordagem recomendada é usar a função de atualização do State, que aceita uma função como argumento. Isso garante que a atualização seja baseada no valor mais recente do State: + +```javascript +setContagem(prevContagem => prevContagem + 1); +``` + +**Múltiplos States com useState** + +É possível gerenciar múltiplos States dentro de um único componente. Aqui está um exemplo que demonstra como fazer isso: + +```javascript +import React, { useState } from 'react'; + +function Formulario() { + const [nome, setNome] = useState(''); + const [email, setEmail] = useState(''); + + const handleSubmit = (e) => { + e.preventDefault(); + console.log(`Nome: ${nome}, Email: ${email}`); + }; + + return ( + + setNome(e.target.value)} + placeholder=""Nome"" + /> + setEmail(e.target.value)} + placeholder=""Email"" + /> + Enviar + + ); +} +``` + +Neste exemplo, o componente `Formulario` possui dois estados: `nome` e `email`. A pessoa usuária pode digitar seu nome e email, e ao submeter o formulário, os valores são exibidos no console. + +**State e Ciclo de Vida dos Componentes** + +O State em React também está intimamente relacionado ao ciclo de vida dos componentes. Durante a vida útil de um componente, o State pode ser atualizado várias vezes, levando a renderizações adicionais da interface. Abaixo está um exemplo de como usar o Hook `useEffect` para lidar com efeitos colaterais, como buscar dados ao montar o componente: + +```javascript +import React, { useState, useEffect } from 'react'; + +function DadosUsuario() { + const [usuario, setUsuario] = useState(null); + + useEffect(() => { + const fetchUsuario = async () => { + const resposta = await fetch('https://api.example.com/usuario'); + const dados = await resposta.json(); + setUsuario(dados); + }; + + fetchUsuario(); + }, []); // O array vazio faz com que o efeito execute apenas na montagem do componente + + if (!usuario) return Carregando...; + + return ( + + Nome: {usuario.nome} + Email: {usuario.email} + + ); +} +``` + +Neste exemplo, o componente `DadosUsuario` busca dados de um usuário quando é montado, usando o Hook `useEffect`. Enquanto os dados estão sendo carregados, uma mensagem de carregamento é exibida. + +**Gerenciamento de State Global** + +Embora o State local em componentes seja útil, muitas aplicações complexas exigem uma abordagem de gerenciamento de State global. Ferramentas como **Redux**, **Context API** e **MobX** permitem que a pessoa desenvolvedora compartilhe o State entre diferentes componentes, facilitando a construção de interfaces mais complexas e escaláveis. + +Um exemplo simples de como usar a Context API para gerenciar State global é mostrado abaixo: + +```javascript +import React, { createContext, useContext, useState } from 'react'; + +const UsuarioContext = createContext(); + +export function UsuarioProvider({ children }) { + const [usuario, setUsuario] = useState(null); + + return ( + + {children} + + ); +} + +export function useUsuario() { + return useContext(UsuarioContext); +} + +// Exemplo de uso +function MeuComponente() { + const { usuario, setUsuario } = useUsuario(); + + return ( + + {usuario ? `Olá, ${usuario.nome}` : 'Usuário não autenticado'} + setUsuario({ nome: 'João' })}>Login + + ); +} +``` + +Neste exemplo, `UsuarioContext` é criado para compartilhar informações sobre o usuário. O componente `MeuComponente` pode acessar e modificar o estado global através do Hook `useUsuario`. + + +**Conclusão** + +Compreender o State é essencial para qualquer pessoa desenvolvedora que deseje criar aplicações interativas com React. O State permite a criação de interfaces dinâmicas e responsivas que reagem a ações da pessoa usuária. Ao utilizar o Hook `useState` e entender a natureza assíncrona das atualizações, a pessoa desenvolvedora pode construir aplicações robustas e de fácil manutenção. Além disso, ao dominar conceitos avançados como gerenciamento de State global e ciclo de vida dos componentes, você estará preparado para enfrentar os desafios de projetos mais complexos. O conhecimento do State é o primeiro passo para dominar o React e explorar suas funcionalidades avançadas. +",rw1730380736895949100,rw17581316941728d3526,# Dominando o React Hook useState | Aprenda a Gerenciar o Estado no React,DevClub | Programação,"[{""foreignRowId"":""rw17581316941728d3526"",""foreignRowDisplayName"":""Neste vídeo, vamos mergulhar fundo no mundo do React Hook useState, explorando todos os aspectos fundamentais que você precisa saber para se tornar um desenvolvedor React experiente. Vamos cobrir:\n- O que é o Hook useState e por que é tão importante.\n​- Como criar e inicializar estados no React.\n- Como atualizar e modificar o estado de forma eficiente.\n- Lidar com estados em componentes funcionais.\n- Exemplos práticos e projetos para consolidar seu conhecimento.""}]",https://www.youtube.com/watch?v=E-gIg2dXWv4,[React: Descomplicando estados](https://blog.rocketseat.com.br/react-descomplicando-estados/),,, +Estrutura de Páginas Web e Links,Descubra como organizar e estruturar uma página web de forma intuitiva e eficiente.,Introdução ao HTML e CSS,"**1. Seções básicas de um documento HTML** + +As páginas da web podem e serão muito diferentes umas das outras, mas todas tendem a compartilhar componentes padrão semelhantes, a menos que a página exiba um vídeo ou um jogo em tela cheia, seja parte de algum tipo de projeto de arte ou seja mal estruturada: + +- **Cabeçalho (header)**: + Normalmente, uma grande faixa na parte superior com um grande título e / ou logotipo. É aí que as principais informações comuns sobre um site geralmente ficam de uma página para outra. + +- **Barra de navegação**: + Links para as principais seções do site; geralmente representado por botões de menu, links ou guias. Como o cabeçalho, esse conteúdo geralmente permanece consistente de uma página para outra - ter uma navegação inconsistente em seu site levará a usuários confusos e frustrados. Muitos web designers consideram a barra de navegação parte do cabeçalho em vez de um componente individual, mas isso não é um requisito; na verdade, alguns também argumentam que ter os dois separados é melhor para acessibilidade, já que os leitores de tela podem ler melhor os dois recursos se estiverem separados. + +- **Conteúdo principal**: + Uma grande área no centro que contém a maior parte do conteúdo exclusivo de uma determinada página da Web, por exemplo, o vídeo que você deseja assistir ou a história principal que você está lendo ou o mapa que deseja visualizar ou as manchetes de notícias, etc. Esta é a única parte do site que definitivamente irá variar de página para página! + +- **Barra lateral (sidebar)**: + Algumas informações periféricas, links, cotações, anúncios etc. Geralmente, isso é contextual ao conteúdo principal (por exemplo, em uma página de um artigo de notícias, a barra lateral pode conter a biografia do autor ou links para artigos relacionados), mas há também casos em que você encontrará alguns elementos recorrentes como um sistema de navegação secundário. + +- **Rodapé (footer)**: + Uma faixa na parte inferior da página que geralmente contém letras pequenas, avisos de direitos autorais ou informações de contato. É um lugar para colocar informações comuns (como o cabeçalho), mas geralmente essas informações não são críticas ou secundárias ao próprio site. O rodapé também é usado às vezes para fins de SEO, fornecendo links para acesso rápido a conteúdo popular. + +**Exemplo de um documento HTML básico:** + +```html + + + + + Exemplo de Página HTML + + + + + Meu Site + Bem-vindo ao meu site! + + + + + Início + Sobre + Serviços + Contato + + + + + Bem-vindo ao Conteúdo Principal + Este é o conteúdo principal da página, onde você encontrará as informações mais importantes. + + + + Barra Lateral + Aqui estão alguns links úteis e outras informações secundárias. + + + + © 2024 Meu Site. Todos os direitos reservados. + Política de Privacidade + + + + +``` + +**2. Links** + +Links em HTML são criados com a tag ``, também conhecida como ""anchor tag"". Ela é usada para criar hiperlinks que podem direcionar o usuário para outra página, documento, e-mail, ou até mesmo para uma seção específica dentro da mesma página. + +- **Sintaxe básica de um link**: + +```html +Texto do Link +``` + +No exemplo acima, o atributo `href` contém o endereço de destino do link, e o conteúdo entre `` e `` é o texto visível no link. + +- **Exemplo básico**: + +```html +Visite nosso site +``` + +Este exemplo cria um link com o texto ""Visite nosso site"", que leva o usuário para ""https://www.exemplo.com"" ao clicar. + +- **Abrir link em uma nova aba**: + +Para abrir o link em uma nova aba, adicione o atributo `target=""_blank""` à tag ``. + +```html +Abrir em nova aba +``` + +- **Links para endereços de e-mail**: + +Para criar um link que abre o cliente de e-mail com um destinatário pré-preenchido, use `mailto:` no atributo `href`. + +```html +Envie um e-mail +``` + +- **Links para seções específicas da página**: + +Para direcionar o usuário a uma seção específica da página, utilize o atributo `id` na tag destino e, no link, adicione `#` seguido do valor desse `id`. + +```html +Vá para a Seção 1 + + + Seção 1 + Conteúdo da Seção 1. + +``` + +**Atributos comuns**: + +- `href`: Define o destino do link. +- `target`: Controla onde abrir o link (`_blank` para nova aba, `_self` para mesma aba). +- `title`: Adiciona um texto de dica exibido ao passar o cursor sobre o link. +- `rel`: Define a relação entre a página atual e a página de destino. Combinado com `target=""_blank""`, é recomendado adicionar `rel=""noopener noreferrer""` para melhorar a segurança.",rw17303925853926d59c2,rw1730480896589942212,# Como entender a estrutura de elementos HTML de uma pagina,Tio do HTML,"[{""foreignRowId"":""rw1730480896589942212"",""foreignRowDisplayName"":""Entenda a estrutura de uma página HTML e quais tags utilizar pra montar sua página.""}]",https://www.youtube.com/watch?v=oZvuH9_IvwI&t=90s&ab_channel=~TioDoHtml,"[Estrutura de documento e sites](https://developer.mozilla.org/pt-BR/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure#se%C3%A7%C3%B5es_b%C3%A1sicas_de_um_documento) +[Estrutura básica de páginas web](https://www.hiperbytes.com.br/curso-de-html-aula1-estrutura-basica-paginas-web/)",Neste exercício você adicionará links internos e externos para facilitar a navegação e tornar seu portfólio online mais completo,rw173091287683887ea99,Adicionando Links +Elementos Multimídia,Incorporar elementos multimídia torna a página mais interativa e acessível para melhorar a experiência do usuário.,Introdução ao HTML e CSS,"Incorporar elementos multimídia como imagens, áudio, vídeo e gráficos torna a página web mais rica e interativa, melhorando a experiência do usuário. Aqui estão alguns conceitos básicos e exemplos de como utilizar esses elementos de forma acessível e responsiva. + +**1. Inserindo imagens com acessibilidade** + +A tag <`img`> insere imagens e exige dois atributos importantes: + +- `src`: define o caminho da imagem. +- `alt`: descreve a imagem para acessibilidade e SEO, fundamental para leitores de tela e para o caso da imagem não carregar. + + +```html + +``` + +Para tornar a imagem responsiva, podemos controlar o tamanho no CSS: + +```css +img { + max-width: 100%; + height: auto; +} +``` + +**Dica**: Use descrições no `alt` que informem claramente o conteúdo da imagem, sem incluir termos como ""imagem de"" ou ""foto de"". + + +**2. Responsividade com *srcset* para Imagens** + +O atributo `srcset` permite fornecer várias resoluções de imagem, permitindo que o navegador escolha a melhor opção para a tela do usuário. Isso melhora a performance, especialmente em dispositivos móveis. + +```html + +``` + +Neste exemplo, o navegador usará a imagem de 768 pixels de largura em telas pequenas e a de 1200 pixels em telas maiores. + + +**3. Adicionando vídeo com personalização** + +A tag <`video`> permite a adição de vídeos, e atributos como `controls`, `autoplay`, `loop` e `muted` ajudam a personalizar a experiência do usuário. + +```html + + Seu navegador não suporta a tag de vídeo. + +``` + +- `controls`: exibe controles de reprodução. +- `autoplay`: inicia a reprodução automaticamente (com `muted` por padrão). +- `loop`: faz o vídeo reiniciar automaticamente ao término. +- `muted`: inicia o vídeo sem som. + +**Dica**: Use `autoplay` com cautela, pois reproduções automáticas podem incomodar o usuário. + +**4. Adicionando legendas em vídeos com <`track`>** + +Legendas são essenciais para acessibilidade em vídeos. A tag <`track`> adiciona legendas sincronizadas, úteis para usuários que preferem assistir em silêncio ou precisam de apoio visual. + +```html + + + +``` + +O arquivo `.vtt` contém as legendas com o tempo sincronizado ao vídeo. + + +**5. Compatibilidade de formato de arquivo** + +- **Imagens**: Use formatos como JPEG e PNG para fotos e gráficos complexos, e SVG para gráficos vetoriais. +- **Vídeos**: MP4 e WebM são amplamente suportados, e o uso de <`source`> ajuda a fornecer múltiplos formatos para garantir compatibilidade. + +",rw17303926086341dc649,rw173048089362798d4d6,"# Curso HTML - Multimídia (Imagens, áudios e vídeos)",Se7i Tecnologia,"[{""foreignRowId"":""rw173048089362798d4d6"",""foreignRowDisplayName"":""Nesse vídeo você vai aprender como trabalhar com multimídias no HTML: Imagens, áudios e vídeos. \n""}]",https://www.youtube.com/watch?v=mHZ6PfLen8c&ab_channel=Se7iTecnologia,"[HTML5 - Conteúdo incorporado e multimídia](https://dev.to/arthurassuncao/html5-conteudo-incorporado-e-multimidia-2kl8) +[Video: O elemento HTML de incorporação de Vídeo](https://developer.mozilla.org/pt-BR/docs/Web/HTML/Element/video) +[IMG](https://developer.mozilla.org/pt-BR/docs/Web/HTML/Element/img)",Adicione imagens e vídeos à sua página. Torne seu conteúdo mais interativo e envolvente,rw1730914094155257784,Adicionando Elementos Multimídia +Formulários - Tabelas - Listas,Desvende os formulários com validação tabelas e listas no contexto de desenvolvimento web.,Introdução ao HTML e CSS,"Os formulários são uma parte essencial da interação em uma página web, permitindo que os usuários `insiram e enviem dados`. Eles podem ser usados para coletar informações, como nome, e-mail, comentários, entre outros. A validação de formulários é um processo crucial que garante que os dados enviados sejam corretos e seguros. + +***Estrutura de um Formulário*** + +Um formulário HTML é criado usando a tag <`form`>, que pode conter diferentes tipos de campos, como: + +- Texto: <`input type=""text""`> +- Senha: <`input type=""password""`> +- Email: <`input type=""email""`> +- Número: <`input type=""number""`> +- Botão de Enviar: <`input type=""submit""`> + +**Exemplo de um formulário simples:** + +```html + + + Nome: + + + E-mail: + + + + + + +``` + +***Validação de Formulários*** + +A validação pode ser feita no lado do cliente, utilizando HTML5, ou no lado do servidor. As validações do lado do cliente podem ser realizadas através de atributos HTML, como `required, minlength, maxlength, e pattern`. + + + +**Exemplo de validação básica com HTML5:** + +```html + + + Idade: + + + + + +``` + + + +***Validação Personalizada*** + +Para validações mais complexas, como verificar formatos específicos ou regras de negócios, você pode usar JavaScript para implementar lógicas personalizadas. +",rw1730392611795685162,rw1730480892419e14aa7,# Como criar um formulário com HTML e CSS,Jeterson Lordano - dev,"[{""foreignRowId"":""rw1730480892419e14aa7"",""foreignRowDisplayName"":""Assistindo o vídeo você vai aprender a criar um formulário estilizado do início ao fim, utilizando HTML e CSS! Este tutorial oferece um passo a passo que o ajudará a construir um formulário simples e a aplicar estilos visuais que o tornem mais atraente e funcional. ""}]",https://www.youtube.com/watch?v=-MsqwWyv8eQ,"[Sua primeira tabela em HTML](https://www.youtube.com/watch?v=lIiZu-94PBk&t=235s) +[Alinhando o conteúdo em tabelas](https://www.youtube.com/watch?v=djvX6p9l-Rk)",Neste exercício você aprenderá sobre formulários e também tabelas e listas,rw17309152597892989ce,Criando tabelas e também formulários e listas +Deploy com o Netlify,O Netlify é uma ferramenta robusta para automação de deploy e hospedagem de sites modernos com facilidade.,Deploy,"O **Netlify** é uma plataforma moderna de hospedagem para sites e aplicações web, projetada para simplificar o processo de **deploy** e integrar práticas de **integração contínua (CI/CD)**. Com ele, você pode conectar repositórios Git e garantir que cada alteração feita no código seja automaticamente refletida em um site público. + +Além da praticidade, o Netlify oferece uma série de funcionalidades que elevam a experiência de publicação e gestão de sites, como: +- **Customização de domínios** para maior profissionalismo. +- **Certificação SSL gratuita**, garantindo conexões seguras. +- **Interface amigável**, que facilita a gestão de builds e monitoramento do status de deploy. + +--- + +**Como Publicar Seu Site no Netlify?** + +**Objetivo** +Aprender a publicar um site simples e disponibilizá-lo online rapidamente. Também exploraremos como configurar deploys automáticos para manter seu projeto sempre atualizado. + +--- + +**1. Publicando Manualmente no Netlify** + +Esse método é indicado para quem deseja publicar rapidamente sites estáticos ou pequenos projetos sem utilizar Git. É ideal para testar ideias ou compartilhar protótipos. + +**Passo a Passo:** + +1. **Acesse o Netlify** + Visite o site [Netlify](https://netlify.com) e clique em **""Sign Up""** para criar uma conta gratuita, ou, se já possuir uma conta, faça login clicando em **""Log In""**. Após entrar, você será direcionado ao painel principal, que exibe todos os seus projetos já publicados. + +2. **Inicie o Deploy Manual** + No painel, procure a opção **""Add New Site""** e clique nela. Em seguida, selecione **""Deploy manually""**. Essa opção abrirá uma nova tela que permitirá o upload direto dos arquivos do seu site. + +3. **Arraste e Solte os Arquivos do Seu Site** + Localize os arquivos do seu site no seu computador (HTML, CSS, JavaScript, imagens, etc.). Em seguida, arraste-os para a área indicada no Netlify. O Netlify iniciará o upload e, em poucos segundos, processará os arquivos, configurando automaticamente o ambiente. + +4. **Visualize e Compartilhe o Link Público** + Após o upload ser concluído, o Netlify gerará automaticamente um link público exclusivo. Esse link permite que qualquer pessoa visualize o seu site. Ele estará pronto para ser compartilhado com colegas, clientes ou amigos. + +5. **Personalize o Domínio (Opcional)** + Se quiser um link mais personalizado, acesse as configurações do site clicando em **""Site Settings""**. Em seguida, navegue até **""Domain Settings""**. Aqui, você pode editar o subdomínio padrão ou conectar um domínio personalizado de sua propriedade, conferindo ao site um aspecto mais profissional. + +--- + +**2. Publicando com GitHub no Netlify** + +Esse método é ideal para quem utiliza Git e deseja automatizar o processo de deploy, garantindo que o site seja atualizado sempre que novas alterações forem feitas no código. + +**Passo a Passo:** + +1. **Conecte o Netlify ao GitHub** + No painel do Netlify, clique em **""Add New Site""** e, desta vez, selecione **""Import from Git""**. O Netlify solicitará que você conecte sua conta GitHub. Clique em **""Authorize""** para conceder acesso, permitindo que a plataforma visualize seus repositórios. + +2. **Selecione o Repositório do Projeto** + Após a conexão, o Netlify exibirá uma lista de repositórios disponíveis em sua conta GitHub. Localize o repositório que contém o projeto que você deseja publicar e clique nele para selecioná-lo. + +3. **Configure a Build e Escolha a Branch** + O próximo passo é definir como o Netlify deve tratar os arquivos do seu projeto. Escolha a branch que será monitorada para deploys (geralmente ""main"" ou ""master""). + + Para sites simples de HTML, CSS e JavaScript, o Netlify detecta automaticamente a configuração necessária. No entanto, para projetos mais complexos (como aplicações em React, Vue, ou outros frameworks), você pode precisar definir comandos específicos de build, como: + ```bash + npm run build + ``` + Também é possível ajustar variáveis de ambiente para atender às necessidades do projeto. + +4. **Ative o Deploy Automático** + Após finalizar as configurações, o Netlify começará a monitorar automaticamente a branch configurada. Sempre que você fizer um **push** de alterações para essa branch, o Netlify iniciará um novo processo de build e atualizará o site. Isso elimina a necessidade de deploys manuais. + +5. **Obtenha e Compartilhe o Link Público** + Assim como no método manual, o Netlify gerará um link público para o seu site. Qualquer pessoa pode acessar o site por esse link, e ele será atualizado automaticamente com cada nova modificação no repositório Git. + +--- + +**Recursos Adicionais do Netlify** + +- **Certificação SSL Automática** + Garantir segurança é essencial. Por isso, o Netlify fornece automaticamente certificados SSL para todos os sites hospedados, sem custo adicional. + +- **Ferramentas de Build Personalizadas** + O Netlify oferece suporte nativo para frameworks modernos, permitindo que você configure pipelines de build automatizados e customize o deploy de projetos complexos. + +- **Monitoramento em Tempo Real** + Acompanhe logs de build e erros em tempo real diretamente pelo painel. Isso permite diagnosticar rapidamente qualquer problema que possa ocorrer durante o deploy. + +- **Redirects e Rewrites** + Configure redirecionamentos e reescritas de URL diretamente através de um arquivo `_redirects`, sem a necessidade de servidores adicionais. + +--- + +**Resultado Esperado** + +Após seguir esses passos, seu site estará disponível online, acessível por meio de um link público. Se optar pelo deploy automático via GitHub, qualquer modificação feita no repositório será refletida no site, garantindo que ele esteja sempre atualizado com o menor esforço possível. O Netlify oferece a combinação perfeita de simplicidade e eficiência, tornando o processo de deploy fluido e descomplicado.",rw17319342118235d2670,rw17304809219861eb6cb,# Como Hospedar seu Site de Graça com Netlify,Dotcode,"[{""foreignRowId"":""rw17304809219861eb6cb"",""foreignRowDisplayName"":""Neste vídeo explica como usar o Netlify para hospedar rapidamente um site na web, sem complicações. Basta criar uma conta, fazer o upload dos arquivos e o Netlify gera um link acessível a qualquer pessoa. É uma maneira simples e eficiente de publicar sites.""}]",https://www.youtube.com/watch?v=0EUTK5EHK_A,[Como realizar deploy de aplicação na Netlify](https://blog.formacao.dev/como-realizar-deploy-de-aplicacao-na-netlify/),"Aprenda a realizar o deploy de seu site no Netlify, configurando deploys automáticos e garantindo atualizações simples e eficientes",rw1731946635738b8a139,Publicando seu Projeto com Netlify +Projeto Pokémon,Explore o mundo Pokémon enquanto aprende habilidades incríveis de front-end e back-end.,Projetos Fullstack,"O universo Pokémon é uma franquia mundialmente reconhecida que combina elementos de aventura, estratégia e exploração. Desde sua estreia em 1996, o conceito central envolve treinadores que capturam criaturas chamadas Pokémon, desenvolvendo suas habilidades e formando laços enquanto exploram um mundo cheio de desafios e mistérios. Cada Pokémon possui características únicas, como tipos elementares (por exemplo, fogo, água, planta), que determinam seus pontos fortes e fracos em batalhas. Essa dinâmica estratégica, aliada a uma jornada de superação e amizade, conquistou gerações de fãs. +A popularidade do Pokémon é incomparável sendo uma das franquias mais lucrativas de todos os tempos. Desde o sucesso inicial dos jogos para Game Boy a série continuou a evoluir com títulos recentes para o Nintendo Switch e fenômenos culturais como Pokémon GO que trouxe a experiência para o mundo real através da realidade aumentada. A franquia promove a criatividade e o pensamento crítico, ao mesmo tempo que incentiva a conexão entre fãs de todas as idades. +",rw1732546252209eee8fb,,,,,,"[Descubra o que é Pokémon e por que a série se tornou um fenômeno](https://modobrincar.rihappy.com.br/o-que-e-pokemon/) +[Repositório Github](https://github.com/Wander06/ensinando-endpoints-parte-2-T26)",Desafie-se a criar uma aplicação incrível que analisa as fraquezas dos Pokémons com base nos tipos e conectando backend com frontend para uma experiência interativa,rw17325466486388a37ea,Crie uma Página Web sobre Pokémons +Projeto Acelera Movies,Este projeto consiste na criação de uma biblioteca de filmes utilizando os templates pré-configurados de repositórios fornecidos pela Aceleradora TW.,Projetos Fullstack,"Neste projeto, você será guiado para desenvolver uma aplicação completa de biblioteca de filmes, utilizando dois repositórios base prontos para acelerar o processo. A proposta é trabalhar tanto o backend, com foco em APIs e banco de dados, quanto o frontend, explorando interfaces interativas. +O objetivo é integrar as duas camadas para criar uma experiência fluida e funcional.",rw17326239607377fa730,,,,,,,"Crie o frontend com Next.js conecte ao backend personalize o layout e implante na Vercel, Configure o backend com Node.js TypeORM e PostgreSQL Teste a API e adicione um filme Explore migrations e prepare para produção no Heroku","rw1732628187155dfa078,rw173262818047403e05d","Frontend - Desenvolvendo a Interface,Backend - Construindo a Base de Dados" +Mocking e Espiões,Entenda a importância dos Spies e como usá-los para melhorar seus testes automatizados.,Testes Unitários com Jest,"**O Que é Mocking e Espiões?** + +**Mocking** é uma técnica usada em testes para simular comportamentos de dependências externas, como APIs ou bancos de dados, permitindo testar o código de forma isolada. +Já os **espiões (spies)** são usados para monitorar chamadas feitas a funções, verificando se elas foram invocadas, com quais parâmetros e quantas vezes. + +--- + +**Tipos Comuns de Mocking e Espiões:** + +- **Mocks:** Substituem o comportamento de funções ou objetos para simular dependências externas. +- **Stubs:** Retornam respostas específicas para chamadas de funções, sem lógica adicional. +- **Espiões (Spies):** Verificam a interação com funções, como chamadas e argumentos usados. +--- + +**Por Que Mocking e Espiões São Importantes?** + +- **Isolamento de Testes:** Garantem que os testes não dependam de fatores externos, como APIs ou bancos de dados. +- **Rapidez nos Testes:** Com mocks, é possível evitar atrasos causados por chamadas reais a serviços externos. +- **Verificação de Interações:** Espiões ajudam a garantir que funções críticas foram chamadas corretamente durante a execução dos testes. +--- + +**Ferramentas para Mocking e Espiões** +- **Jest (JavaScript):** Oferece suporte integrado para mocks e spies, tornando o processo de teste mais simples. +- **Sinon.js:** Popular em projetos JavaScript, permite criar spies, stubs e mocks. +- **Mockito (Java):** Ferramenta robusta para mocking em aplicações Java. +--- + +**Boas Práticas:** +- **Mockar Apenas o Necessário:** Evite mockar tudo, pois isso pode tornar os testes menos realistas. +- **Testar Comportamento Real:** Sempre que possível, priorize testar comportamentos reais antes de recorrer ao mocking. +- **Verificar Interações Essenciais:** Use espiões para confirmar que funções críticas estão sendo chamadas corretamente. +--- + +**Exemplo Prático de Mocking e Espiões com Jest** + +**Código (userService.js):** +```bash +function getUser(id) { + // Simulação de chamada a um banco de dados + return { id, name: 'User Test' }; +} +module.exports = { getUser }; +``` +**Teste com Mocking (userService.test.js):** +```bash +const { getUser } = require('./userService'); +test('deve retornar o usuário com ID fornecido', () => { + const mockGetUser = jest.fn().mockReturnValue({ id: 1, name: 'Mock User' }); + expect(mockGetUser(1)).toEqual({ id: 1, name: 'Mock User' }); + expect(mockGetUser).toHaveBeenCalledWith(1); +}); +``` +**Rodando os testes:** +```bash +npx jest +```",rw17327243381915bac78,rw17327245965322396ed,"# Mocks, Stubs, Dummies, Fakes e Spies ",Otavio Lemos,"[{""foreignRowId"":""rw17327245965322396ed"",""foreignRowDisplayName"":""Nesse vídeo tem a definição de todos esses tipos de dublês de teste utilizando um artigo clássico do Martin Fowler.""}]",https://www.youtube.com/watch?v=9w4GpaOeX7M,[Documentação do Jest sobre Mock Functions](https://jestjs.io/pt-BR/docs/mock-functions),O desafio consiste em testar um sistema simples de carrinho de compras.,rw1732814508508e8129b,Construindo e Testando um Sistema de Carrinho de Compras +Testando Código com Dependências Externas,"Aprenda a testar código que depende de serviços externos, como APIs de terceiros enquanto garante a confiabilidade e a estabilidade dos seus testes.",Testes Unitários com Jest,"**O Que São Dependências Externas?** + +Dependências externas são componentes fora do controle direto do seu código, como: + +- **APIs externas:** Serviços de terceiros que fornecem funcionalidades específicas. +- **Bancos de dados:** Armazenamento de informações acessadas pelo seu sistema. +- **Bibliotecas e frameworks:** Código externo utilizado para adicionar funcionalidades ao projeto. +--- +**Desafios de Testar Código com Dependências Externas** +- **Instabilidade:** O serviço externo pode estar fora do ar ou responder lentamente. +- **Dados Voláteis:** A base de dados externa pode mudar, gerando inconsistências nos testes. +- **Custo:** Chamadas constantes a APIs externas podem gerar custos desnecessários. +--- +**Estratégias para Testar Código com Dependências Externas** +- **Mocking:** Simula o comportamento da dependência externa, permitindo testar o código de forma isolada. +- **Stubs:** Retornam respostas controladas para funções externas, sem precisar executar a lógica real. +- **Espiões (Spies):** Monitoram a interação com funções externas, verificando chamadas e parâmetros. +--- +**Ferramentas Populares** +- **Jest (JavaScript):** Permite mockar funções assíncronas que fazem chamadas externas. +- **Sinon.js:** Oferece suporte para criar mocks, stubs e spies em projetos JavaScript. +- **WireMock:** Ferramenta que simula APIs externas para testes em aplicações Java. +--- +**Exemplo Prático: Testando Código com API Externa Usando Jest** + +**Código (apiService.js):** +```bash +const axios = require('axios'); +async function fetchData(url) { + const response = await axios.get(url); + return response.data; +} +module.exports = { fetchData }; +``` + +**Teste com Mocking (apiService.test.js)** + +```bash +const { fetchData } = require('./apiService'); +const axios = require('axios'); +jest.mock('axios'); +test('deve retornar dados mockados da API', async () => { + axios.get.mockResolvedValue({ data: { message: 'Mocked Data' } }); + const data = await fetchData('https://api.example.com/data'); + expect(data).toEqual({ message: 'Mocked Data' }); + expect(axios.get).toHaveBeenCalledWith('https://api.example.com/data'); +}); +``` +**Rodando os testes** +```bash +npx jest +``` +",rw1732725191266b72448,rw1732725225314aa5dcb,# Tutorial Teste Unitário com Jest,Dev Tech,"[{""foreignRowId"":""rw1732725225314aa5dcb"",""foreignRowDisplayName"":""Tutorial sobre como utilizar Jest para escrever testes unitários em projetos Node.js. \n""}]",https://youtu.be/A6ODQSxy3Co?si=Et-sIs6Iv2lZq1UQ,[Documentação do Jest sobre Mock Functions](https://jestjs.io/pt-BR/docs/mock-functions),Nesta atividade você vai criar uma função que simula a inserção de dados em um banco de dados,rw1732810429625e12b85,Testando Código com Banco de Dados Simulado +Testando Componentes React,Aprender a testar componentes React utilizando bibliotecas e boas práticas para garantir qualidade e funcionalidade.,Testes Unitários com Jest,"**Os testes de componentes React** são uma parte essencial do desenvolvimento front-end para garantir que o comportamento esperado seja mantido. Este conteúdo aborda: + +- Configuração de ambiente de testes com Jest e React Testing Library. +- Testes unitários para verificar funcionalidades específicas de componentes. +- Testes de integração para assegurar a interação entre diferentes partes da aplicação. +- Abordagem TDD (Test Driven Development) para escrever testes antes do código. + +--- + +**Testando um Componente React** + +**Código do Componente: `Greeting.jsx`** + +Este componente exibe uma mensagem de saudação e tem um botão que altera a mensagem quando clicado. + +```bash +import React, { useState } from ""react""; + +const Greeting = () => { + const [message, setMessage] = useState(""Olá, visitante!""); + + const handleClick = () => { + setMessage(""Bem-vindo ao React!""); + }; + + return ( + + {message} + Alterar Saudação + + ); +}; + +export default Greeting; +``` +**Código do Teste: `Greeting.test.jsx`** + +```bash +import { render, screen, fireEvent } from ""@testing-library/react""; +import Greeting from ""./Greeting""; + +describe(""Greeting Component"", () => { + it(""deve exibir a mensagem inicial corretamente"", () => { + render(); + + // Verifica se a mensagem inicial é exibida + const messageElement = screen.getByTestId(""greeting-text""); + expect(messageElement.textContent).toBe(""Olá, visitante!""); + }); + + it(""deve alterar a mensagem ao clicar no botão"", () => { + render(); + + // Simula o clique no botão + const buttonElement = screen.getByText(""Alterar Saudação""); + fireEvent.click(buttonElement); + + // Verifica se a mensagem foi alterada + const messageElement = screen.getByTestId(""greeting-text""); + expect(messageElement.textContent).toBe(""Bem-vindo ao React!""); + }); +}); +``` +--- + +**Passos para Executar o Teste** + +**1. Instale as dependências:** +```bash +npm install --save-dev @testing-library/react @testing-library/jest-dom jest +``` + +**2. Execute os testes:** +```bash +npm test +``` + +--- + +**Resultado esperado:** + +Os dois testes devem passar e você verá a confirmação no terminal. + +--- + +**Explicação:** + +- **render()**: Renderiza o componente React para um DOM virtual. +- **screen.getByTestId**: Localiza o elemento pelo atributo data-testid. +- **fireEvent.click**: Simula a ação de clique no botão. +- **expect**: Verifica se o comportamento do componente está correto. +",rw1732725482864a45477,rw1732726068414632003,# Testando um componente React,Front Beginners,"[{""foreignRowId"":""rw1732726068414632003"",""foreignRowDisplayName"":""Neste vídeo você colocará em prática a como testar um componente react utilizando jest e também react testing library.""}]",https://www.youtube.com/watch?v=9UiIAbWU5eA," [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)",Nesta atividade você vai testar um componente contador utilizando Jest e React Testing Library,rw1732812769706adad54,Teste Componente de Contador +Boas Práticas de Testes,Boas práticas de testes são essenciais para garantir a qualidade do código e facilitar a manutenção dos sistemas.,Testes Unitários com Jest,"Seguir boas práticas de testes é **crucial** para o sucesso do desenvolvimento de software. +Isso envolve: + +- Criar testes claros e objetivos. +- Cobrir cenários reais de uso. +- Garantir que os testes sejam rápidos e fáceis de manter. Além disso, os testes devem ser independentes entre si e devem fornecer feedback rápido sobre a saúde do sistema. + +--- + +**Cenário: Testar um botão de contagem** + +**Código do Componente (`Counter.js`):** + +```bash +import React, { useState } from ""react""; + +const Counter = () => { + const [count, setCount] = useState(0); + + return ( + + Contador: {count} + setCount(count + 1)}>Incrementar + + ); +}; + +export default Counter; +``` + +**Código de Teste (Counter.test.js):** + +```bash +import { render, screen, fireEvent } from ""@testing-library/react""; +import Counter from ""./Counter""; + +describe(""Counter Component"", () => { + it(""deve renderizar o contador com valor inicial 0"", () => { + render(); + const counterText = screen.getByText(/Contador: 0/i); + expect(counterText).toBeInTheDocument(); // Verifica se o texto inicial está na tela + }); + + it(""deve incrementar o contador ao clicar no botão"", () => { + render(); + const button = screen.getByRole(""button"", { name: /Incrementar/i }); + fireEvent.click(button); // Simula o clique no botão + const counterText = screen.getByText(/Contador: 1/i); + expect(counterText).toBeInTheDocument(); // Verifica se o valor foi incrementado + }); +}); + +``` +--- + +**Boas Práticas Demonstradas:** + +- **Testar um comportamento por vez:** +Cada it testa apenas uma funcionalidade: renderização inicial e incremento. + +- **Usar seletores semânticos:** +getByText e getByRole utilizam seletores baseados no conteúdo ou função do elemento, que são mais confiáveis e refletem a experiência do usuário. + +- **Isolamento de testes:** +Cada teste é independente, sem dependência entre os estados. Cada render cria uma instância limpa do componente. + +- **Mensagens claras:** +As descrições dos testes explicam exatamente o que estão verificando. + +--- +**Executando os Testes** + +Para rodar o teste, utilize o comando: + +```bash +npm test +``` + +**Resultado esperado:** + +```plaintext +PASS src/Counter.test.js + Counter Component + ✓ deve renderizar o contador com valor inicial 0 (30 ms) + ✓ deve incrementar o contador ao clicar no botão (15 ms) +```",rw1732726244691adcd36,rw1732726508036fe2f1b,# Princípios F.I.R.S.T.: Qualidade na Criação de Testes Automatizados,Dias de Dev,"[{""foreignRowId"":""rw1732726508036fe2f1b"",""foreignRowDisplayName"":""Descubra como aplicar os princípios F.I.R.S.T. para garantir qualidade na criação de testes automatizados! Neste vídeo, explora cada um desses princípios essenciais, ajudando você a escrever testes robustos e eficazes.""}]",https://www.youtube.com/watch?v=p6opbsek-zs,"[Testes automatizados: tipos, ferramentas e boas práticas](https://community.revelo.com.br/testes-automatizados-tipos-ferramentas-e-boas-praticas/) +","Nesta atividade, você vai refatorar um conjunto de testes para garantir que eles sejam organizados e fáceis de manter.",rw1732803174198ffbf6a,Refatorando Testes para Melhor Manutenção +Conceitos Básicos de Testes Unitários,"Compreenda o que são testes unitários, a importância de garantir a qualidade do código e quando utilizá-los.",Testes Unitários com Jest,"**O Que São Testes Unitários?** + +Testes unitários são uma prática fundamental no desenvolvimento de software, que consistem em escrever pequenos testes para verificar se uma **unidade específica** de código está funcionando corretamente. Uma ""unidade"" normalmente se refere a uma **função**, **método** ou **componente isolado** da aplicação. O objetivo desses testes é garantir que cada parte do sistema funcione como esperado, independentemente das outras partes do código. + +A importância de realizar testes unitários vai além de simplesmente verificar o comportamento esperado de uma função. Eles ajudam a **evitar bugs**, **melhorar a qualidade do código** e **facilitar a manutenção** ao longo do tempo. Quando você escreve um teste unitário, você tem uma forma automatizada de verificar se seu código está funcionando corretamente, sem a necessidade de testes manuais repetidos. + +Além disso, os testes unitários tornam o processo de desenvolvimento mais confiável e ágil, permitindo que os desenvolvedores façam alterações no código sem medo de quebrar funcionalidades existentes. Isso é especialmente importante em equipes de desenvolvimento maiores e em projetos complexos, onde as mudanças frequentes no código podem introduzir novos problemas. + +--- + +**Quando Usar Testes Unitários?** + +Testes unitários são úteis principalmente quando você está criando **funções independentes** e **isoladas**, ou seja, que não dependem de outras partes complexas do sistema. Se você tem funções que executam cálculos ou manipulam dados de maneira simples, testes unitários são ideais. + +Você pode também escrever testes unitários em várias fases do ciclo de desenvolvimento, mas é altamente recomendável que os desenvolvedores escrevam esses testes **antes de começar a codificar**, no que se chama de **Test-Driven Development (TDD)**. Isso ajuda a guiar o desenvolvimento de forma mais estruturada e diminui a chance de problemas mais tarde. + +--- + +**Por Que Testar o Código?** + +- **Detectar erros precocemente:** Ao testar pequenas partes do código, você consegue identificar problemas logo no início do desenvolvimento, evitando que erros se acumulem. +- **Refatoração segura:** Quando você precisa alterar ou otimizar o código, os testes unitários servem como uma rede de segurança, garantindo que as mudanças não quebrem funcionalidades existentes. +- **Facilita a manutenção:** Com uma base de testes, é mais fácil entender o comportamento de diferentes partes do sistema. Caso algo dê errado no futuro, você pode rodar os testes novamente para verificar se o problema é relacionado ao código já testado. +- **Documentação:** Os testes podem servir como uma forma de documentação do comportamento esperado de cada unidade de código. Outros desenvolvedores que entrarem no projeto podem olhar para os testes e entender rapidamente como as funções ou métodos devem funcionar. + +--- + +**Como Funciona um Teste Unitário?** + +Em termos simples, um teste unitário verifica se uma função retorna o valor correto para uma determinada entrada. Por exemplo, se você tiver uma função que soma dois números, o teste unitário verificará se ela realmente soma os valores corretamente: + +```javascript +function soma(a, b) { + return a + b; +} + +test('soma 1 e 2 para retornar 3', () => { + expect(soma(1, 2)).toBe(3); +}); +Neste exemplo, o teste está dizendo: ""Eu espero que a função soma(1, 2) retorne o valor 3."" Se a função retornar algo diferente de 3, o Jest (ou outro framework de testes) vai identificar esse erro e exibir uma mensagem informando que o teste falhou. +",rw1732729739182de554a,rw17327320098823e5f62,# Teste Unitário - O que é ?,Garoto de Software,"[{""foreignRowId"":""rw17327320098823e5f62"",""foreignRowDisplayName"":"" Nesse video tento de uma maneira simples explicar os conceitos básicos desse tipo de teste.""}]",https://www.youtube.com/watch?v=dxdvGuKyBs8,"- [Teste unitário: entenda a importância desse tipo de teste para o desenvolvimento de software](https://www.objective.com.br/insights/teste-unitario/) +- [Testes unitários](https://medium.com/@celionormando/testes-unit%C3%A1rios-5bb55a9b4e83)",Nesta atividade você vai escrever um teste unitário simples para uma função que soma dois números,rw1732800899865ca56dd,Testando a Soma com Jest +Escrevendo Testes Simples com Jest,Aprenda a usar o Jest para criar testes básicos.,Testes Unitários com Jest,"**Por que utilizar Jest?** + +Jest é conhecido por sua simplicidade e funcionalidade completa, permitindo que pessoas desenvolvedoras configurem, escrevam e executem testes rapidamente. Ele oferece suporte nativo para a criação de mocks, spies, testes assíncronos e geração de relatórios claros. + +--- + +**Como começar** + + 1. **Instalação** + No terminal, basta rodar o comando: + ```bash + npm install --save-dev jest + ``` + + - **Para projetos que utilizam Yarn:** + + ```bash + yarn add --dev jest + ``` + + 2. **Configuração básica** + Adicione o script de teste ao arquivo `package.json`: + + ```json + ""scripts"": { + ""test"": ""jest"" + } + ``` + + 3. **Criando o primeiro teste** + Comece criando um arquivo chamado `sum.js` com uma função simples: + + ```javascript + function sum(a, b) { + return a + b; + } + module.exports = sum; + ``` + + Crie o arquivo de teste correspondente `sum.test.js`: + + ```javascript + const sum = require('./sum'); + + test('soma de 1 + 2 deve ser 3', () => { + expect(sum(1, 2)).toBe(3); + }); + ``` + + Execute o comando `npm test` para verificar o resultado. + +--- + +**Dicas** + 1. Organize seus testes em pastas separadas para manter o projeto limpo. + 2. Nomeie os arquivos de teste com a extensão `.test.js` ou `.spec.js` para facilitar a execução. +",rw1732729774319f3a701,rw1732733703246a64f39,# Concretizando expectativas: introdução ao Jest - CodeLab Bits,CodeLab,"[{""foreignRowId"":""rw1732733703246a64f39"",""foreignRowDisplayName"":""No vídeo de hoje o João veio falar um pouco sobre testes no JavaScript dando uma noção básica do framework Jest.\n""}]",https://www.youtube.com/watch?app=desktop&v=0a0lqX2pFdM&ab,[Documentação oficial do Jest](https://jestjs.io),Nesta atividade você vai escrever um teste para comparar duas strings,rw1732803088332a5dd34,Teste de Comparação de String +Testando Funções e Módulos com Jest,Explore como testar funções e módulos em JavaScript utilizando Jest para garantir que seu código esteja funcionando corretamente.,Testes Unitários com Jest,"**Por Que Testar Funções e Módulos?** + +Ao desenvolver software, é essencial garantir que cada função e módulo do código funcione conforme o esperado. Testar funções e módulos com Jest proporciona diversas vantagens: + +- **Qualidade do Código**: Reduz a possibilidade de erros, garantindo que as funcionalidades implementadas estão corretas. + +- **Facilidade de Manutenção**: Permite que mudanças no código sejam feitas com segurança, pois os testes verificam se as novas alterações não quebram funcionalidades existentes. + +- **Automação do Processo de Teste**: Com Jest, é possível automatizar a execução dos testes, economizando tempo e garantindo consistência. + +--- + +**Funcionalidades do Jest para Testar Funções e Módulos** + +- **Função test**: Define um caso de teste específico que verifica o comportamento de uma função ou módulo. + +- **Matcher expect**: Compara o resultado da função testada com o valor esperado. +Agrupamento com describe: Agrupa testes relacionados para melhor organização. + +- **Cobertura de Código**: Mede a quantidade de código que está sendo testada, incentivando uma cobertura mais completa. + +--- + +**Exemplo Simples: Testando Funções com Jest** + +Vamos começar com uma função simples que soma dois números. + +**Função (math.js):** +```bash +function soma(a, b) { + return a + b; +} + +module.exports = soma; +``` + +--- + +**Teste Unitário (math.test.js):** + +```bash +const soma = require('./math'); + +test('deve somar dois números corretamente', () => { + const resultado = soma(2, 3); + expect(resultado).toBe(5); +}); +} + +module.exports = soma; +``` + +Aqui, o Jest verifica se a função soma retorna o valor correto quando somamos 2 e 3. + +--- + +**Testando Módulos com Funções Múltiplas** + +Agora, vamos testar um módulo com múltiplas funções. + +**Módulo (calculadora.js):** + +```bash +function soma(a, b) { + return a + b; +} + +function multiplica(a, b) { + return a * b; +} + +module.exports = { soma, multiplica }; +``` +--- + +**Teste Unitário (calculadora.test.js):** + +```bash +const { soma, multiplica } = require('./calculadora'); + +describe('Funções de cálculo', () => { + test('deve somar dois números corretamente', () => { + expect(soma(4, 5)).toBe(9); + }); + + test('deve multiplicar dois números corretamente', () => { + expect(multiplica(3, 4)).toBe(12); + }); +}); +``` + +--- + +**Organização e Boas Práticas nos Testes** + + +**1. Use Nomes Descritivos**: Dê nomes claros para seus testes, para que fique evidente o que está sendo testado. + + +**2. Agrupe Testes Relacionados**: Utilize o bloco describe para organizar melhor os testes que verificam funções de um mesmo módulo. + + +**3. Teste Cenários Diferentes**: Valide tanto cenários de sucesso quanto situações onde a função pode falhar. + + +**4. Automatize a Execução dos Testes**: Configure scripts para rodar os testes sempre que houver mudanças no código. + +--- + +**Rodando os Testes com Jest** + +Para executar os testes, basta rodar o seguinte comando no terminal: + +```bash +npx jest +``` + +Esse comando busca todos os arquivos de teste no projeto e executa cada um, exibindo os resultados diretamente no terminal.",rw1732734177188ad5703,rw1732798064338e28dea,# Descomplicando Testes Unitários!,Attekita Dev,"[{""foreignRowId"":""rw1732798064338e28dea"",""foreignRowDisplayName"":""Nessa aula você aprenderá um pouco sobre testes unitários e sua importância, assim como sobre nossa ferramenta de testes, o JestJS.""}]",https://youtu.be/HcDJdKfm5nA?si=gH5KDOMpthzsVKJu,"[Funções de Simulação](https://jestjs.io/pt-BR/docs/mock-functions) +[Manual Mocks](https://jestjs.io/docs/manual-mocks)",Você irá criar e testar uma função que realiza uma requisição HTTP a uma API externa,rw17328104408179a988d,Testando uma Função com Dependências Externas +Cobertura de Código,Entenda a importância da cobertura de código e como utilizar ferramentas para medir e melhorar a qualidade dos seus testes.,Testes Unitários com Jest,"**Cobertura de Código: O Que É e Como Medir com Jest** + +Cobertura de código é uma métrica usada para determinar o quão bem o seu código foi testado. Ter uma boa cobertura de código ajuda a garantir que as partes críticas do sistema estão sendo testadas e que seu código é robusto e livre de erros. Este conteúdo explora as diferentes técnicas e ferramentas usadas para medir a cobertura de código, além de práticas recomendadas para alcançar uma cobertura eficiente sem exageros. + +--- + + +**O Que é Cobertura de Código?** + +Cobertura de código mede a quantidade de código que foi executada durante os testes automatizados. Ela fornece uma visão sobre quais partes do código estão sendo testadas e quais não estão. As métricas mais comuns de cobertura incluem: + + + +- **Cobertura de Linhas**: Percentual de linhas de código executadas. +- **Cobertura de Funções**: Percentual de funções testadas. +- **Cobertura de Condições**: Percentual de condições lógicas verificadas nos testes. + +--- + +**Por Que a Cobertura de Código é Importante?** + +- **Identificar Lacunas nos Testes**: Ajuda a perceber quais partes do código não estão sendo testadas, possibilitando melhorias nos testes. +- **Melhor Qualidade de Código**: Um código com boa cobertura tem menor chance de conter bugs ocultos. +- **Confiança no Sistema**: Com alta cobertura de código, você tem mais confiança de que o sistema se comportará como esperado. + +--- + + +**Ferramentas para Medir a Cobertura de Código** + +- **Jest (para JavaScript)**: Jest tem suporte embutido para cobertura de código e gera relatórios detalhados. +- **Istanbul/NYC**: Popular para JavaScript, permite gerar relatórios de cobertura. +- **JaCoCo**: Usado para medir a cobertura de código em aplicações Java. +- **Cobertura de Código em CI/CD**: Ferramentas como SonarQube e Codecov integram-se ao fluxo de CI/CD para gerar relatórios contínuos de cobertura. + +--- + +**Boas Práticas** + +- **Foque nas Funções Críticas**: Não é necessário ter 100% de cobertura, mas deve-se priorizar o teste das funções mais importantes. +- **Evite Testes Desnecessários**: Tentar atingir 100% de cobertura com testes triviais pode gerar falsos positivos e aumentar a manutenção do código. +- **Cobertura Não é o Único Indicador de Qualidade**: Embora importante, cobertura de código não garante que o código esteja livre de bugs. Focar apenas nela pode ser enganoso. + +--- + + +**Exemplo Prático de Cobertura de Código com Jest** + +Para medir a cobertura de código em um projeto usando Jest, siga os passos abaixo: + +**Código (calculator.js)** + +```javascript +// calculator.js +function add(a, b) { + return a + b; +} + +module.exports = { add }; + +// calculator.test.js +const { add } = require('./calculator'); + +test('deve somar dois números', () => { + expect(add(1, 2)).toBe(3); +}); + +``` + +--- + +**Rodando os Testes com Cobertura** + +Para rodar os testes e gerar o relatório de cobertura, execute o seguinte comando no terminal: + +```bash +npx jest --coverage +``` + + +O Jest irá executar os testes e gerar um relatório de cobertura de código. + +--- + +**Relatório de Cobertura** + +Ao rodar os testes com o comando acima, o Jest irá gerar um relatório detalhado sobre a cobertura do seu código. O relatório mostrará a porcentagem de código coberto pelos testes e informações adicionais, como quais linhas ou funções não foram testadas. + +--- + +**Exemplo de saída do relatório de cobertura no terminal:** + + +Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: 0.343s +Ran all test suites. + +--- +```bash +---------------|----------|----------|----------|----------|------------------- +File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s +---------------|----------|----------|----------|----------|------------------- +All files | 100% | 100% | 100% | 100% | + calculator.js | 100% | 100% | 100% | 100% | +---------------|----------|----------|----------|----------|------------------- +``` +--- + +No exemplo acima, vemos que o código está 100% coberto pelos testes, ou seja, todas as linhas, funções e condições foram testadas. + +--- + +Esse processo ajuda a garantir que seu código está sendo validado adequadamente, fornecendo confiança de que ele está funcionando conforme o esperado. +",rw1732734206416123fc2,rw173279845374308edfb,"# O que é cobertura de código (code coverage) e como calcular? ",Andre Okazaki,"[{""foreignRowId"":""rw173279845374308edfb"",""foreignRowDisplayName"":""Nessa aula você vai aprender o que é a cobertura de código (ou code coverage, em inglês), como funciona essa parada e como tirar um relatório do seu projeto direto no Visual Studio - e essa é a parte mais fácil.\n""}]",https://www.youtube.com/watch?v=hLT_ThViNdk,[Documentação do Jest sobre Cobertura de Código](https://jestjs.io/pt-BR/),O objetivo desta atividade é explorar como o Jest mede a cobertura de código em um projeto simples,rw1732811211638964415,Medindo a Cobertura de Código +O que é Deploy?,Descubra como as aplicações ganham vida e chegam até você! Entenda o que é deploy e como ele funciona.,Deploy,"**Deploy** é o processo de disponibilizar uma aplicação ou sistema de software em um ambiente de produção, tornando-o acessível aos usuários finais. Trata-se de uma etapa crítica que requer planejamento e execução cuidadosa para garantir o sucesso da aplicação. + +O deploy tem como principais objetivos e benefícios a **disponibilização da aplicação para os usuários**, permitindo que eles acessem e utilizem a solução desenvolvida. Além disso, ele possibilita a **atualização e implantação de novas versões**, entregando melhorias contínuas, correções de bugs e novos recursos, mantendo a aplicação competitiva e alinhada às necessidades do mercado. Outro ponto importante é a **garantia de estabilidade e confiabilidade**: um processo de deploy bem estruturado, preferencialmente automatizado, reduz erros e assegura que a aplicação funcione de maneira consistente. + +Também contribui diretamente para **melhorar a experiência do usuário**, já que ele terá acesso às últimas atualizações, aumentando a satisfação e a retenção. Por fim, ele **facilita a escalabilidade da infraestrutura**, permitindo que a aplicação suporte aumentos de demanda, e viabiliza a gestão de diferentes ambientes, como desenvolvimento, homologação e produção, assegurando um fluxo de trabalho organizado e seguro. + +**Tipos de Deploy Mais Comuns:** + +- **Deploy manual**: Realizado com intervenções humanas, mas propenso a erros. Ideal apenas para situações simples. + +- **Deploy automatizado**: Feito com ferramentas de automação, garante rapidez e precisão, além de suportar pipelines de integração e entrega contínua. + +- **Deploy em azul/verde (blue-green)**: Mantém duas versões da aplicação (uma ativa e outra em standby). Facilita a reversão em caso de problemas. + +- **Canary Release**: Uma nova versão é disponibilizada gradualmente para um pequeno grupo de usuários antes do lançamento completo. + +**Melhores Práticas:** + +- **Automatize sempre que possível** utilizando ferramentas de CI/CD (Continuous Integration/Continuous Deployment) para simplificar e acelerar o processo. + +- **Realize monitoramento constante** após o deploy para detectar possíveis falhas ou degradações de desempenho. + +- **Tenha um plano de rollback** para reverter rapidamente caso algo dê errado, minimizando o impacto nos usuários. +",rw17327343320856e374b,rw173048092353167cc2b,# Deploy // Dicionário do Programador,Código Fonte TV,"[{""foreignRowId"":""rw173048092353167cc2b"",""foreignRowDisplayName"":""Dicionário do Programador: é o quadro semanal onde o canal Código Fonte TV desvendam termos, tecnologias e palavras do incrível universo da programação! Neste vídeo, é explorado o tema Deploy. ""}]",https://www.youtube.com/watch?v=gJw7l2JKpuQ&ab_channel=C%C3%B3digoFonteTo que,,,, +PrismaORM,Prisma é um ORM (Object-Relational Mapper) de nova geração que visa simplificar e proteger a interação com bancos de dados.,Node.js,"Prisma é um ORM (Object-Relational Mapper) de nova geração que visa simplificar e proteger a interação com bancos de dados. Ele não é um ORM tradicional, pois se concentra em uma abordagem mais moderna e centrada no desenvolvedor. + + + +Ele funciona com base em um fluxo de trabalho simples e poderoso: + +Defina (Prisma Schema): Você descreve a estrutura do seu banco de dados (modelos, campos e relações) em um único arquivo chamado `schema.prisma`. Esta é a sua fonte única da verdade. + +Sincronize (Prisma Migrate): Com um comando, o Prisma compara seu schema com o banco de dados e gera automaticamente o SQL para aplicar qualquer mudança, mantendo tudo em sincronia. + +Interaja (Prisma Client): O Prisma gera uma API de queries totalmente type-safe e com auto-complete, feita sob medida para o seu schema. Isso permite que você escreva consultas no seu código de forma intuitiva, prevenindo bugs antes mesmo de rodar a aplicação. + +",rw175068136549736a7ee,rw1750684131708558731,# Vincular Node.js com Express ao PostgreSQL via Prisma,Dev. Odair Michael,"[{""foreignRowId"":""rw1750684131708558731"",""foreignRowDisplayName"":""Nesta aula você vai aprender a vincular o Node.js com Express ao PostgreSQL via Prisma""}]",https://www.youtube.com/watch?v=69cMbxc06nk,[Documentação do Prisma - para que serve e como utilizar](https://www.prisma.io/docs/orm),"Como Configurar a Conexão com o Banco, Gerar o Cliente e Modelar os Dados da Aplicação , A partir de agora você vai aprenderá como realizar as quatro operações fundamentais de banco de dados CRUD: Create (Criar), Read (Ler), Update (Atualizar) e Delete (Deletar) utilizando o Prisma ORM, Neste exercício você vai criar sua primeira tabela em um banco de dados sem escrever uma única linha de código SQL utilizando o Prisma Migrate","rw1749913231498b36ede,rw17507690657455f92cf,rw1750769620065527d4b","Modelagem do banco,Criando o primeiro CRUD com PrismaORM,Prisma Migrate e Prisma Client" +Fundamentos(typescript Fundamentos),Exercícios complementares referentes ao tópico de fundamentos,Exercícios Adicionais,"Aqui verá exercícios com dificuldades variadas, simplificando e aprofundando o tópico de Fundamentos(typescript Fundamentos)",rw175147221097169153e,,,,,,[Tópico de Fundamentos(Typescript Fundamentos)](https://staging--e-acelera-homologacao.netlify.app/nivelamento/rw17169041087560470c1-TypeScript:%20Fundamentos/rw1721236357157ccf465-Fundamentos),"Primeiro exercício da lista com o objetivo de aprofundar o aprendizado, Segundo exercício da lista com o objetivo de aprofundar o aprendizado","rw1751481256893111248,rw1751550527376edcf02","Soma dobrada,Contador ocorrência" +Condicionais (Typescript: Lógica de Programação),Exercícios adicionais referente ao tópico de Condicionais,Exercícios Adicionais,"Aqui verá exercícios com dificuldades variadas, simplificando e aprofundando o tópico de Condicionais (Typescript: Lógica de Programação)",rw1751472269115737a43,,,,,,[Tópico de Condicionais(Typescript: Lógica de programação)](https://staging--e-acelera-homologacao.netlify.app/nivelamento/rw1720014886324a56ac2-TypeScript:%20Lógica%20de%20Programação/rw17212367802520ba251-Condicionais),"Primeiro exercício da lista com o objetivo de aprofundar o aprendizado, Segundo exercício da lista com o objetivo de aprofundar o aprendizado, Terceiro exercício da lista com o objetivo de aprofundar o aprendizado, Quarto exercício da lista com o objetivo de aprofundar o aprendizado, Quinto exercício da lista com o objetivo de aprofundar o aprendizado, Sexto exercício da lista com o objetivo de aprofundar o aprendizado, Sétimo exercício da lista com o objetivo de aprofundar o aprendizado, Oitavo exercício da lista com o objetivo de aprofundar o aprendizado, Nono exercício da lista com o objetivo de aprofundar o aprendizado","rw17515525189894c60af,rw1751552572795b6b20e,rw1751552688513b36111,rw17515527172787e011c,rw1751552757468282e36,rw175155278352465b47e,rw1751552821533df6b2b,rw1751552848491ebd141,rw1751552876958039585","Soma maior 50,Positivo negativo ou nulo,Menor e maior valor,Par ou impar ,Múltiplo de 3, Divisibilidade entre dois números,Soma com ajuste,Maior e menor valor de quatro números, Ordem descendente" +Array simples (Typescript: Lógica de Programação),Exercícios adicionais referente ao tópico de Array simples,Exercícios Adicionais," Aqui verá exercícios com dificuldades variadas, simplificando e aprofundando o tópico de Array simples (Typescript: Lógica de Programação)",rw17514730654126505cd,,,,,,[Tópico de Array Simples(Typescript: Lógica de programação)](https://staging--e-acelera-homologacao.netlify.app/nivelamento/rw1720014886324a56ac2-TypeScript:%20Lógica%20de%20Programação/rw1727203515904ad3fa2-Array%20Simples),"Primeiro exercício da lista com o objetivo de aprofundar o aprendizado, Segundo exercício da lista com o objetivo de aprofundar o aprendizado, Terceiro exercício da lista com o objetivo de aprofundar o aprendizado, Quarto exercício da lista com o objetivo de aprofundar o aprendizado","rw1751553325597a32e1b,rw1751553389129395eda,rw1751553414853317534,rw17515535995444bdcb3"," Vetores positivos negativos,Vetor invertido,Notas faixa,Loja de artesanato vendas" +Repetição (Typescript: Lógica de Programação),Exercícios adicionais referente ao tópico de Repetição,Exercícios Adicionais,"Aqui verá exercícios com dificuldades variadas, simplificando e aprofundando o tópico de Repetição (Typescript: Lógica de Programação)",rw175154749268307462c,,,,,,[Tópico de Repetição(Typescript:Fundamentos)](https://staging--e-acelera-homologacao.netlify.app/nivelamento/rw1720014886324a56ac2-TypeScript:%20Lógica%20de%20Programação/rw1726765151047cfa7ec-Repetição),"Primeiro exercício da lista com o objetivo de aprofundar o aprendizado, Segundo exercício da lista com o objetivo de aprofundar o aprendizado, Terceiro exercício da lista com o objetivo de aprofundar o aprendizado, Quarto exercício da lista com o objetivo de aprofundar o aprendizado, Quinto exercício da lista com o objetivo de aprofundar o aprendizado.","rw1751553822823df99a1,rw17515539124722dfb74,rw1751554432252955c80,rw1751554459322694909,rw1751554485263b2fea7","Exibir números de 0 a 40, Exibir números ímpares entre M e N,Mostrar o maior valor digitado,Soma de intervalos, Conversão de polegadas para centímetros" +Métodos map filter e sort,Uso de map filter sort e reduce para manipular listas,TypeScript: Lógica de Programação,"​**Métodos map filter e sort em TypeScript** + + + +Os métodos map filter sort e reduce ajudam a manipular listas de forma moderna e funcional em TypeScript. Com eles é possível transformar filtrar ordenar e resumir informações sem a necessidade de laços tradicionais. Esses métodos tornam o código mais legível conciso e declarativo + + + + + +**map** + + + +O método map percorre cada item da lista e retorna uma nova lista com os elementos transformados de acordo com a função aplicada + + +```ts + +const numeros = [1, 2, 3]; + +const dobrados = numeros.map(n => n * 2); + +console.log(dobrados); // [2, 4, 6] + +``` + + + +**filter** + + + +O método filter seleciona os itens de uma lista com base em uma condição retornando apenas os que satisfazem essa condição + + + +```ts + +const idades = [17, 18, 21]; + +const maiores = idades.filter(i => i >= 18); + +console.log(maiores); // [18, 21] + +``` + +**sort** + + + +O método sort ordena os elementos da lista. Para ordenar números corretamente é necessário passar uma função de comparação + + + +```ts + +const idades = [17, 18, 21]; + + +const ordenadas = idades.sort((a, b) => a - b); + + +console.log(ordenadas); // [17, 18, 21] + +``` + + + +**reduce** + + + +O método reduce acumula os valores da lista e os reduz a um único resultado. Por exemplo somar todos os valores + + + +```ts + +const notas = [8, 7, 6]; + +const soma = notas.reduce((acc, atual) => acc + atual, 0); + +console.log(soma); // 21 + +``` + + + +**Encadeando métodos** + + + +Os métodos podem ser usados juntos. No exemplo abaixo filtramos quem é do setor financeiro aplicamos aumento e somamos os salários + + + +```ts + +const funcionarios = [ + + { nome: 'Ana', setor: 'Financeiro', salario: 2000 }, + + { nome: 'João', setor: 'Marketing', salario: 1800 }, + + { nome: 'Maria', setor: 'Financeiro', salario: 2500 } + +]; + + + +const total = funcionarios + + .filter(f => f.setor === 'Financeiro') + + .map(f => f.salario * 1.5) + + .reduce((soma, sal) => soma + sal, 0); + + + +console.log(total); // 6750 + +``` + + + +**Quando usar cada método** + + + +- **map:** use quando quiser transformar cada item de uma lista. Ele retorna uma **nova lista** + +- **filter:** use para manter apenas os itens que atendem a uma condição. Também retorna uma **nova lista** + +- **sort:** ideal para ordenar itens. Ele **modifica a lista original** + +- **reduce:** indicado para gerar um **único valor final** a partir de todos os itens da lista, como somar ou calcular média + +​ +",rw17515517780331570b6,rw17515527172509dcf4c,# Como usar map reduce e filter na prática com JavaScript,DevClub | Programação,"[{""foreignRowId"":""rw17515527172509dcf4c"",""foreignRowDisplayName"":""Neste vídeo você aprende de forma simples e direta como funcionam os métodos map, filter e reduce em JavaScript. Com exemplos visuais e didáticos, o instrutor mostra como aplicar esses métodos para transformar, filtrar e reduzir listas de forma mais prática e moderna\n\n""}]",https://www.youtube.com/watch?v=Ar2cMgpjkLM,"[Documentação oficial do map (MDN)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/map) + + + +[Documentação oficial do filter (MDN)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) + + + +[Documentação oficial do sort (MDN)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) + + + +[Documentação oficial do reduce (MDN)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) + + + +[Artigo HCode: Conhecendo map, filter e reduce](https://hcode.com.br/blog/conhecendo-map-filter-reduce-em-javascript) + + + +[Vídeo: Entenda map, filter e reduce na prática (DevSuperior)](https://www.youtube.com/watch?v=ZYPQmfcZGxg) + + + +[Vídeo: Métodos de array explicados de forma simples (DevClub)](https://www.youtube.com/watch?v=Ar2cMgpjkLM) + + + +","Guia com os passos necessários para realizar as atividades corretamente, Nesta atividade, você irá retornar um objeto com as informações das alunas aprovadas, Nesta atividade, você irá retornar o nome da aluna com a menor nota","rw175208044431077ed1e,rw17549300132192ebb02,rw1755092831407e570c5,rw1755093112006fb018e","Instruções importantes,Retornar nomes das aprovadas,Retornar objeto com as informações das alunas,Retornar a aluna com menor nota" +Operador Ternário,Operadores Ternários em TypeScript exploraremos a sintaxe e os benefícios desse operador que simplifica decisões condicionais em uma única linha de código.,TypeScript: Lógica de Programação,"Operadores Ternários em TypeScript, exploraremos a sintaxe e os benefícios desse operador, que simplifica decisões condicionais em uma única linha de código. Veremos como ele pode ser uma alternativa eficiente ao uso de `if-else`, tornando o código mais enxuto e legível. Abordaremos como aplicá-lo em situações práticas, como atribuição de valores com base em condições, retorno de funções e outras operações lógicas. O objetivo é mostrar como o uso adequado do operador ternário melhora a clareza e a eficiência do código em cenários do dia a dia. + +**Operador ternário** + +Permite a avaliação de uma condição e a escolha entre duas expressões com base nessa condição, tudo em uma única linha de código. Veja um exemplo: + +```typescript +let idade: number = 18; +let resultado = idade >= 18 ? ""Adulto"" : ""Menor de idade""; +console.log(resultado); +``` + +Neste exemplo, a variável resultado recebe o valor ""Adulto"" se idade for maior ou igual a 18; caso contrário, recebe o valor ""Menor de idade"". +",rw17267746000309152e6,rw1727181976096a054ca,"# Operador Ternário (O ""economizador"" de linhas de código)",Código Fonte TV,"[{""foreignRowId"":""rw1727181976096a054ca"",""foreignRowDisplayName"":""No vídeo de hoje, vamos explorar como utilizar o operador ternário de maneira eficaz em suas aplicações. Vamos ver exemplos práticos que mostram como ele pode substituir estruturas condicionais mais longas, ajudando a manter seu código limpo e direto.""}]",https://www.youtube.com/watch?v=YjEtiFi2k7g,"[MDN Web Docs - Operador Condicional (Ternário)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/Conditional_operator) + +",,, +Array Simples,Arrays em TypeScript permitem armazenar e manipular dados de forma organizada com suporte para tipos estáticos propriedades anuláveis e métodos como propriedades de objetos.,TypeScript: Lógica de Programação,"Arrays Simples e Arrays de Objetos em TypeScript permitem armazenar múltiplos valores de um mesmo tipo ou objetos organizados. Em TypeScript, é possível definir o tipo dos elementos para garantir a consistência dos dados. Além disso, o uso de **propriedades anuláveis (nullable)** permite que alguns elementos do array possam ser `null` ou `undefined`, trazendo mais flexibilidade ao código. Métodos podem ser definidos como propriedades de objetos dentro dos arrays, permitindo funcionalidades adicionais. + + +Aqui estão alguns exercícios com **Arrays Simples** e **Arrays de Objetos**: + +### 1. Array Simples - Listando números pares + +```typescript +let numeros: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + +function listarPares(arr: number[]): number[] { + return arr.filter(num => num % 2 === 0); +} + +console.log(listarPares(numeros)); // Saída: [2, 4, 6, 8, 10] +``` + +Neste exemplo, o array `numeros` contém números de 1 a 10 e a função `listarPares` filtra e retorna apenas os números pares. + +### 2. Array Simples - Somando todos os valores + +```typescript +let numeros: number[] = [5, 10, 15, 20]; + +function somarArray(arr: number[]): number { + return arr.reduce((acumulador, valorAtual) => acumulador + valorAtual, 0); +} + +console.log(somarArray(numeros)); // Saída: 50 +``` + +Aqui, a função `somarArray` utiliza o método `reduce` para somar todos os valores no array. + +--- + +### 3. Array de Objetos - Listando nomes de membros + +```typescript +type Membro = { + nome: string; + idade: number; +}; + +let membros: Membro[] = [ + { nome: ""Ana"", idade: 25 }, + { nome: ""Carlos"", idade: 30 }, + { nome: ""Bruna"", idade: 22 } +]; + +function listarNomes(arr: Membro[]): string[] { + return arr.map(membro => membro.nome); +} + +console.log(listarNomes(membros)); // Saída: ['Ana', 'Carlos', 'Bruna'] +``` + +Neste exercício, o array `membros` contém objetos com `nome` e `idade`, e a função `listarNomes` retorna um array com os nomes. + +### 4. Array de Objetos - Filtrando por idade + +```typescript +type Membro = { + nome: string; + idade: number; +}; + +let membros: Membro[] = [ + { nome: ""Ana"", idade: 25 }, + { nome: ""Carlos"", idade: 30 }, + { nome: ""Bruna"", idade: 22 } +]; + +function membrosMaioresDe25(arr: Membro[]): Membro[] { + return arr.filter(membro => membro.idade > 25); +} + +console.log(membrosMaioresDe25(membros)); // Saída: [{ nome: 'Carlos', idade: 30 }] +``` + +A função `membrosMaioresDe25` retorna os membros cuja idade é maior que 25. + +--- + +### 5. Array de Objetos - Atualizando a idade de um membro + +```typescript +type Membro = { + nome: string; + idade: number; +}; + +let usuarios: Membro[] = [ + { nome: ""Ana"", idade: 25 }, + { nome: ""Carlos"", idade: 30 }, + { nome: ""Bruna"", idade: 22 } +]; + +function atualizarIdade(arr: Membro[], nome: string, novaIdade: number): Membro[] { + return arr.map(membro => { + if (membro.nome === nome) { + return { ...membro, idade: novaIdade }; + } + return membro; + }); +} + +console.log(atualizarIdade(membros, ""Ana"", 26)); +// Saída: [{ nome: 'Ana', idade: 26 }, { nome: 'Carlos', idade: 30 }, { nome: 'Bruna', idade: 22 }] +``` + +Aqui, a função `atualizarIdade` busca pelo nome no array de membros e atualiza a idade do membro correspondente. +",rw1727203515904ad3fa2,rw1727182071303ae95a8,# Arrays simples de objetos,CodeTotal,"[{""foreignRowId"":""rw1727182071303ae95a8"",""foreignRowDisplayName"":""Neste vídeo, você aprenderá conceitos básicos sobre a utilização de Arrays simples e Arrays de objetos no JavaScript utilizando TypeScript.\n\nSerão abordados alguns tópicos, a exemplo:\n\n- Como declarar e manipular Arrays simples;\n- Como trabalhar com Arrays de objetos;\n- O uso de propriedades anuláveis (nullable) para evitar erros em casos onde valores podem ser `null` ou `undefined`;\n- Métodos como propriedades, permitindo que funções sejam atribuídas diretamente aos objetos e acessadas como qualquer outra propriedade.\n\nEste conteúdo é essencial para quem deseja aprofundar o uso de Arrays e melhorar a segurança e a estruturação do código em TypeScript.\n""}]",https://www.youtube.com/watch?v=mY_bJ9R-0bI," [Curso TypeScript - Arrays e Tuplas](https://jornadadodev.com.br/cursos/front-end/typescript/arrays-e-tuplas) + [Array.prototype.map() - MDN](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/map) +[Array.prototype.filter() - MDN](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) ","Guia com os passos necessários para realizar as atividades corretamente, Primeiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Segundo exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Terceiro exercício da lista com o objetivo de garantir que o teste seja bem-sucedido, Quarto exercício da lista com o objetivo de garantir que o teste seja bem-sucedido","rw17278857951789628d4,rw1727886436829261856,rw1727886940271b774a5,rw1727887740711bbc6c1,rw1727887863868c37cc0","Instruções importantes, Vetor pares dobro e impares triplo,Intercalação vetores,Produtos e lucros,Pontuação do concurso" +Métodos map filter e sort,Uso de map filter sort e reduce para manipular listas,TypeScript: Lógica de Programação,"​**Métodos map filter e sort em TypeScript** + + + +Os métodos map filter sort e reduce ajudam a manipular listas de forma moderna e funcional em TypeScript. Com eles é possível transformar filtrar ordenar e resumir informações sem a necessidade de laços tradicionais. Esses métodos tornam o código mais legível conciso e declarativo + + + + + +**map** + + + +O método map percorre cada item da lista e retorna uma nova lista com os elementos transformados de acordo com a função aplicada + + +```ts + +const numeros = [1, 2, 3]; + +const dobrados = numeros.map(n => n * 2); + +console.log(dobrados); // [2, 4, 6] + +``` + + + +**filter** + + + +O método filter seleciona os itens de uma lista com base em uma condição retornando apenas os que satisfazem essa condição + + + +```ts + +const idades = [17, 18, 21]; + +const maiores = idades.filter(i => i >= 18); + +console.log(maiores); // [18, 21] + +``` + +**sort** + + + +O método sort ordena os elementos da lista. Para ordenar números corretamente é necessário passar uma função de comparação + + + +```ts + +const idades = [17, 18, 21]; + + +const ordenadas = idades.sort((a, b) => a - b); + + +console.log(ordenadas); // [17, 18, 21] + +``` + + + +**reduce** + + + +O método reduce acumula os valores da lista e os reduz a um único resultado. Por exemplo somar todos os valores + + + +```ts + +const notas = [8, 7, 6]; + +const soma = notas.reduce((acc, atual) => acc + atual, 0); + +console.log(soma); // 21 + +``` + + + +**Encadeando métodos** + + + +Os métodos podem ser usados juntos. No exemplo abaixo filtramos quem é do setor financeiro aplicamos aumento e somamos os salários + + + +```ts + +const funcionarios = [ + + { nome: 'Ana', setor: 'Financeiro', salario: 2000 }, + + { nome: 'João', setor: 'Marketing', salario: 1800 }, + + { nome: 'Maria', setor: 'Financeiro', salario: 2500 } + +]; + + + +const total = funcionarios + + .filter(f => f.setor === 'Financeiro') + + .map(f => f.salario * 1.5) + + .reduce((soma, sal) => soma + sal, 0); + + + +console.log(total); // 6750 + +``` + + + +**Quando usar cada método** + + + +- **map:** use quando quiser transformar cada item de uma lista. Ele retorna uma **nova lista** + +- **filter:** use para manter apenas os itens que atendem a uma condição. Também retorna uma **nova lista** + +- **sort:** ideal para ordenar itens. Ele **modifica a lista original** + +- **reduce:** indicado para gerar um **único valor final** a partir de todos os itens da lista, como somar ou calcular média + +​ +",rw17515517780331570b6,rw17515527172509dcf4c,# Como usar map reduce e filter na prática com JavaScript,DevClub | Programação,"[{""foreignRowId"":""rw17515527172509dcf4c"",""foreignRowDisplayName"":""Neste vídeo você aprende de forma simples e direta como funcionam os métodos map, filter e reduce em JavaScript. Com exemplos visuais e didáticos, o instrutor mostra como aplicar esses métodos para transformar, filtrar e reduzir listas de forma mais prática e moderna\n\n""}]",https://www.youtube.com/watch?v=Ar2cMgpjkLM,"[Documentação oficial do map (MDN)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/map) + + + +[Documentação oficial do filter (MDN)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) + + + +[Documentação oficial do sort (MDN)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) + + + +[Documentação oficial do reduce (MDN)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) + + + +[Artigo HCode: Conhecendo map, filter e reduce](https://hcode.com.br/blog/conhecendo-map-filter-reduce-em-javascript) + + + +[Vídeo: Entenda map, filter e reduce na prática (DevSuperior)](https://www.youtube.com/watch?v=ZYPQmfcZGxg) + + + +[Vídeo: Métodos de array explicados de forma simples (DevClub)](https://www.youtube.com/watch?v=Ar2cMgpjkLM) + + + +","Guia com os passos necessários para realizar as atividades corretamente, Nesta atividade, você irá retornar um objeto com as informações das alunas aprovadas, Nesta atividade, você irá retornar o nome da aluna com a menor nota","rw175208044431077ed1e,rw17549300132192ebb02,rw1755092831407e570c5,rw1755093112006fb018e","Instruções importantes,Retornar nomes das aprovadas,Retornar objeto com as informações das alunas,Retornar a aluna com menor nota" +Benefícios da Refatoração,Refatoração melhora legibilidade reutilização reduz erros e facilita a manutenção do código.,TypeScript: Refatoração,"A refatoração em TypeScript traz diversos benefícios, tanto para a qualidade do código quanto para a eficiência do desenvolvimento. Aqui estão alguns dos principais: + +**Legibilidade:** Código limpo e organizado facilita a compreensão por outros desenvolvedores, além de melhorar o fluxo de leitura. +**Reutilização:** Ao modularizar o código, fica mais fácil reutilizar funções e componentes em diferentes partes do projeto. +**Redução de Erros:** Ao remover duplicações e melhorar a lógica, você diminui as chances de introduzir erros. +**Facilidade de Manutenção:** Um código bem organizado e claro facilita a compreensão e a correção de problemas durante o ciclo de vida do projeto. +**Desempenho:** Refatorar pode melhorar a eficiência do código, resultando em melhor performance da aplicação, especialmente em trechos críticos. +**Testabilidade:** Código mais limpo e modular é mais fácil de testar, tanto manualmente quanto por meio de testes automatizados, o que melhora a qualidade geral do software. +**Escalabilidade:** Um código bem estruturado e otimizado torna-se mais fácil de escalar à medida que o projeto cresce, facilitando a adição de novas funcionalidades. +**Redução de Dívida Técnica:** Refatorar regularmente evita o acúmulo de soluções improvisadas e ""gambiarras"", reduzindo a dívida técnica ao longo do tempo.",rw17267632624582fe2e7,rw1727961920967e41be3,# Refatoração - Dicionário do Programador,Código Fonte TV,"[{""foreignRowId"":""rw1727961920967e41be3"",""foreignRowDisplayName"":""Neste vídeo você aprenderá o que é refatoração, seus principais benefícios e como deixar o seu código mais limpo.""}]",https://www.youtube.com/watch?v=VOxnyVI2lOc&ab_channel=CódigoFonteTV,[Refatoração - Dicionário do Programador](https://www.youtube.com/watch?v=VOxnyVI2lOc),,, +Principais Técnicas de Refatoração em TypeScript,Técnicas de refatoração em TypeScript melhoram a clareza do código e tornam a manutenção mais fácil.,TypeScript: Refatoração,"As principais técnicas de refatoração em TypeScript ajudam a manter o código mais limpo, eficiente e de fácil manutenção. Aqui estão algumas frequentemente utilizadas: + +**1. Extrair Funções** + +Quando você percebe que um bloco de código está se repetindo ou que uma função está fazendo várias coisas ao mesmo tempo, considere extrair parte desse código em funções menores. Isso aumenta a clareza e a modularidade. + +Exemplo antes da refatoração: + +``` typescript +function processUser(user: any) { + console.log(user.name); + console.log(user.age); + + // Validação + if (!user.name || !user.age) { + throw new Error(""Invalid data""); + } + // Processamento + user.isActive = true; +} +``` +Após a refatoração: +```typescript +function validateUser(user: any) { + if (!user.name || !user.age) { + throw new Error(""Invalid data""); + } +} + +function activateUser(user: any) { + user.isActive = true; +} + +function processUser(user: any) { + console.log(user.name); + console.log(user.age); + validateUser(user); + activateUser(user); +} +``` +**2. Renomear Variáveis** + +Escolher nomes descritivos para variáveis, funções e classes ajuda a tornar o código mais autodescritivo, evitando comentários desnecessários. Se uma variável chamada a não faz sentido, renomeie-a para algo mais significativo. + +Exemplo: +``` typescript +let a = 0; // O que é ""a""? +``` +Após a refatoração: +```typescript +let totalUsers = 0; +``` +**3. Evitar Duplicação de Código** + +Se você identificar que o mesmo trecho de código está sendo usado em vários lugares, considere extrair esse código em uma função reutilizável. + +Exemplo antes da refatoração: + +``` typescript +let user1 = { name: ""Alice"", age: 25 }; +console.log(user1.name); +console.log(user1.age); + +let user2 = { name: ""Bob"", age: 30 }; +console.log(user2.name); +console.log(user2.age); +``` + +Após a refatoração: +``` typescript +function logUserInfo(user: { name: string, age: number }) { + console.log(user.name); + console.log(user.age); +} + +let user1 = { name: ""Alice"", age: 25 }; +let user2 = { name: ""Bob"", age: 30 }; + +logUserInfo(user1); +logUserInfo(user2); +``` + +**4. Utilizar Tipagem Apropriada** + +TypeScript permite que você defina tipos explícitos para seus dados, o que ajuda a garantir que o código seja mais seguro e previsível. Se você está lidando com objetos complexos, considere criar tipos ou interfaces que representem esses dados. + +Exemplo antes da refatoração: +``` typescript +function getUserData(user: any) { + return user.name + "" is "" + user.age + "" years old""; +} +``` +Após a refatoração: +``` typescript +interface User { + name: string; + age: number; +} + +function getUserData(user: User) { + return `${user.name} is ${user.age} years old`; +} +``` + +**5. Simplificar Condicionais** + +Condicionais longas podem se tornar difíceis de ler e manter. Sempre que possível, simplifique-as. + +Exemplo antes da refatoração: +``` typescript +if (user.age > 18) { + if (user.isActive) { + return true; + } else { + return false; + } +} else { + return false; +} +``` +Após a refatoração: +``` typescript +return user.age > 18 && user.isActive; +```",rw17267635193113866b5,rw172676310522712900a,"# Refatoração Funcional ",Otávio Lemos,"[{""foreignRowId"":""rw172676310522712900a"",""foreignRowDisplayName"":""Neste vídeo você aprenderá a fazer Refatoração Funcional em TypeScript.""}]",https://www.youtube.com/watch?v=Hef59LiR8-0,[Refatoração em TypeScript](https://www.youtube.com/watch?v=Hef59LiR8-0),Primeiro exercício da lista com objetivo de fixar os conceitos da refatoração em TypeScript,rw172795995480204cc77,Refatorando Arrays \ No newline at end of file diff --git a/prisma/data/videos.csv b/prisma/data/videos.csv new file mode 100644 index 0000000..9191b14 --- /dev/null +++ b/prisma/data/videos.csv @@ -0,0 +1,155 @@ +title,description,references,link,topics,idVideos +# Guia definitivo de Aprendendo a Aprender,"O vídeo é um guia detalhado sobre técnicas e estratégias para melhorar a aprendizagem. Aborda tópicos como: entendendo o funcionamento do cérebro, técnicas de memorização, estratégias de estudo, motivação, disciplina e erros comuns.",Fabio Akita,https://www.youtube.com/watch?v=oUPaJxk6TZ0,Aprenda a aprender,rw1719238213648dc3250 +# Como posso estudar melhor?,"O vídeo apresenta dicas para melhorar a organização nos estudos, destacando a importância de estabelecer compromissos semanais, como em compromissos sociais, e utilizar uma agenda ou calendário para planejar horários específicos para cada disciplina. Sugere evitar o estudo intenso de última hora, espaçando o aprendizado para melhor retenção, e alternar entre momentos de foco e relaxamento para consolidar o conhecimento.",Alura,https://www.youtube.com/watch?v=Is6c9KSGCbk,Como posso estudar melhor,rw171802568549384bdc9 +# Como estudo programação?,"O vídeo aborda tópicos importantes para ajuda na hora do estudo sobre programação +Organização, Métodos de Estudo, Ambiente de Estudo. Autoconhecimento, Estudo de Programação e Motivação e Produtividade.",Rafaella Ballerini,https://www.youtube.com/watch?v=Xfgc3ZDtwTQ,Como estudo programação,rw171802568547809418e +# Como posso aprender a programar?,"Para quem está começando no mundo da programação, uma das principais dúvidas são: **por onde começar?** Neste vídeo, Gabs Ferreira e Paulo Silveira compartilham dicas valiosas sobre como dar os primeiros passos nesse universo.",Alura,https://www.youtube.com/watch?v=MwCx2qKdbDw,Como posso aprender a programar?,rw171802568550836053b +# 3 Técnicas que eu uso para aprender a programar qualquer coisa,"Neste vídeo, são apresentadas técnicas fundamentais para aprender programação, mesmo para aquelas pessoas que não se consideram naturalmente talentosas nessa área. ",Filipe Deschamps,https://www.youtube.com/watch?v=ZtMzB5CoekE,Técnicas para aprender a programar,rw17180256855225581f7 +# Veja como instalar VS Code,"Nesse vídeo, vemos o simples passo a passo para instalar no seu Windows o Visual Studio Code, um dos editores de código mais populares entre desenvolvedores. O VS Code oferece uma ampla variedade de extensões e ferramentas para programação em diversas linguagens, tornando o ambiente de desenvolvimento ágil e eficiente.",Ativs Code,https://www.youtube.com/watch?v=QT-YWT1-YI4,Instalar Visual Studio Code,rw1720197669951f72e18 +# 20 Extensões VS Code para otimizar seu tempo na programação,"Neste vídeo, você aprenderá a instalar 20 extensões essenciais no Visual Studio Code para maximizar sua produtividade e personalizar seu ambiente de desenvolvimento. Cada extensão é explicada brevemente, destacando suas funcionalidades e como podem facilitar seu fluxo de trabalho.",Hero Code,https://www.youtube.com/watch?v=7P2idkQBZws,Extensões no Visual Studio Code,rw1720199151690506d7d +# Instalando o PostgreSQL e pgAdmin no Linux Ubuntu,Nesse vídeo vemos o simples passo a passo para instalar o PostgreSQL e a interface de usuário PgAdmin 4. Postgres é um dos ambientes SQL mais utilizados em todo o mundo.,José Ailton TI,https://www.youtube.com/watch?v=1jSb4LJH1dw,Instalação para Linux,rw1720441083154060eaf +# Curso de Typescript - Operadores,"Neste vídeo, será explorado o uso dos operadores em TypeScript. Serão abordados os operadores matemáticos, operadores de atribuição de valores, operadores de comparação e os operadores lógicos. O objetivo é mostrar como esses conceitos funcionam na prática e como podem ser aplicados no código em TypeScript.",Filipe Morelli Developer,https://www.youtube.com/watch?v=nqM6wDp47Sw,Operadores,rw1725556521808c8761e +# Tipos de variáveis,"Abordagem sobre o uso de tipos em TypeScript, destacando a inclusão de tipos numéricos, booleanos e strings (incluindo template strings). Também explora arrays, tuplas e enumerações, explicando suas funcionalidades e diferenças em relação ao JavaScript. A explicação inclui exemplos práticos de código e a importância do uso de let para definir variáveis com escopo limitado.",William Suane | DevDojo,https://www.youtube.com/watch?v=rCKvrhLRFLE,Tipos de variáveis,rw1725557273503aeca0c +# Curso de TypeScript para iniciantes,"Este guia abrange os principais aspectos do TypeScript, começando com uma introdução aos seus fundamentos, onde são apresentados os conceitos básicos que diferenciam o TypeScript do JavaScript, especialmente no que se refere à tipagem estática. Em seguida, são fornecidas instruções detalhadas sobre como instalar e configurar o TS em diferentes ambientes de desenvolvimento. Além de explorar os tipos básicos e interfaces disponíveis na linguagem. Este conteúdo é ideal para quem deseja adquirir uma compreensão sólida e abrangente do TypeScript, abordando desde os conceitos iniciais até as funcionalidades mais avançadas.",Dimitri Teixeira | Programação Web,https://www.youtube.com/watch?v=svUEOLz-tms,Fundamentos,rw1725630408780f28e7a +# Como Instalar o PostgreSQL no Windows,"Neste vídeo, você aprenderá de forma rápida e direta como fazer a instalação do PostgreSQL no Windows.",Rogério Napoleão Jr,https://www.youtube.com/watch?v=UbX-2Xud1JA,Instalação para Windows,rw17256336124819cd8eb +# Como instalar o PostgreSQL no Mac,"Neste vídeo, você aprenderá de forma rápida e direta como fazer a instalação do PostgreSQL no Mac .",Programming Knowledge,https://www.youtube.com/watch?v=PShGF_udSpk,Instalação para macOS,rw17256341835236ba28a +# Refatoração Funcional,Neste vídeo você aprenderá a fazer Refatoração Funcional em TypeScript.,Otávio Lemos,https://www.youtube.com/watch?v=Hef59LiR8-0,Principais Técnicas de Refatoração em TypeScript,rw172676310522712900a +# Estrutura Condicional,"Neste vídeo, você aprenderá a usar as estruturas condicionais. + +As principais estruturas condicionais em programação são: + +1. **if**: Executa um bloco de código se a condição for verdadeira. +2. **else**: Executa um bloco de código se a condição do `if` for falsa. +3. **else if**: Verifica múltiplas condições, permitindo testar mais de uma condição antes de executar o bloco `else`. +4. **switch**: Usado para executar diferentes blocos de código com base no valor de uma variável. + +Entenda como e quando utilizar cada uma delas para tomar decisões em seu código! +",Filipe Morelli Developer,https://www.youtube.com/watch?v=bbYbgiD1XyM,Condicionais,rw17271015159244bf9b2 +# Estrutura de Repetição,"Neste vídeo, você aprenderá a usar as estruturas de repetição. + +As principais estruturas de repetição em programação são: + +1. **for**: Utilizada quando o número de iterações é conhecido. +2. **while**: Usada quando o número de iterações não é conhecido e depende de uma condição. +3. **do...while**: Semelhante ao `while`, mas garante que o bloco de código seja executado pelo menos uma vez. + +Explore cada uma delas para entender suas aplicações! +",Filipe Morelli Developer,https://www.youtube.com/watch?v=LC1-rDSI004,Repetição,rw17271020082434a6bb8 +# Funções,"Neste vídeo, você aprenderá a usar funções em TypeScript. + +Funções são blocos de código reutilizáveis que executam uma tarefa específica. ",Daniel Berg,https://www.youtube.com/watch?v=iSFxyGsXMpI,"Funções ",rw17271128247767b3c39 +# O que é o tal do Algoritmo?,No vídeo são exploradas essas questões e desvendar como o entendimento e o domínio dos algoritmos podem fazer toda a diferença na sua jornada como pessoa programadora. Mergulhe nesse universo e entenda por que os algoritmos estão por trás de tantas inovações tecnológicas!,Diolinux,https://www.youtube.com/watch?v=z1XTcKKRbKM,Algoritmos,rw1727113785634333cc8 +"# Operador Ternário (O ""economizador"" de linhas de código)","No vídeo de hoje, vamos explorar como utilizar o operador ternário de maneira eficaz em suas aplicações. Vamos ver exemplos práticos que mostram como ele pode substituir estruturas condicionais mais longas, ajudando a manter seu código limpo e direto.",Código Fonte TV,https://www.youtube.com/watch?v=YjEtiFi2k7g,Operador Ternário,rw1727181976096a054ca +# Arrays simples de objetos,"Neste vídeo, você aprenderá conceitos básicos sobre a utilização de Arrays simples e Arrays de objetos no JavaScript utilizando TypeScript. + +Serão abordados alguns tópicos, a exemplo: + +- Como declarar e manipular Arrays simples; +- Como trabalhar com Arrays de objetos; +- O uso de propriedades anuláveis (nullable) para evitar erros em casos onde valores podem ser `null` ou `undefined`; +- Métodos como propriedades, permitindo que funções sejam atribuídas diretamente aos objetos e acessadas como qualquer outra propriedade. + +Este conteúdo é essencial para quem deseja aprofundar o uso de Arrays e melhorar a segurança e a estruturação do código em TypeScript. +",CodeTotal,https://www.youtube.com/watch?v=mY_bJ9R-0bI,Array Simples,rw1727182071303ae95a8 +# O que é GIT e GITHUB? - definição e conceitos importantes 1/2,Esse vídeo explica a definição de Git e Github e os principais conceitos utilizados na ferramenta! É algo muito necessário na vida de uma pessoa desenvolvedora.,Rafaella Ballerini,https://www.youtube.com/watch?v=DqTITcMq68k,GitHub,rw172718612668122783c +# Comandos Git mais usados por desenvolvedores,"Neste vídeo serão demonstrados os comandos do Git mais utilizados no dia a dia de uma desenvolvedora. + +Serão abordados comandos como: +- git init; +- git status; +- git add; +- git commit; +- git log; +- git branch; +- git checkout; +- git merge; +",Matheus Battisti,https://www.youtube.com/watch?v=Xxcjjh7DkJk,Como utilizar o GitHub e Git,rw1727188618314cdca08 +# Como personalizar o seu perfil no Github (Readme),"O vídeo ensina como personalizar o perfil do GitHub, começando pela criação do repositório e do arquivo `README.md`. Ele mostra como adicionar estatísticas do GitHub, ícones de tecnologias, badges de redes sociais, um GIF personalizado e a cobrinha de commits. + + + +A personalização do perfil é essencial para pessoas desenvolvedoras, pois ajuda a destacar suas habilidades e projetos de forma visual e interativa. Este vídeo é ideal tanto para iniciantes quanto para desenvolvedoras experientes que desejam aprimorar sua presença no GitHub. +",Rafaella Ballerini,https://www.youtube.com/watch?v=TsaLQAetPLU,Como personalizar o GitHub,rw172718871387068b90f +# Instalar o Node.js no Windows,"Neste vídeo será ensinado como instalar Node.js no Windows. ",Gordin de Óculos | Informática e Tecnologia,https://www.youtube.com/watch?v=OmJOT50TW1g&ab_channel=Gordinde%C3%93culos-Inform%C3%A1ticaeTecnologia,Instalar Node.js,rw17271894235882d9cda +# Como Instalar Git Bash no Windows,"Neste vídeo é ensinado um passo a passo de como fazer download do terminal Git Bash. No final da instalação, é exibido como pode testar. ",Alessandro Ramos,https://www.youtube.com/watch?v=eZBjPi--uRM&ab_channel=AlessandroRamos,Git bash,rw1727959966242d7705d +# Refatoração - Dicionário do Programador,"Neste vídeo você aprenderá o que é refatoração, seus principais benefícios e como deixar o seu código mais limpo.",Código Fonte TV,https://www.youtube.com/watch?v=VOxnyVI2lOc&ab_channel=CódigoFonteTV,Benefícios da Refatoração,rw1727961920967e41be3 +# Aprenda Git e Github em 5 minutos," Assuntos abordados: + +- O que é Git? +- O que é Github? +- Como utilizar cada um? +- Qual a diferença entre Git e Github? +- Comece a mostrar seus códigos; +- Principais comandos; +- Básico de Git e Github; +- Github é um multiverso;",Mucharski,https://www.youtube.com/watch?v=-l4Aa8wef8s,"Git ",rw17279619210594231cf +# Curso de Node.js - Protocolo HTTP #05,"Nesta aula, você aprenderá o que é o protocolo HTTP, que é o mecanismo que possibilita toda a comunicação entre servidor e cliente na WEB. Além disso, vai descobrir como construir seu próprio servidor HTTP usando Node.js e JavaScript, iniciando seus primeiros passos no desenvolvimento web com Node.js.",Victor Lima - Ciência da Computação,https://www.youtube.com/watch?v=QnTCre0HHv8&list=PLJ_KhUnlXUPtbtLwaxxUxHqvcNQndmI4B&index=6,Protocolo HTTP,rw173030548457336f6be +# Curso de Node.JS - O que é Node.JS #01,"Nesta aula, você aprenderá que o Node.js é uma plataforma que executa código JavaScript no lado do servidor, ou seja, fora dos navegadores. Node.js não é uma linguagem de programação, biblioteca ou framework, mas sim uma plataforma para interpretar JavaScript.",Victor Lima - Ciência da Computação,https://www.youtube.com/watch?v=LLqq6FemMNQ&list=PLJ_KhUnlXUPtbtLwaxxUxHqvcNQndmI4B&index=2," Internet: Conceitos e fundamentos",rw173030856205779a18c +# Criando aplicações usando React e Next jS com Typescript - Aula 01 - Curso de React Next,"Neste vídeo, aprenderemos a criar uma aplicação web usando React e Next.js com TypeScript. Vamos explorar como configurar o ambiente de desenvolvimento e entender as vantagens de unir essas ferramentas, incluindo a criação de interfaces interativas e a utilização de renderização server-side para otimizar o desempenho e SEO. Além disso, abordaremos conceitos fundamentais do React, como componentização, Virtual DOM e estado, e veremos como o Next.js adiciona funcionalidades avançadas para melhorar a experiência do desenvolvedor e do usuário.",CFBCursos,https://www.youtube.com/watch?v=k9IG_tPonwo,Fundamentos Next.js,rw1730309558200da1b04 +# Entendendo o escopo de variáveis e constantes em React Next JS - Aula 03 - Curso de React Next,"Neste vídeo, exploramos os conceitos de escopo de variáveis e constantes ao trabalhar com React e Next.js, utilizando TypeScript. A aula aborda como e onde declarar `const`, `let` e `var`, e explica a importância dos escopos local e global para garantir a segurança e o desempenho do código. Veremos como esses conceitos influenciam o comportamento das variáveis e como aplicá-los corretamente para evitar erros comuns e melhorar a organização da aplicação.",CFBCursos,https://www.youtube.com/watch?v=N5DCZWR_CWA,Variáveis e Constantes,rw173022851922113f6a4 +# Aprenda HTML em apenas 5 MINUTOS (2023),"Neste vídeo, aprenda as partes mais importantes do HTML em apenas 5 minutos! Explorando desde a estrutura básica de um documento HTML até aos elementos principais, como head, body, e links hipertextuais. ",Tiger Codes,https://www.youtube.com/watch?v=5Hn58p-hYC0&t=126s&ab_channel=TigerCodes,Estrutura Básica,rw173038056692115906a +# Como usar TAILWIND e classes CSS puras em React Next JS,"Neste vídeo você vai aprender sobre como usar o TAILWIND e classes CSS puras em React, Next e Typescript para aplicar formatação em nossos projetos.",CFBCursos,https://www.youtube.com/watch?v=IkYFn5Ums1Y,CSS + Next.js,rw173038059683403a76d +# Aprendendo como criar FUNÇÕES em React Next JS - Aula 04 - Curso de React Next,"Este vídeo ensina como criar funções em React usando Next.js com TypeScript, abordando os conceitos e regras essenciais para escrever funções eficientes e bem estruturadas no contexto de aplicações React. A aula cobre a definição e o uso de funções comuns, funções de seta (arrow functions) e o papel de cada tipo de função na organização e reutilização do código. Além disso, demonstra como o TypeScript facilita a definição de tipos para parâmetros e valores de retorno, aumentando a segurança e clareza do código.",CFBCursos,https://www.youtube.com/watch?v=nWBgsikNl08,Funções + Next.js,rw1730381347511d42889 +# React.Js e Axios - Consumir dados de API com React e Axios,"Neste vídeo você vai aprender a usar o Axios, uma biblioteca Javascript , Promise Based, que permite fazer requisições HTTP de forma facilitada. Grandes projetos são feitos com React e Axios, também utilizaremos React Router Dom para criar as rotas (páginas) da nossa aplicação.",Matheus Battisti - Hora de Codar,https://www.youtube.com/watch?v=NbhoeLj6lBs,Axios,rw17303826775236dc6f9 +# O que é Reset CSS?,"Neste vídeo, é apresentada uma comparação da criação de um site em HTML e CSS em diferentes navegadores. Ressaltando a importância do Reset CSS, que garante uma base consistente. Além disso, é demonstrado como usar o Reset CSS e o que cada tag está fazendo.",Marco Bruno,https://www.youtube.com/watch?v=23G_3ODk5mY&ab_channel=MarcoBruno,Reset.css,rw173038438692167ef21 +# Renderização Condicional em Next.js,"Renderização condicional em React permite exibir ou ocultar componentes com base em condições, criando uma interface mais intuitiva. Usando operadores como `&&` e a operação ternária, é possível exibir um componente conforme a condição (verdadeira ou falsa). Isso também possibilita mudanças dinâmicas de estilo, personalizando a interface para o usuário e melhorando a experiência interativa.",CFBCursos,https://www.youtube.com/watch?v=ZSt8_kGWFJc,Renderização,rw1730385045868cb4220 +# Criando COMPONENTES em React e Next,"Nesta aula vamos aprender como criar componentes em React, Next e Typescript.",CFBCursos,https://www.youtube.com/watch?v=_II0dYvxiFI,Componentes + Next.js,rw1730385036838928c85 +# Criando COMPONENTES com PROPS em React eNext,"Nesta aula vamos continuar a aprender sobre como criar componentes em React, Next e Typescript. Vamos aprender o que são props e como podemos utilizar props para enviar funções e variáveis para um componente.",CFBCursos,https://www.youtube.com/watch?v=X_nGc0irnkM,Componentes + props,rw1730385453771961ca5 +# Criando Links e Redirecionamento de Página no Next.js,"O vídeo introduz um novo curso de React, focando na criação e navegação entre páginas em uma aplicação. O professor Bruno explica como: + +- **Criar a estrutura de pastas:** Os alunos são orientados a criar pastas para `produtos` e `teste`, onde desenvolverão as páginas correspondentes. +- **Construir componentes de página:** Cada página (`produtos.tsx` e `teste.tsx`) é criada para exportar funções que retornam conteúdo específico. +- **Navegação entre páginas:** É demonstrado o uso da tag `link` para permitir que os usuários naveguem entre a página inicial, a de produtos e a de teste. +- **Importar um menu de navegação:** O menu é adicionado ao topo de cada página, facilitando a transição entre elas. + +O vídeo destaca a importância de organizar a aplicação, garantindo que, ao final, as páginas estejam interconectadas e funcionais.",CBFCursos,https://www.youtube.com/watch?v=Ru1Xt-xdZy4,Direcionamento de Páginas,rw1730385685387455da6 +# Trabalhando com Listas em React Next,"O vídeo é uma aula do professor Bruno sobre como manipular listas em projetos de Next.js com TypeScript. Ele ensina a preencher um elemento `` de forma dinâmica, utilizando dados de um array de cursos. Através de exemplos práticos, o professor demonstra como usar o método `.map()` para gerar opções a partir de listas, abordando também o uso de objetos JSON para tornar o preenchimento ainda mais eficiente. A aula explora diferentes abordagens e finaliza com a promessa de conteúdos futuros sobre o consumo de APIs.",CBFCursos,https://www.youtube.com/watch?v=vub097QVdjs,Listas,rw1730386588439f1bcef +# Estilos CSS inline,"O vídeo apresenta uma introdução ao CSS, incluindo uma parte prática com exercícios e um enfoque específico no estilo CSS ""inline"". Também são discutidas as principais vantagens e desvantagens desse estilo para ajudar você a decidir quando utilizá-lo em seus projetos. Ao final da página, você encontrará referências com conteúdos complementares para aprofundar o aprendizado neste tópico.",Gustavo Guanabara | Curso em vídeo,https://www.youtube.com/watch?v=byqhpuVpvEI,Estilos.css,rw1730391187322b4f666 +# API com Node.JS - Passo 0 - Introdução (O que é uma REST API?),"Este vídeo apresenta uma introdução sobre REST API, abordando desde conceitos básicos até tipos de clientes, endpoints e restrições.",Maransatto,https://www.youtube.com/watch?v=d_vXgK4uZJM&list=PLWgD0gfm500EMEDPyb3Orb28i7HK5_DkR,REST API,rw17303922044867583d9 +# CSS Grid Layout e Flexbox - Quando Utilizar,"Aprenda a organizar e alinhar elementos na página de forma prática e eficiente, explorando o poder do CSS Grid Layout e do Flexbox para criar layouts responsivos e visualmente equilibrados.",Origamid,https://www.youtube.com/watch?v=x-4z_u8LcGc&t=1339s&ab_channel=Origamid,Flexbox e Grid,rw1730468775715f5a925 +# Como Funciona A Hierarquia No CSS,Este vídeo aborda em detalhes como funciona a hierarquia entre as diferentes maneiras de declarar propriedades em CSS.,Nicholas Arths,https://www.youtube.com/watch?v=ioO3Y81oMbQ&ab_channel=N%C3%ADcolasArths.,Hierarquia no CSS,rw1730469206916700276 +# Um Dev Júnior tem que Saber Isso de CSS Box Model,"O Box Model é um conceito fundamental em CSS que todo desenvolvedor front-end e designer precisa dominar, pois ele influencia diretamente na construção de interfaces eficientes e bem estruturadas.",DPW,https://www.youtube.com/watch?v=YNqrNqpq6-E&ab_channel=dpw,Box model e Box sizing,rw17304698234373039ff +# Como deixar o Layout Responsivo no seu site,"Aprenda responsividade na prática com este tutorial sobre como transformar seu site num layout responsivo através do uso de ferramentas de desenvolvedor do seu navegador, o visual studio code e códigos CSS: media screen, container, propriedades CSS e mais.",Alura,https://www.youtube.com/watch?v=kyFiT4ofMwk&t=526s&ab_channel=Alura,Design responsivo,rw173047014175556eaeb +# CSS: Seletores e Especificidade,CSS: Entenda Seletores e Especificidade para aprimorar o controle sobre o estilo dos elementos na sua página.,Cod3r Cursos,https://www.youtube.com/watch?v=dPL23aVRIlc&ab_channel=Cod3rCursos,Seletores CSS,rw17304704919002a1f75 +# Como adicionar fontes personalizadas no site? (Tutorial de HTML e CSS),"Aprenda a adicionar fontes personalizadas ao seu site usando apenas HTML e CSS! Neste vídeo, você verá como usar fontes genéricas, fontes do Google Fonts e fontes offline.",Inteliogia,https://www.youtube.com/watch?v=V1uN8beSc04&ab_channel=Inteliogia-Dev%27sInsights,Fontes,rw17304726962139b6587 +# TypeORM #1 - Conhecendo e criando um primeiro projeto,"Neste vídeo, apresenta um tutorial do TypeORM, um framework em TypeScript. Explore suas principais características, como suporte a múltiplos bancos de dados, tipagem estática e mapeamento de entidades. ",Angelo Luz,https://www.youtube.com/watch?v=6o0Vw0665kw,TypeORM,rw173047838568373c5c5 +# Curso NodeJS - Migrations #13,"Neste vídeo, abordaremos as migrations, uma ferramenta essencial do TypeORM que facilita a criação de tabelas, colunas e relacionamentos no nosso banco de dados. + +",Programar na web,https://www.youtube.com/watch?v=cmzqqBVJaec&t=8s,Migrations,rw1730478678431b72962 +# CSS: Aprenda de verdade css position,"Aprenda, de uma vez por todas, como dominar o posicionamento no CSS! Neste vídeo, você vai entender a fundo as diferenças entre position: **static, absolute, relative, fixed e stick**, para aplicar esses conceitos com confiança e precisão nos seus projetos.",Daniel Tapias | Serliv,https://www.youtube.com/watch?v=XCvSUC0zECI,Posicionamento,rw1730480417487fc918c +# Curso React: Criando Componentes no React - #04,"Neste vídeo, vamos expandir nossos conhecimentos em React, criando Componentes e entendendo suas finalidades. Assim, tornaremos nossa aplicação mais reutilizável, além de melhorar a organização e facilitar a manutenção do código.",Matheus Battisti - Hora de Codar,https://www.youtube.com/watch?v=-wrsG0IGc-M,Componentes,rw1730480888550084053 +# Aprenda REACT HOOKS em 30 minutos | Tutorial sobre Hooks,"Nesse vídeo vamos entender o que são os React Hooks, como utilizá-los e como criar os nossos próprios Hooks. Além disso, aprenderemos os principais Hooks oferecidos pelo React como o useState e useEffect.",Fernanda Kipper | Dev,https://www.youtube.com/watch?v=Fc-___dblSI,Hooks,rw1730480890516130743 +# Como criar um formulário com HTML e CSS,"Assistindo o vídeo você vai aprender a criar um formulário estilizado do início ao fim, utilizando HTML e CSS! Este tutorial oferece um passo a passo que o ajudará a construir um formulário simples e a aplicar estilos visuais que o tornem mais atraente e funcional. ",Jeterson Lordano - dev,https://www.youtube.com/watch?v=-MsqwWyv8eQ,Formulários - Tabelas - Listas,rw1730480892419e14aa7 +"# Curso HTML - Multimídia (Imagens, áudios e vídeos)","Nesse vídeo você vai aprender como trabalhar com multimídias no HTML: Imagens, áudios e vídeos. +",Se7i Tecnologia,https://www.youtube.com/watch?v=mHZ6PfLen8c&ab_channel=Se7iTecnologia,Elementos Multimídia,rw173048089362798d4d6 +# Como entender a estrutura de elementos HTML de uma pagina,Entenda a estrutura de uma página HTML e quais tags utilizar pra montar sua página.,Tio do HTML,https://www.youtube.com/watch?v=oZvuH9_IvwI&t=90s&ab_channel=~TioDoHtml,Estrutura de Páginas Web e Links,rw1730480896589942212 +# Fluxo de dados unidirecional com React e Remix: como manter seus dados consistentes,"Neste vídeo, você vai aprender o que é o fluxo de dados unidirecional e como implementá-lo em React e Remix para garantir a atualização consistente dos dados e melhorar a sincronização no front-end.",RemixJS Brasil,https://www.youtube.com/watch?v=raV2nn6HLdw,One-way Data Flow,rw1730480897661541054 +# Aprenda Props no React de Forma Simples e Rápida! | Recorte,"Este vídeo ensina tudo sobre Props no React, um conceito essencial para a comunicação entre componentes. Você aprenderá como elas funcionam, sua importância para criar aplicações modulares e reutilizáveis, e como usá-las para passar dados de forma eficiente. Dominar Props é fundamental para avançar no React!",Felipe Rocha • Full Stack Club,https://www.youtube.com/watch?v=MEUdCa9mPNM,Props,rw1730480898416cd510b +# Introdução ao React #2. O React e o ReactDOM.,Nesta aula iremos ver a função das duas bibliotecas que compõe o React: React e ReactDOM.,web3escola,https://www.youtube.com/watch?v=Eqd4w1U4ugI,React DOM,rw1730480899480877480 +# Entendendo Refs e forwardRef no ReactJS: Quando e Como Utilizar?,"Neste vídeo, vou te mostrar como utilizar Refs para acessar elementos diretamente e como o forwardRef ajuda a criar componentes reutilizáveis que expõem seu DOM interno. Vamos explorar juntos a teoria e exemplos práticos para que você aprenda a aplicar essas técnicas no seu código e otimizar suas aplicações!",Dev Junior Alves,https://www.youtube.com/watch?v=tJZX6U5SxOM,Refs,rw1730480902069221187 +# Curso React: Renderização condicional (if),"A proposta deste vídeo é mostrar como podemos exibir JSX diferente baseado em uma condição, ou seja, um if. Utilizaremos uma técnica chamada de renderização condicional no React, que deixa nosso código limpo e permite exibir dados de forma dinâmica, baseados em uma condição. +",Matheus Battisti - Hora de Codar,https://www.youtube.com/watch?v=7ewepbLCvHc&list=PLnDvRpP8BneyVA0SZ2okm-QBojomniQVO&index=13,"Rendering ",rw1730480905287b8eed4 +# React Router: O guia completo para navegação em aplicativos React,"Neste vídeo, você verá como configurar o React Router e criar rotas para diferentes páginas no seu aplicativo! Vamos explorar juntos como passar parâmetros de rota e tratar erros de forma prática. No final, você estará pronto para criar uma experiência de navegação incrível para seus usuários. ",Matheus Battisti - Hora de Codar,https://www.youtube.com/watch?v=7b42lVMdEjE,Router,rw173048090692264cb7a +# Como Hospedar seu Site de Graça com Netlify,"Neste vídeo explica como usar o Netlify para hospedar rapidamente um site na web, sem complicações. Basta criar uma conta, fazer o upload dos arquivos e o Netlify gera um link acessível a qualquer pessoa. É uma maneira simples e eficiente de publicar sites.",Dotcode,https://www.youtube.com/watch?v=0EUTK5EHK_A," Deploy com o Netlify",rw17304809219861eb6cb +# Deploy // Dicionário do Programador,"Dicionário do Programador: é o quadro semanal onde o canal Código Fonte TV desvendam termos, tecnologias e palavras do incrível universo da programação! Neste vídeo, é explorado o tema Deploy. ",Código Fonte TV,https://www.youtube.com/watch?v=gJw7l2JKpuQ&ab_channel=C%C3%B3digoFonteTo que,O que é Deploy?,rw173048092353167cc2b +"# Mocks, Stubs, Dummies, Fakes e Spies",Nesse vídeo tem a definição de todos esses tipos de dublês de teste utilizando um artigo clássico do Martin Fowler.,Otavio Lemos,https://www.youtube.com/watch?v=9w4GpaOeX7M,Mocking e Espiões,rw17327245965322396ed +# Tutorial Teste Unitário com Jest,"Tutorial sobre como utilizar Jest para escrever testes unitários em projetos Node.js. +",Dev Tech,https://youtu.be/A6ODQSxy3Co?si=Et-sIs6Iv2lZq1UQ,Testando Código com Dependências Externas,rw1732725225314aa5dcb +# Testando um componente React,Neste vídeo você colocará em prática a como testar um componente react utilizando jest e também react testing library.,Front Beginners,https://www.youtube.com/watch?v=9UiIAbWU5eA," Testando Componentes React ",rw1732726068414632003 +# Princípios F.I.R.S.T.: Qualidade na Criação de Testes Automatizados,"Descubra como aplicar os princípios F.I.R.S.T. para garantir qualidade na criação de testes automatizados! Neste vídeo, explora cada um desses princípios essenciais, ajudando você a escrever testes robustos e eficazes.",Dias de Dev,https://www.youtube.com/watch?v=p6opbsek-zs,Boas Práticas de Testes,rw1732726508036fe2f1b +# Teste Unitário - O que é ?," Nesse video tento de uma maneira simples explicar os conceitos básicos desse tipo de teste.",Garoto de Software,https://www.youtube.com/watch?v=dxdvGuKyBs8,Conceitos Básicos de Testes Unitários,rw17327320098823e5f62 +# Concretizando expectativas: introdução ao Jest - CodeLab Bits,"No vídeo de hoje o João veio falar um pouco sobre testes no JavaScript dando uma noção básica do framework Jest. +",CodeLab,https://www.youtube.com/watch?app=desktop&v=0a0lqX2pFdM&ab,Escrevendo Testes Simples com Jest,rw1732733703246a64f39 +# Descomplicando Testes Unitários!,"Nessa aula você aprenderá um pouco sobre testes unitários e sua importância, assim como sobre nossa ferramenta de testes, o JestJS.",Attekita Dev,https://youtu.be/HcDJdKfm5nA?si=gH5KDOMpthzsVKJu,Testando Funções e Módulos com Jest,rw1732798064338e28dea +# O que é cobertura de código (code coverage) e como calcular?,"Nessa aula você vai aprender o que é a cobertura de código (ou code coverage, em inglês), como funciona essa parada e como tirar um relatório do seu projeto direto no Visual Studio - e essa é a parte mais fácil. +",Andre Okazaki,https://www.youtube.com/watch?v=hLT_ThViNdk," Cobertura de Código",rw173279845374308edfb +# Vincular Node.js com Express ao PostgreSQL via Prisma,Nesta aula você vai aprender a vincular o Node.js com Express ao PostgreSQL via Prisma,Dev. Odair Michael,https://www.youtube.com/watch?v=69cMbxc06nk,PrismaORM,rw1750684131708558731 +# Como usar map reduce e filter na prática com JavaScript,"Neste vídeo você aprende de forma simples e direta como funcionam os métodos map, filter e reduce em JavaScript. Com exemplos visuais e didáticos, o instrutor mostra como aplicar esses métodos para transformar, filtrar e reduzir listas de forma mais prática e moderna + +",DevClub | Programação,https://www.youtube.com/watch?v=Ar2cMgpjkLM,Métodos map filter e sort,rw17515527172509dcf4c +# Dominando o React Hook useState | Aprenda a Gerenciar o Estado no React,"Neste vídeo, vamos mergulhar fundo no mundo do React Hook useState, explorando todos os aspectos fundamentais que você precisa saber para se tornar um desenvolvedor React experiente. Vamos cobrir: +- O que é o Hook useState e por que é tão importante. +​- Como criar e inicializar estados no React. +- Como atualizar e modificar o estado de forma eficiente. +- Lidar com estados em componentes funcionais. +- Exemplos práticos e projetos para consolidar seu conhecimento.",DevClub | Programação,https://www.youtube.com/watch?v=E-gIg2dXWv4,State,rw17581316941728d3526 \ No newline at end of file diff --git a/prisma/migrations/20241003183617_nome_da_migracao/migration.sql b/prisma/migrations/20241003183617_nome_da_migracao/migration.sql new file mode 100644 index 0000000..45bd45d --- /dev/null +++ b/prisma/migrations/20241003183617_nome_da_migracao/migration.sql @@ -0,0 +1,33 @@ +-- CreateEnum +CREATE TYPE "ElementType" AS ENUM ('VIDEO', 'EXERCICIO'); + +-- CreateTable +CREATE TABLE "User" ( + "id" SERIAL NOT NULL, + "email" TEXT NOT NULL, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Progress" ( + "id" SERIAL NOT NULL, + "itemId" TEXT NOT NULL, + "itemStatus" BOOLEAN NOT NULL, + "elementType" "ElementType" NOT NULL, + "userId" INTEGER NOT NULL, + + CONSTRAINT "Progress_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "Progress_itemId_key" ON "Progress"("itemId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Progress_userId_key" ON "Progress"("userId"); + +-- AddForeignKey +ALTER TABLE "Progress" ADD CONSTRAINT "Progress_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20241113170254_criando/migration.sql b/prisma/migrations/20241113170254_criando/migration.sql new file mode 100644 index 0000000..d2ecda7 --- /dev/null +++ b/prisma/migrations/20241113170254_criando/migration.sql @@ -0,0 +1,22 @@ +/* + Warnings: + + - The values [VIDEO,EXERCICIO] on the enum `ElementType` will be removed. If these variants are still used in the database, this will fail. + - Changed the type of `itemStatus` on the `Progress` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + +*/ +-- CreateEnum +CREATE TYPE "ItemStatus" AS ENUM ('NotStarted', 'InProgress', 'Completed'); + +-- AlterEnum +BEGIN; +CREATE TYPE "ElementType_new" AS ENUM ('Video', 'Exercise'); +ALTER TABLE "Progress" ALTER COLUMN "elementType" TYPE "ElementType_new" USING ("elementType"::text::"ElementType_new"); +ALTER TYPE "ElementType" RENAME TO "ElementType_old"; +ALTER TYPE "ElementType_new" RENAME TO "ElementType"; +DROP TYPE "ElementType_old"; +COMMIT; + +-- AlterTable +ALTER TABLE "Progress" DROP COLUMN "itemStatus", +ADD COLUMN "itemStatus" "ItemStatus" NOT NULL; diff --git a/prisma/migrations/20241119165728_removendo_chave_unique_do_itemstatus/migration.sql b/prisma/migrations/20241119165728_removendo_chave_unique_do_itemstatus/migration.sql new file mode 100644 index 0000000..8d74025 --- /dev/null +++ b/prisma/migrations/20241119165728_removendo_chave_unique_do_itemstatus/migration.sql @@ -0,0 +1,2 @@ +-- DropIndex +DROP INDEX "Progress_itemId_key"; diff --git a/prisma/migrations/20241129135556_mudanca_relacionamento_user_progress/migration.sql b/prisma/migrations/20241129135556_mudanca_relacionamento_user_progress/migration.sql new file mode 100644 index 0000000..d5559b1 --- /dev/null +++ b/prisma/migrations/20241129135556_mudanca_relacionamento_user_progress/migration.sql @@ -0,0 +1,2 @@ +-- DropIndex +DROP INDEX "Progress_userId_key"; diff --git a/prisma/migrations/20241129141953_adicionando_topic_id_em_progress/migration.sql b/prisma/migrations/20241129141953_adicionando_topic_id_em_progress/migration.sql new file mode 100644 index 0000000..43ca324 --- /dev/null +++ b/prisma/migrations/20241129141953_adicionando_topic_id_em_progress/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - Added the required column `topicId` to the `Progress` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Progress" ADD COLUMN "topicId" TEXT NOT NULL; diff --git a/prisma/migrations/20241129142123_adicionando_topic_id_em_progress/migration.sql b/prisma/migrations/20241129142123_adicionando_topic_id_em_progress/migration.sql new file mode 100644 index 0000000..88a68de --- /dev/null +++ b/prisma/migrations/20241129142123_adicionando_topic_id_em_progress/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Progress" ALTER COLUMN "topicId" SET DEFAULT 'default-topic-id'; diff --git a/prisma/migrations/20250218183742_criando_coluna_de_provider_para_modelo_user/migration.sql b/prisma/migrations/20250218183742_criando_coluna_de_provider_para_modelo_user/migration.sql new file mode 100644 index 0000000..bea0a29 --- /dev/null +++ b/prisma/migrations/20250218183742_criando_coluna_de_provider_para_modelo_user/migration.sql @@ -0,0 +1,15 @@ +/* + Warnings: + + - A unique constraint covering the columns `[email,provider]` on the table `User` will be added. If there are existing duplicate values, this will fail. + - Added the required column `provider` to the `User` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropIndex +DROP INDEX "User_email_key"; + +-- AlterTable +ALTER TABLE "User" ADD COLUMN "provider" TEXT NOT NULL; + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_provider_key" ON "User"("email", "provider"); diff --git a/prisma/migrations/20250218184827_criando_enum_para_coluna_provider/migration.sql b/prisma/migrations/20250218184827_criando_enum_para_coluna_provider/migration.sql new file mode 100644 index 0000000..a5f9688 --- /dev/null +++ b/prisma/migrations/20250218184827_criando_enum_para_coluna_provider/migration.sql @@ -0,0 +1,15 @@ +/* + Warnings: + + - Changed the type of `provider` on the `User` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + +*/ +-- CreateEnum +CREATE TYPE "Provider" AS ENUM ('Google', 'Github', 'Linkedin', 'Facebook'); + +-- AlterTable +ALTER TABLE "User" DROP COLUMN "provider", +ADD COLUMN "provider" "Provider" NOT NULL; + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_provider_key" ON "User"("email", "provider"); diff --git a/prisma/migrations/20250221180946_removendo_chave_composta_para_email_e_provider/migration.sql b/prisma/migrations/20250221180946_removendo_chave_composta_para_email_e_provider/migration.sql new file mode 100644 index 0000000..503b0c1 --- /dev/null +++ b/prisma/migrations/20250221180946_removendo_chave_composta_para_email_e_provider/migration.sql @@ -0,0 +1,21 @@ +/* + Warnings: + + - A unique constraint covering the columns `[email]` on the table `User` will be added. If there are existing duplicate values, this will fail. + - Added the required column `loginDate` to the `User` table without a default value. This is not possible if the table is not empty. + - Changed the type of `provider` on the `User` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + +*/ +-- DropIndex +DROP INDEX "User_email_provider_key"; + +-- AlterTable +ALTER TABLE "User" ADD COLUMN "loginDate" TIMESTAMP(3) NOT NULL, +DROP COLUMN "provider", +ADD COLUMN "provider" TEXT NOT NULL; + +-- DropEnum +DROP TYPE "Provider"; + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); diff --git a/prisma/migrations/20250320145057_adicao_do_campo_modified_at_no_progresso/migration.sql b/prisma/migrations/20250320145057_adicao_do_campo_modified_at_no_progresso/migration.sql new file mode 100644 index 0000000..6484e0a --- /dev/null +++ b/prisma/migrations/20250320145057_adicao_do_campo_modified_at_no_progresso/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - Added the required column `modifiedAt` to the `Progress` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Progress" ADD COLUMN "modifiedAt" TIMESTAMP(3) NOT NULL; diff --git a/prisma/migrations/20250326173001_add_unique_no_itemid/migration.sql b/prisma/migrations/20250326173001_add_unique_no_itemid/migration.sql new file mode 100644 index 0000000..629a518 --- /dev/null +++ b/prisma/migrations/20250326173001_add_unique_no_itemid/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - A unique constraint covering the columns `[itemId]` on the table `Progress` will be added. If there are existing duplicate values, this will fail. + +*/ +-- CreateIndex +CREATE UNIQUE INDEX "Progress_itemId_key" ON "Progress"("itemId"); diff --git a/prisma/migrations/20250520155458_/migration.sql b/prisma/migrations/20250520155458_/migration.sql new file mode 100644 index 0000000..8b82f3b --- /dev/null +++ b/prisma/migrations/20250520155458_/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - A unique constraint covering the columns `[itemId,userId]` on the table `Progress` will be added. If there are existing duplicate values, this will fail. + +*/ +-- DropIndex +DROP INDEX "Progress_itemId_key"; + +-- CreateIndex +CREATE UNIQUE INDEX "Progress_itemId_userId_key" ON "Progress"("itemId", "userId"); diff --git a/prisma/migrations/20250603135434_add_theme_id/migration.sql b/prisma/migrations/20250603135434_add_theme_id/migration.sql new file mode 100644 index 0000000..4dea96d --- /dev/null +++ b/prisma/migrations/20250603135434_add_theme_id/migration.sql @@ -0,0 +1,9 @@ +/* + Warnings: + + - Added the required column `themeId` to the `Progress` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Progress" ADD COLUMN "themeId" TEXT NOT NULL, +ALTER COLUMN "topicId" DROP DEFAULT; diff --git a/prisma/migrations/20250611125301_remove_unecessary_id/migration.sql b/prisma/migrations/20250611125301_remove_unecessary_id/migration.sql new file mode 100644 index 0000000..8a942ad --- /dev/null +++ b/prisma/migrations/20250611125301_remove_unecessary_id/migration.sql @@ -0,0 +1,10 @@ +/* + Warnings: + + - The primary key for the `Progress` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `id` on the `Progress` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "Progress" DROP CONSTRAINT "Progress_pkey", +DROP COLUMN "id"; diff --git a/prisma/migrations/20251018132440_novo_migrate/migration.sql b/prisma/migrations/20251018132440_novo_migrate/migration.sql new file mode 100644 index 0000000..686a9ba --- /dev/null +++ b/prisma/migrations/20251018132440_novo_migrate/migration.sql @@ -0,0 +1,72 @@ +-- CreateTable +CREATE TABLE "Theme" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "cardDescription" TEXT, + "image" TEXT, + "category" TEXT, + "sequence" INTEGER NOT NULL DEFAULT 0, + "alt" TEXT, + + CONSTRAINT "Theme_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Topic" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "cardDescription" TEXT, + "description" TEXT, + "references" TEXT, + "themeId" TEXT NOT NULL, + + CONSTRAINT "Topic_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Exercise" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "sequence" INTEGER NOT NULL DEFAULT 0, + "topicId" TEXT NOT NULL, + + CONSTRAINT "Exercise_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Video" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "references" TEXT, + "link" TEXT NOT NULL, + "topicId" TEXT NOT NULL, + + CONSTRAINT "Video_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Theme_title_key" ON "Theme"("title"); + +-- CreateIndex +CREATE UNIQUE INDEX "Topic_title_key" ON "Topic"("title"); + +-- CreateIndex +CREATE UNIQUE INDEX "Exercise_title_key" ON "Exercise"("title"); + +-- CreateIndex +CREATE UNIQUE INDEX "Video_title_key" ON "Video"("title"); + +-- CreateIndex +CREATE UNIQUE INDEX "Video_link_key" ON "Video"("link"); + +-- AddForeignKey +ALTER TABLE "Topic" ADD CONSTRAINT "Topic_themeId_fkey" FOREIGN KEY ("themeId") REFERENCES "Theme"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Exercise" ADD CONSTRAINT "Exercise_topicId_fkey" FOREIGN KEY ("topicId") REFERENCES "Topic"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Video" ADD CONSTRAINT "Video_topicId_fkey" FOREIGN KEY ("topicId") REFERENCES "Topic"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20251118043243_remove_typo_no_user_id_de_progress/migration.sql b/prisma/migrations/20251118043243_remove_typo_no_user_id_de_progress/migration.sql new file mode 100644 index 0000000..84ecd59 --- /dev/null +++ b/prisma/migrations/20251118043243_remove_typo_no_user_id_de_progress/migration.sql @@ -0,0 +1,103 @@ +/* + Warnings: + + - You are about to drop the `Exercise` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `Theme` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `Topic` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `Video` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "Exercise" DROP CONSTRAINT "Exercise_topicId_fkey"; + +-- DropForeignKey +ALTER TABLE "Topic" DROP CONSTRAINT "Topic_themeId_fkey"; + +-- DropForeignKey +ALTER TABLE "Video" DROP CONSTRAINT "Video_topicId_fkey"; + +-- DropTable +DROP TABLE "Exercise"; + +-- DropTable +DROP TABLE "Theme"; + +-- DropTable +DROP TABLE "Topic"; + +-- DropTable +DROP TABLE "Video"; + +-- CreateTable +CREATE TABLE "themes" ( + "idThemes" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "cardDescription" TEXT, + "image" TEXT, + "category" TEXT, + "sequence" INTEGER DEFAULT 0, + "alt" TEXT, + + CONSTRAINT "themes_pkey" PRIMARY KEY ("idThemes") +); + +-- CreateTable +CREATE TABLE "topics" ( + "idTopics" TEXT NOT NULL, + "title" TEXT NOT NULL, + "cardDescription" TEXT, + "description" TEXT, + "references" TEXT, + "themeId" TEXT, + + CONSTRAINT "topics_pkey" PRIMARY KEY ("idTopics") +); + +-- CreateTable +CREATE TABLE "exercises" ( + "idExercises" TEXT NOT NULL, + "title" TEXT NOT NULL, + "cardDescription" TEXT, + "description" TEXT, + "sequence" INTEGER DEFAULT 0, + "topicId" TEXT, + + CONSTRAINT "exercises_pkey" PRIMARY KEY ("idExercises") +); + +-- CreateTable +CREATE TABLE "videos" ( + "idVideos" TEXT NOT NULL, + "title" TEXT NOT NULL, + "description" TEXT, + "references" TEXT, + "link" TEXT NOT NULL, + "topicId" TEXT, + + CONSTRAINT "videos_pkey" PRIMARY KEY ("idVideos") +); + +-- CreateIndex +CREATE UNIQUE INDEX "themes_title_key" ON "themes"("title"); + +-- CreateIndex +CREATE UNIQUE INDEX "topics_title_key" ON "topics"("title"); + +-- CreateIndex +CREATE UNIQUE INDEX "exercises_title_key" ON "exercises"("title"); + +-- CreateIndex +CREATE UNIQUE INDEX "videos_title_key" ON "videos"("title"); + +-- CreateIndex +CREATE UNIQUE INDEX "videos_link_key" ON "videos"("link"); + +-- AddForeignKey +ALTER TABLE "topics" ADD CONSTRAINT "topics_themeId_fkey" FOREIGN KEY ("themeId") REFERENCES "themes"("idThemes") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "exercises" ADD CONSTRAINT "exercises_topicId_fkey" FOREIGN KEY ("topicId") REFERENCES "topics"("idTopics") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "videos" ADD CONSTRAINT "videos_topicId_fkey" FOREIGN KEY ("topicId") REFERENCES "topics"("idTopics") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/migrations/20251118050209_remove_unique_de_title/migration.sql b/prisma/migrations/20251118050209_remove_unique_de_title/migration.sql new file mode 100644 index 0000000..81131ba --- /dev/null +++ b/prisma/migrations/20251118050209_remove_unique_de_title/migration.sql @@ -0,0 +1,11 @@ +-- DropIndex +DROP INDEX "exercises_title_key"; + +-- DropIndex +DROP INDEX "themes_title_key"; + +-- DropIndex +DROP INDEX "topics_title_key"; + +-- DropIndex +DROP INDEX "videos_title_key"; diff --git a/prisma/migrations/20251121174227_init/migration.sql b/prisma/migrations/20251121174227_init/migration.sql new file mode 100644 index 0000000..c97d32e --- /dev/null +++ b/prisma/migrations/20251121174227_init/migration.sql @@ -0,0 +1,131 @@ +/* + Warnings: + + - The primary key for the `exercises` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `cardDescription` on the `exercises` table. All the data in the column will be lost. + - You are about to drop the column `idExercises` on the `exercises` table. All the data in the column will be lost. + - The primary key for the `themes` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `cardDescription` on the `themes` table. All the data in the column will be lost. + - You are about to drop the column `idThemes` on the `themes` table. All the data in the column will be lost. + - The primary key for the `topics` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `cardDescription` on the `topics` table. All the data in the column will be lost. + - You are about to drop the column `idTopics` on the `topics` table. All the data in the column will be lost. + - The primary key for the `videos` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `idVideos` on the `videos` table. All the data in the column will be lost. + - You are about to drop the column `topicId` on the `videos` table. All the data in the column will be lost. + - You are about to drop the `User` table. If the table is not empty, all the data it contains will be lost. + - A unique constraint covering the columns `[videoId]` on the table `topics` will be added. If there are existing duplicate values, this will fail. + - The required column `id` was added to the `exercises` table with a prisma-level default value. This is not possible if the table is not empty. Please add this column as optional, then populate it before making it required. + - Added the required column `shortDescription` to the `exercises` table without a default value. This is not possible if the table is not empty. + - Made the column `description` on table `exercises` required. This step will fail if there are existing NULL values in that column. + - Made the column `sequence` on table `exercises` required. This step will fail if there are existing NULL values in that column. + - Made the column `topicId` on table `exercises` required. This step will fail if there are existing NULL values in that column. + - The required column `id` was added to the `themes` table with a prisma-level default value. This is not possible if the table is not empty. Please add this column as optional, then populate it before making it required. + - Added the required column `shortDescription` to the `themes` table without a default value. This is not possible if the table is not empty. + - Made the column `description` on table `themes` required. This step will fail if there are existing NULL values in that column. + - Made the column `image` on table `themes` required. This step will fail if there are existing NULL values in that column. + - Added the required column `category` to the `themes` table without a default value. This is not possible if the table is not empty. + - Made the column `sequence` on table `themes` required. This step will fail if there are existing NULL values in that column. + - Made the column `alt` on table `themes` required. This step will fail if there are existing NULL values in that column. + - The required column `id` was added to the `topics` table with a prisma-level default value. This is not possible if the table is not empty. Please add this column as optional, then populate it before making it required. + - Added the required column `shortDescription` to the `topics` table without a default value. This is not possible if the table is not empty. + - Added the required column `videoId` to the `topics` table without a default value. This is not possible if the table is not empty. + - Made the column `description` on table `topics` required. This step will fail if there are existing NULL values in that column. + - Made the column `references` on table `topics` required. This step will fail if there are existing NULL values in that column. + - Made the column `themeId` on table `topics` required. This step will fail if there are existing NULL values in that column. + - The required column `id` was added to the `videos` table with a prisma-level default value. This is not possible if the table is not empty. Please add this column as optional, then populate it before making it required. + - Made the column `description` on table `videos` required. This step will fail if there are existing NULL values in that column. + - Made the column `references` on table `videos` required. This step will fail if there are existing NULL values in that column. + +*/ +-- CreateEnum +CREATE TYPE "ThemeCategory" AS ENUM ('Leveling', 'SelfStudy'); + +-- DropForeignKey +ALTER TABLE "Progress" DROP CONSTRAINT "Progress_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "exercises" DROP CONSTRAINT "exercises_topicId_fkey"; + +-- DropForeignKey +ALTER TABLE "topics" DROP CONSTRAINT "topics_themeId_fkey"; + +-- DropForeignKey +ALTER TABLE "videos" DROP CONSTRAINT "videos_topicId_fkey"; + +-- AlterTable +ALTER TABLE "exercises" DROP CONSTRAINT "exercises_pkey", +DROP COLUMN "cardDescription", +DROP COLUMN "idExercises", +ADD COLUMN "id" TEXT NOT NULL, +ADD COLUMN "shortDescription" TEXT NOT NULL, +ALTER COLUMN "description" SET NOT NULL, +ALTER COLUMN "sequence" SET NOT NULL, +ALTER COLUMN "topicId" SET NOT NULL, +ADD CONSTRAINT "exercises_pkey" PRIMARY KEY ("id"); + +-- AlterTable +ALTER TABLE "themes" DROP CONSTRAINT "themes_pkey", +DROP COLUMN "cardDescription", +DROP COLUMN "idThemes", +ADD COLUMN "id" TEXT NOT NULL, +ADD COLUMN "shortDescription" TEXT NOT NULL, +ALTER COLUMN "description" SET NOT NULL, +ALTER COLUMN "image" SET NOT NULL, +DROP COLUMN "category", +ADD COLUMN "category" "ThemeCategory" NOT NULL, +ALTER COLUMN "sequence" SET NOT NULL, +ALTER COLUMN "alt" SET NOT NULL, +ADD CONSTRAINT "themes_pkey" PRIMARY KEY ("id"); + +-- AlterTable +ALTER TABLE "topics" DROP CONSTRAINT "topics_pkey", +DROP COLUMN "cardDescription", +DROP COLUMN "idTopics", +ADD COLUMN "id" TEXT NOT NULL, +ADD COLUMN "shortDescription" TEXT NOT NULL, +ADD COLUMN "videoId" TEXT NOT NULL, +ALTER COLUMN "description" SET NOT NULL, +ALTER COLUMN "references" SET NOT NULL, +ALTER COLUMN "themeId" SET NOT NULL, +ADD CONSTRAINT "topics_pkey" PRIMARY KEY ("id"); + +-- AlterTable +ALTER TABLE "videos" DROP CONSTRAINT "videos_pkey", +DROP COLUMN "idVideos", +DROP COLUMN "topicId", +ADD COLUMN "id" TEXT NOT NULL, +ALTER COLUMN "description" SET NOT NULL, +ALTER COLUMN "references" SET NOT NULL, +ADD CONSTRAINT "videos_pkey" PRIMARY KEY ("id"); + +-- DropTable +DROP TABLE "User"; + +-- CreateTable +CREATE TABLE "users" ( + "id" SERIAL NOT NULL, + "email" TEXT NOT NULL, + "provider" TEXT NOT NULL, + "loginDate" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "users_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "users_email_key" ON "users"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "topics_videoId_key" ON "topics"("videoId"); + +-- AddForeignKey +ALTER TABLE "Progress" ADD CONSTRAINT "Progress_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "topics" ADD CONSTRAINT "topics_themeId_fkey" FOREIGN KEY ("themeId") REFERENCES "themes"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "topics" ADD CONSTRAINT "topics_videoId_fkey" FOREIGN KEY ("videoId") REFERENCES "videos"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "exercises" ADD CONSTRAINT "exercises_topicId_fkey" FOREIGN KEY ("topicId") REFERENCES "topics"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20251121195110/migration.sql b/prisma/migrations/20251121195110/migration.sql new file mode 100644 index 0000000..41d2edb --- /dev/null +++ b/prisma/migrations/20251121195110/migration.sql @@ -0,0 +1,8 @@ +-- DropForeignKey +ALTER TABLE "topics" DROP CONSTRAINT "topics_themeId_fkey"; + +-- AlterTable +ALTER TABLE "topics" ALTER COLUMN "themeId" DROP NOT NULL; + +-- AddForeignKey +ALTER TABLE "topics" ADD CONSTRAINT "topics_themeId_fkey" FOREIGN KEY ("themeId") REFERENCES "themes"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/migrations/20251121200225_optional_relation/migration.sql b/prisma/migrations/20251121200225_optional_relation/migration.sql new file mode 100644 index 0000000..8d742e1 --- /dev/null +++ b/prisma/migrations/20251121200225_optional_relation/migration.sql @@ -0,0 +1,33 @@ +/* + Warnings: + + - You are about to drop the column `videoId` on the `topics` table. All the data in the column will be lost. + - A unique constraint covering the columns `[topicId]` on the table `videos` will be added. If there are existing duplicate values, this will fail. + +*/ +-- DropForeignKey +ALTER TABLE "exercises" DROP CONSTRAINT "exercises_topicId_fkey"; + +-- DropForeignKey +ALTER TABLE "topics" DROP CONSTRAINT "topics_videoId_fkey"; + +-- DropIndex +DROP INDEX "topics_videoId_key"; + +-- AlterTable +ALTER TABLE "exercises" ALTER COLUMN "topicId" DROP NOT NULL; + +-- AlterTable +ALTER TABLE "topics" DROP COLUMN "videoId"; + +-- AlterTable +ALTER TABLE "videos" ADD COLUMN "topicId" TEXT; + +-- CreateIndex +CREATE UNIQUE INDEX "videos_topicId_key" ON "videos"("topicId"); + +-- AddForeignKey +ALTER TABLE "exercises" ADD CONSTRAINT "exercises_topicId_fkey" FOREIGN KEY ("topicId") REFERENCES "topics"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "videos" ADD CONSTRAINT "videos_topicId_fkey" FOREIGN KEY ("topicId") REFERENCES "topics"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/migrations/20251124175931_mapeamento_categoria/migration.sql b/prisma/migrations/20251124175931_mapeamento_categoria/migration.sql new file mode 100644 index 0000000..fb6a471 --- /dev/null +++ b/prisma/migrations/20251124175931_mapeamento_categoria/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - The values [Leveling,SelfStudy] on the enum `ThemeCategory` will be removed. If these variants are still used in the database, this will fail. + +*/ +-- AlterEnum +BEGIN; +CREATE TYPE "ThemeCategory_new" AS ENUM ('nivelamento', 'autoestudo'); +ALTER TABLE "themes" ALTER COLUMN "category" TYPE "ThemeCategory_new" USING ("category"::text::"ThemeCategory_new"); +ALTER TYPE "ThemeCategory" RENAME TO "ThemeCategory_old"; +ALTER TYPE "ThemeCategory_new" RENAME TO "ThemeCategory"; +DROP TYPE "public"."ThemeCategory_old"; +COMMIT; diff --git a/prisma/migrations/20251208215525_adminjs_user_model/migration.sql b/prisma/migrations/20251208215525_adminjs_user_model/migration.sql new file mode 100644 index 0000000..a97402f --- /dev/null +++ b/prisma/migrations/20251208215525_adminjs_user_model/migration.sql @@ -0,0 +1,17 @@ +-- CreateEnum +CREATE TYPE "Role" AS ENUM ('ADMIN', 'EDITOR', 'VIEWER'); + +-- CreateTable +CREATE TABLE "AdminUser" ( + "id" SERIAL NOT NULL, + "email" TEXT NOT NULL, + "password" TEXT NOT NULL, + "role" "Role" NOT NULL DEFAULT 'VIEWER', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "AdminUser_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "AdminUser_email_key" ON "AdminUser"("email"); diff --git a/prisma/migrations/20260106172759_remove_adminuser/migration.sql b/prisma/migrations/20260106172759_remove_adminuser/migration.sql new file mode 100644 index 0000000..fdbf22d --- /dev/null +++ b/prisma/migrations/20260106172759_remove_adminuser/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - You are about to drop the `AdminUser` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- AlterTable +ALTER TABLE "users" ADD COLUMN "role" "Role" NOT NULL DEFAULT 'VIEWER'; + +-- DropTable +DROP TABLE "AdminUser"; diff --git a/prisma/migrations/20260107181122/migration.sql b/prisma/migrations/20260107181122/migration.sql new file mode 100644 index 0000000..eae3d33 --- /dev/null +++ b/prisma/migrations/20260107181122/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "themes" ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true; diff --git a/prisma/migrations/20260130165027_add_column_active_topics/migration.sql b/prisma/migrations/20260130165027_add_column_active_topics/migration.sql new file mode 100644 index 0000000..779bd0b --- /dev/null +++ b/prisma/migrations/20260130165027_add_column_active_topics/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "topics" ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true; diff --git a/prisma/migrations/20260216170231_add_is_active_exercise/migration.sql b/prisma/migrations/20260216170231_add_is_active_exercise/migration.sql new file mode 100644 index 0000000..230f433 --- /dev/null +++ b/prisma/migrations/20260216170231_add_is_active_exercise/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "exercises" ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..044d57c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (e.g., Git) +provider = "postgresql" diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..8c75957 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,116 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model User { + id Int @id @default(autoincrement()) + email String @unique + provider String + loginDate DateTime + Progress Progress[] + role Role @default(VIEWER) + + @@map("users") +} + +model Progress { + itemId String + topicId String + themeId String + + itemStatus ItemStatus + elementType ElementType + modifiedAt DateTime @updatedAt + + userId Int + user User @relation(fields: [userId], references: [id]) + + @@unique([itemId, userId]) +} + +enum ItemStatus { + NotStarted + InProgress + Completed +} + +enum ElementType { + Video + Exercise +} + +enum ThemeCategory { + Leveling @map("nivelamento") + SelfStudy @map("autoestudo") +} + +model Theme { + id String @id @default(cuid()) + title String + description String + shortDescription String + image String + category ThemeCategory + sequence Int @default(0) + alt String + isActive Boolean @default(true) + + topic Topic[] + + @@map("themes") +} + +model Topic { + id String @id @default(cuid()) + title String + shortDescription String + description String + references String + isActive Boolean @default(true) + + themeId String? + theme Theme? @relation(fields: [themeId], references: [id]) + + exercises Exercise[] + video Video? + + @@map("topics") +} + +model Exercise { + id String @id @default(cuid()) + title String + shortDescription String + description String + sequence Int @default(0) + isActive Boolean @default(true) + + topicId String? + topic Topic? @relation(fields: [topicId], references: [id]) + + @@map("exercises") +} + +model Video { + id String @id @default(cuid()) + title String + description String + references String + link String @unique + + topicId String? @unique + topic Topic? @relation(fields: [topicId], references: [id]) + + @@map("videos") +} + +enum Role { + ADMIN + EDITOR + VIEWER +} diff --git a/prisma/seed.js b/prisma/seed.js new file mode 100644 index 0000000..ace8104 --- /dev/null +++ b/prisma/seed.js @@ -0,0 +1,150 @@ +import { PrismaClient, ThemeCategory } from "@prisma/client"; +import * as fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; +import { parse } from "fast-csv"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.join(path.dirname(__filename), "data"); + +async function csvToJSON(filename) { + return new Promise((resolve, reject) => { + const parsedRows = []; + + fs.createReadStream(`${__dirname}/${filename}.csv`) + .pipe( + parse({ + headers: true, + ignoreEmpty: true, + discardUnmappedColumns: true, + trim: true, + }), + ) + .on("error", (error) => { + console.error(error); + reject(error); + }) + .on("data", (row) => parsedRows.push(row)) + .on("end", () => resolve(parsedRows)); + }); +} + +const prisma = new PrismaClient(); + +async function main() { + if (process.env.NODE_ENV === "production") { + console.warn("Run of the seed script was skipped..."); + return; + } + + console.log("Iniciando seed..."); + + await prisma.exercise.deleteMany(); + await prisma.topic.deleteMany(); + await prisma.video.deleteMany(); + await prisma.theme.deleteMany(); + + const themesData = await csvToJSON("themes"); + const topicsData = await csvToJSON("topics"); + const exercisesData = await csvToJSON("exercises"); + const videosData = await csvToJSON("videos"); + + const themeTitleToId = new Map(); + const topicTitleToId = new Map(); + const videoTitleToId = new Map(); + + let exerciseCount = 0; + let themeCount = 0; + + const urlRegex = /\((https?:\/\/[^\s)]+)\)/; + + for (const theme of themesData) { + const matchImageURL = theme.image.match(urlRegex); + + const createdTheme = await prisma.theme.create({ + data: { + title: theme.title, + description: theme.description, + shortDescription: theme.cardDescription, + image: + matchImageURL && matchImageURL.length > 1 ? matchImageURL[1] : "", + category: + theme.category === "Nivelamento" + ? ThemeCategory.Leveling + : ThemeCategory.SelfStudy, + sequence: ++themeCount, + alt: theme.alt, + }, + }); + themeTitleToId.set(createdTheme.title, createdTheme.id); + } + + for (const topic of topicsData) { + const themeId = themeTitleToId.get(topic.themes); + + if (!themeId) { + console.warn(`Tema não encontrado para tópico: ${topic.title}`); + continue; + } + + const createdTopic = await prisma.topic.create({ + data: { + title: topic.title, + shortDescription: topic.cardDescription, + description: topic.description, + references: topic.references, + themeId, + }, + }); + + topicTitleToId.set(createdTopic.title, createdTopic.id); + } + + for (const video of videosData) { + const topicId = topicTitleToId.get(video.topics); + if (!topicId) { + console.warn(`Tópico não encontrado para vídeo: ${video.title}`); + continue; + } + const createdVideo = await prisma.video.create({ + data: { + title: video.title, + description: video.description, + references: video.references, + link: video.link, + topicId, + }, + }); + + videoTitleToId.set(createdVideo.title, createdVideo.id); + } + + for (const exercise of exercisesData) { + const topicId = topicTitleToId.get(exercise.topics); + if (!topicId) { + console.warn(`Tópico não encontrado para exercício: ${exercise.title}`); + continue; + } + + await prisma.exercise.create({ + data: { + title: exercise.title, + shortDescription: exercise.cardDescription, + description: exercise.description, + sequence: ++exerciseCount, + topicId, + }, + }); + } + + console.log("Seed concluído com sucesso!"); +} + +main() + .catch((e) => { + console.error("Erro no seed:", e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/singleton.ts b/singleton.ts new file mode 100644 index 0000000..78abbc5 --- /dev/null +++ b/singleton.ts @@ -0,0 +1,15 @@ +import { PrismaClient } from "@prisma/client"; +import { DeepMockProxy, mockDeep, mockReset } from "jest-mock-extended"; + +import prisma from "./client.js"; + +jest.mock("./client", () => ({ + __esModule: true, + default: mockDeep(), +})); + +beforeEach(() => { + mockReset(prismaMock); +}); + +export const prismaMock = prisma as unknown as DeepMockProxy; diff --git a/src/controllers/exercise/ExerciseController.ts b/src/controllers/exercise/ExerciseController.ts new file mode 100644 index 0000000..6817c4d --- /dev/null +++ b/src/controllers/exercise/ExerciseController.ts @@ -0,0 +1,158 @@ +import { plainToInstance } from 'class-transformer'; +import { ValidationError, validateOrReject } from 'class-validator'; +import type { Request, Response } from 'express'; +import { GetExerciseByIdDTO } from '../../dtos/GetExerciseById.dto.js'; +import { GetExercisesByTopicIdDTO } from '../../dtos/GetExercisesByTopicId.dto.js'; +import { CreateExerciseDTO } from '../../dtos/CreateExercise.dto.js'; +import { UpdateExerciseDTO } from '../../dtos/UpdateExercise.dto.js'; +import { ExerciseService } from '../../services/exercise/ExerciseService.js'; +import { STATUS_CODE } from '../../utils/constants.js'; +import { getPaginationParams } from '../../utils/pagination.js'; + +export class ExerciseController { + private exerciseService: ExerciseService; + + constructor() { + this.exerciseService = new ExerciseService(); + } + + async getAllExercises(req: Request, res: Response) { + try { + const { page, limit } = getPaginationParams(req); + const exercises = await this.exerciseService.getAllExercises(page, limit); + return res.status(STATUS_CODE.OK).json(exercises); + } catch (_error) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: 'Error fetching exercises' }); + } + } + + async getExerciseById(req: Request, res: Response) { + const dto = plainToInstance(GetExerciseByIdDTO, req.params, { + enableImplicitConversion: true, + }); + + try { + await validateOrReject(dto); + const exercise = await this.exerciseService.getExerciseById(dto.id); + + if (!exercise) { + return res + .status(STATUS_CODE.NOT_FOUND) + .json({ message: 'Exercise not found' }); + } + + return res.status(STATUS_CODE.OK).json(exercise); + } catch (error) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res + .status(STATUS_CODE.BAD_REQUEST) + .json({ message: 'Invalid Exercise ID' }); + } + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: 'Error fetching exercise' }); + } + } + + async getExercisesByTopicId(req: Request, res: Response) { + const dto = plainToInstance(GetExercisesByTopicIdDTO, req.params, { + enableImplicitConversion: true, + }); + + try { + await validateOrReject(dto); + const exercises = await this.exerciseService.getExercisesByTopicId( + dto.topicId, + ); + return res.status(STATUS_CODE.OK).json(exercises); + } catch (error) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res + .status(STATUS_CODE.BAD_REQUEST) + .json({ message: 'Invalid Topic ID' }); + } + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: 'Error fetching exercises by topic ID' }); + } + } + + async createExercise(req: Request, res: Response) { + const dto = plainToInstance(CreateExerciseDTO, req.body, { + enableImplicitConversion: true, + }); + + try { + await validateOrReject(dto); + + const exercise = await this.exerciseService.createExercise(dto); + + return res.status(STATUS_CODE.CREATED).json(exercise); + } catch (error: any) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: error[0].constraints?.isNotEmpty || 'Invalid data', + }); + } + + return res.status(STATUS_CODE.INTERNAL_SERVER_ERROR).json({ + message: 'Error creating exercise', + details: error, + }); + } + } + + async updateExercise(req: Request, res: Response) { + const id = req.params.id.trim(); + + const dto = plainToInstance(UpdateExerciseDTO, req.body, { + enableImplicitConversion: true, + }); + + try { + await validateOrReject(dto); + + const exercise = await this.exerciseService.updateExercise(id, dto); + + return res.status(STATUS_CODE.OK).json(exercise); + } catch (error: any) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: 'Invalid data for update', + }); + } + + return res.status(STATUS_CODE.INTERNAL_SERVER_ERROR).json({ + message: 'Error updating exercise', + details: error, + }); + } + } + + async deleteExercise(req: Request, res: Response) { + const id = req.params.id.trim(); + + try { + const exercise = await this.exerciseService.deleteExercise(id); + return res.status(STATUS_CODE.OK).json(exercise); + } catch (error: any) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: 'Error deleting exercise', details: error }); + } + } +} diff --git a/src/controllers/login/LoginController.test.ts b/src/controllers/login/LoginController.test.ts new file mode 100644 index 0000000..3ac0e20 --- /dev/null +++ b/src/controllers/login/LoginController.test.ts @@ -0,0 +1,156 @@ +/** biome-ignore-all lint/complexity/useLiteralKeys: Usamos modificador de acesso private para as dependencias */ +import type { Request, Response } from 'express'; +import { TokenService } from '../../services/TokenService.js'; +import { STATUS_CODE } from '../../utils/constants.js'; +import { LoginController } from './LoginController.js'; +import { Role } from '@prisma/client'; + +jest.mock('../../services/TokenService'); +let controller: LoginController; +let req: Partial; +let res: Partial; +let mockTokenService: jest.Mocked; + +describe('LoginController - registerUser', () => { + beforeEach(() => { + mockTokenService = new TokenService() as jest.Mocked; + + controller = new LoginController(); + controller['tokenService'] = mockTokenService; + + req = { + headers: { authorization: 'Bearer eysncskwnsopmcsabuwsa' }, + user: { + email: 'test@gmail.com', + id: 1, + role: Role.VIEWER, + }, + }; + res = { + json: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('Verifica se o token é expirado ou invalido, deve retornar: "Expired or invalid token"', async () => { + req = { headers: { authorization: 'eynkdsflmdnas' } }; + + await controller.registerUser(req as Request, res as Response); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.TOKEN_EXPIRED); + expect(res.json).toHaveBeenCalledWith({ + message: 'Expired or invalid token', + }); + }); + + it('Verifica se ocorreu erro ao extrair o token, deve retornar: "Error extracting token"', async () => { + mockTokenService.extractToken.mockResolvedValue(null); + + await controller.registerUser(req as Request, res as Response); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.INTERNAL_SERVER_ERROR); + expect(res.json).toHaveBeenCalledWith({ + message: 'Error extracting token', + }); + }); + + it('Verifica se o usuário existe no banco de dados, deve retornar: "User already exists"', async () => { + const date: Date = new Date(2025, 1, 25); + + mockTokenService.extractToken.mockResolvedValue({ + accessToken: 'eysdnsdnsakns', + email: 'usuariaaceleradora@gmail.com', + exp: 5689, + iat: 4567, + id: '1', + jti: 'njjdkmk', + name: 'Milena', + provider: 'google', + sub: '1568888', + }); + + mockTokenService.findUserByEmail.mockResolvedValue({ + email: 'usuariaaceleradora@gmail.com', + id: 1, + loginDate: date, + provider: 'google', + role: Role.VIEWER, + }); + + await controller.registerUser(req as Request, res as Response); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.OK); + expect(res.json).toHaveBeenCalledWith({ message: 'User already exists' }); + }); + + it('Verifica se ocorreu um erro ao registrar o usuário, deve retornar: "Error registering user"', async () => { + mockTokenService.extractToken.mockResolvedValue({ + accessToken: 'eysdnsdnsakns', + email: 'usuariaaceleradora@gmail.com', + exp: 5689, + iat: 4567, + id: '1', + jti: 'njjdkmk', + name: 'Milena', + provider: 'google', + sub: '1568888', + }); + + mockTokenService.findUserByEmail.mockResolvedValue(null); + + mockTokenService.registerUser.mockResolvedValue(null); + + await controller.registerUser(req as Request, res as Response); + + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.INTERNAL_SERVER_ERROR); + expect(res.json).toHaveBeenCalledWith({ + message: 'Error registering user', + }); + }); + + it('Verifica se ocorreu uma exceção ao criar usuário, deve retornar: "Error processing the created user"', async () => { + mockTokenService.extractToken.mockRejectedValue( + new Error('Error processing the created user'), + ); + + await controller.registerUser(req as Request, res as Response); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.INTERNAL_SERVER_ERROR); + expect(res.json).toHaveBeenCalledWith({ + message: 'Error processing the created user', + }); + }); + + it('Verifica se o usuário foi criado com sucesso , deve retornar: "User created successfully!"', async () => { + const date: Date = new Date(2025, 1, 25); + + mockTokenService.extractToken.mockResolvedValue({ + accessToken: 'eysdnsdnsakns', + email: 'usuariaaceleradora@gmail.com', + exp: 5689, + iat: 4567, + id: '1', + jti: 'njjdkmk', + name: 'Milena', + provider: 'google', + sub: '1568888', + }); + + mockTokenService.findUserByEmail.mockResolvedValue(null); + + mockTokenService.registerUser.mockResolvedValue({ + email: 'test@gmail.com', + id: 2, + loginDate: date, + provider: 'github', + role: Role.VIEWER, + }); + + await controller.registerUser(req as Request, res as Response); + + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.OK); + expect(res.json).toHaveBeenCalledWith({ + message: 'User created successfully!', + }); + }); +}); diff --git a/src/controllers/login/LoginController.ts b/src/controllers/login/LoginController.ts new file mode 100644 index 0000000..cec9af0 --- /dev/null +++ b/src/controllers/login/LoginController.ts @@ -0,0 +1,55 @@ +import type { Request, Response } from "express"; +import { TokenService } from "../../services/TokenService.js"; +import { STATUS_CODE } from "../../utils/constants.js"; + +export class LoginController { + private tokenService: TokenService; + + constructor() { + this.tokenService = new TokenService(); + } + + async registerUser(req: Request, res: Response) { + const token = req.headers.authorization?.split(" ")[1]; + + if (!token) { + return res + .status(STATUS_CODE.TOKEN_EXPIRED) + .json({ message: "Expired or invalid token" }); + } + + try { + const extractToken = await this.tokenService.extractToken(token); + + if (!extractToken) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: "Error extracting token" }); + } + + const findUser = await this.tokenService.findUserByEmail(extractToken); + + if (findUser) { + return res + .status(STATUS_CODE.OK) + .json({ message: "User already exists" }); + } + + const createdUser = await this.tokenService.registerUser(extractToken); + + if (!createdUser) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: "Error registering user" }); + } + + return res + .status(STATUS_CODE.OK) + .json({ message: "User created successfully!" }); + } catch (_error) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: "Error processing the created user" }); + } + } +} diff --git a/src/controllers/progress/ProgressController.test.ts b/src/controllers/progress/ProgressController.test.ts new file mode 100644 index 0000000..36de8b4 --- /dev/null +++ b/src/controllers/progress/ProgressController.test.ts @@ -0,0 +1,393 @@ +/** biome-ignore-all lint/complexity/useLiteralKeys: Usamos modificador de acesso private para as dependencias */ +import { ElementType, ItemStatus, Role } from '@prisma/client'; +import { plainToClass } from 'class-transformer'; +import { validateSync } from 'class-validator'; +import type { Request, Response } from 'express'; +import { ProgressController } from '../../controllers/progress/ProgressController.js'; +import { SaveStatusProgressDTO } from '../../dtos/SaveStatusProgress.dto.js'; +import { ProgressService } from '../../services/progress/ProgressService.js'; +import { StackbyService } from '../../services/StackbyService.js'; +import type { SingleProgressResponse } from '../../types/types.js'; +import { STATUS_CODE } from '../../utils/constants.js'; + +jest.mock('../../services/Progress/ProgressService'); +jest.mock('../../services/UserService'); +jest.mock('../../services/StackbyService'); +jest.mock('../../middleware/validateTokenMiddleware', () => ({ + validateTokenMiddleware: jest.fn(), +})); + +let controller: ProgressController; +let req: Partial; +let res: Partial; +let mockProgressService: jest.Mocked; +let mockStackbyService: jest.Mocked; + +describe('Progress Controller Unit Tests', () => { + describe('getTopicProgress', () => { + let controller: ProgressController; + let req: Partial; + let res: Partial; + + beforeEach(() => { + mockProgressService = + new ProgressService() as jest.Mocked; + mockStackbyService = new StackbyService() as jest.Mocked; + controller = new ProgressController(); + controller['progressService'] = mockProgressService; + controller['stackbyService'] = mockStackbyService; + + req = { + params: { id: '1', idType: 'topicId' }, + query: { totalItens: '12' }, + user: { + email: 'test@gmail.com', + id: 1, + role: Role.VIEWER, + }, + }; + res = { + json: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('deve retornar 400 se faltarem params ou query inválida', async () => { + req.params = {}; + await controller.getTopicExercisesStatusProgress( + req as Request, + res as Response, + ); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.BAD_REQUEST); + + req.params = { topicId: '1' }; + req.query = {}; + await controller.getTopicExercisesStatusProgress( + req as Request, + res as Response, + ); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.BAD_REQUEST); + + req.query = { totalItens: '1ab' }; + await controller.getTopicExercisesStatusProgress( + req as Request, + res as Response, + ); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.BAD_REQUEST); + + req.query = { totalItens: '-5' }; + await controller.getTopicExercisesStatusProgress( + req as Request, + res as Response, + ); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.BAD_REQUEST); + }); + + it('deve retornar 500 em erro interno do service', async () => { + mockStackbyService.calculateTotalItems.mockReturnValue(10); + mockProgressService.getProgressPercentageById.mockRejectedValue( + new Error('err'), + ); + await controller.getProgressPercentageById( + req as Request, + res as Response, + ); + expect(res.status).toHaveBeenCalledWith( + STATUS_CODE.INTERNAL_SERVER_ERROR, + ); + expect(res.json).toHaveBeenCalledWith({ + message: 'Error processing the request', + }); + }); + + it('deve retornar 200 e o progresso quando tudo OK', async () => { + mockStackbyService.calculateTotalItems.mockReturnValue(10); + mockProgressService.getProgressPercentageById.mockResolvedValue({ + progress: 75, + }); + + await controller.getProgressPercentageById( + req as Request, + res as Response, + ); + + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.OK); + expect(res.json).toHaveBeenCalledWith({ progress: 75 }); + }); + }); + + describe('UpdateStatusDto', () => { + it('é válido para um itemStatus Enum correto', () => { + const dto = plainToClass(SaveStatusProgressDTO, { + elementType: ElementType.Exercise, + itemStatus: ItemStatus.Completed, + themeId: '1', + }); + const errors = validateSync(dto); + expect(errors).toHaveLength(0); + }); + + it('é inválido para um itemStatus inválido', () => { + const dto = plainToClass(SaveStatusProgressDTO, { + elementType: ElementType.Exercise, + itemStatus: 'Finished' as ItemStatus, + themeId: '1', + }); + const errors = validateSync(dto); + expect(errors.length).toBeGreaterThan(0); + expect(errors[0].constraints).toHaveProperty('isEnum'); + }); + }); + + describe('saveStatusProgress', () => { + beforeEach(() => { + mockProgressService = + new ProgressService() as jest.Mocked; + controller = new ProgressController(); + controller['progressService'] = mockProgressService; + + req = { + body: { itemStatus: 'NotStarted' }, + params: { itemId: '1', topicId: '1' }, + user: { + email: 'test@gmail.com', + id: 1, + role: Role.VIEWER, + }, + }; + res = { + json: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('deve retornar o progresso atualizado ao mudar o status ou criar um novo registro', async () => { + const progress = { + elementType: ElementType.Exercise, + itemId: 'rw12346789', + itemStatus: ItemStatus.InProgress, + modifiedAt: new Date(), + themeId: '1', + topicId: 'rw987654321', + userId: 1, + }; + + mockProgressService.saveStatusProgress.mockResolvedValue(progress); + await controller.saveStatusProgress(req as Request, res as Response); + + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.OK); + expect(res.json).toHaveBeenCalledWith(progress); + }); + + it('deve retornar "Internal server error while processing the request" em caso de erro no servidor', async () => { + mockProgressService.saveStatusProgress.mockRejectedValue( + new Error('Internal server error'), + ); + + await controller.saveStatusProgress(req as Request, res as Response); + + expect(res.status).toHaveBeenCalledWith( + STATUS_CODE.INTERNAL_SERVER_ERROR, + ); + expect(res.json).toHaveBeenCalledWith({ + message: 'Internal server error while processing the request', + }); + }); + }); + + describe('getTopicExercisesStatusProgress', () => { + beforeEach(() => { + mockProgressService = + new ProgressService() as jest.Mocked; + + controller = new ProgressController(); + controller['progressService'] = mockProgressService; + + req = { + params: { + id: '1', + idType: 'topicId', + }, + user: { + email: 'test@gmail.com', + id: 1, + role: Role.VIEWER, + }, + }; + res = { + json: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + }); + + it("deve retornar 'topicId não encontrado' se o topicId não existir", async () => { + mockProgressService.getAllStatusProgressById.mockResolvedValue([]); + + await controller.getTopicExercisesStatusProgress( + req as Request, + res as Response, + ); + + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.NOT_FOUND); + expect(res.json).toHaveBeenCalledWith({ message: 'Progress not found' }); + }); + + it("deve retornar 'Progresso não encontrado' se o status do exercício não for encontrado", async () => { + req.params = { + itemId: '1', + }; + + mockProgressService.getAllStatusProgressById.mockResolvedValue([]); + + await controller.getExerciseStatusProgress( + req as Request, + res as Response, + ); + + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.NOT_FOUND); + expect(res.json).toHaveBeenCalledWith({ message: 'Status not found' }); + }); + + it("deve retornar 'Erro ao processar a solicitação' se ocorrer um erro", async () => { + mockProgressService.getAllStatusProgressById.mockRejectedValue( + new Error('err'), + ); + await controller.getTopicExercisesStatusProgress( + req as Request, + res as Response, + ); + + expect(res.status).toHaveBeenCalledWith( + STATUS_CODE.INTERNAL_SERVER_ERROR, + ); + expect(res.json).toHaveBeenCalledWith({ + message: 'Error processing the request', + }); + }); + + it('deve retornar a lista de status dos exercícios quando disponível', async () => { + const statusList: SingleProgressResponse[] = [ + { + elementType: ElementType.Exercise, + itemId: 'rw1726148766181e6dab5', + itemStatus: ItemStatus.Completed, + modifiedAt: new Date(), + themeId: '1', + topicId: 'rw17212367802520ba251', + userId: 1, + }, + ]; + + mockProgressService.getAllStatusProgressById.mockResolvedValue( + statusList, + ); + + await controller.getTopicExercisesStatusProgress( + req as Request, + res as Response, + ); + + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.OK); + expect(res.json).toHaveBeenCalledWith(statusList); + }); + }); + + describe('getExerciseStatusProgress', () => { + beforeEach(() => { + mockProgressService = + new ProgressService() as jest.Mocked; + + controller = new ProgressController(); + controller['progressService'] = mockProgressService; + + req = { + params: { itemId: '2', topicId: '1' }, + user: { + email: 'test@gmail.com', + id: 1, + role: Role.VIEWER, + }, + }; + res = { + json: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + }); + + it("deve retornar 'itemId não encontrado' se o itemId não existir", async () => { + req.params = { ...req.params, itemId: '' }; + mockProgressService.getAllStatusProgressById.mockResolvedValue([]); + + await controller.getExerciseStatusProgress( + req as Request, + res as Response, + ); + + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.BAD_REQUEST); + expect(res.json).toHaveBeenCalledWith({ + message: 'You must pass an itemId and a topicId as params.', + }); + }); + it("deve retornar 'status não encontrado' se o status não for encontrado", async () => { + mockProgressService.getAllStatusProgressById.mockResolvedValue([]); + + await controller.getExerciseStatusProgress( + req as Request, + res as Response, + ); + + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.NOT_FOUND); + expect(res.json).toHaveBeenCalledWith({ message: 'Status not found' }); + }); + + it("deve retornar 'Erro ao processar a solicitação' se ocorrer um erro", async () => { + mockProgressService.getSingleStatusProgressByItemId.mockRejectedValue( + new Error('INTERNAL_SERVER_ERROR'), + ); + + await controller.getExerciseStatusProgress( + req as Request, + res as Response, + ); + + expect(res.status).toHaveBeenCalledWith( + STATUS_CODE.INTERNAL_SERVER_ERROR, + ); + expect(res.json).toHaveBeenCalledWith({ + message: 'Error processing the request', + }); + }); + + it('deve retornar um objeto com itemStatus e itemId quando disponível', async () => { + const exerciseSuccess: SingleProgressResponse = { + elementType: ElementType.Exercise, + itemId: 'rw1726148766181e6dab5', + itemStatus: ItemStatus.InProgress, + modifiedAt: new Date(), + themeId: 'q', + topicId: 'q', + userId: 1, + }; + + mockProgressService.getSingleStatusProgressByItemId.mockResolvedValue( + exerciseSuccess, + ); + + await controller.getExerciseStatusProgress( + req as Request, + res as Response, + ); + + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.OK); + expect(res.json).toHaveBeenCalledWith(exerciseSuccess); + }); + }); +}); diff --git a/src/controllers/progress/ProgressController.ts b/src/controllers/progress/ProgressController.ts new file mode 100644 index 0000000..2f3a8cc --- /dev/null +++ b/src/controllers/progress/ProgressController.ts @@ -0,0 +1,197 @@ +import { plainToInstance } from "class-transformer"; +import { validateOrReject } from "class-validator"; +import type { Request, Response } from "express"; +import { ProgressDTO } from "../../dtos/Progress.dto.js"; +import { SaveStatusProgressDTO } from "../../dtos/SaveStatusProgress.dto.js"; +import { ProgressService } from "../../services/progress/ProgressService.js"; +import { StackbyService } from "../../services/StackbyService.js"; +import { IdType, StackbyEndpoint } from "../../types/types.js"; +import { + STACKBY_ENDPOINTS_HASHTABLE, + STATUS_CODE, +} from "../../utils/constants.js"; + +export class ProgressController { + private progressService: ProgressService; + private stackbyService: StackbyService; + + constructor() { + this.progressService = new ProgressService(); + this.stackbyService = new StackbyService(); + } + + async getProgressPercentageById(req: Request, res: Response) { + const dto = plainToInstance(ProgressDTO, req.params); + const userId = req.user?.id; + + try { + if (!userId) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: "Missing userId. You must pass a valid userId.", + }); + } + await validateOrReject(dto); + + const { id, idType } = dto; + + const endpoint = STACKBY_ENDPOINTS_HASHTABLE[idType as IdType]; + if (!endpoint) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: "You must pass a valid id and an idType as params.", + }); + } + + const topics = await this.stackbyService.fetchStackbyData( + StackbyEndpoint.TOPICS, + ); + if (idType === IdType.THEME_ID) { + const themes = await this.stackbyService.fetchStackbyData( + StackbyEndpoint.THEMES, + ); + const totalItems = this.stackbyService.calculateTotalItems( + id, + endpoint, + themes, + topics, + ); + const result = await this.progressService.getProgressPercentageById( + { id, idType, userId }, + totalItems, + themes, + topics, + ); + return res.status(STATUS_CODE.OK).json(result); + } else { + const totalItems = this.stackbyService.calculateTotalItems( + id, + endpoint, + topics, + ); + const topicProgress = + await this.progressService.getProgressPercentageById( + { + id, + idType, + userId, + }, + totalItems, + ); + return res.status(STATUS_CODE.OK).json(topicProgress); + } + } catch (_error) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: "Error processing the request" }); + } + } + + async saveStatusProgress(req: Request, res: Response) { + const { topicId, itemId } = req.params; + const dto = plainToInstance(SaveStatusProgressDTO, req.body); + + const userId = req.user?.id; + + try { + await validateOrReject(dto); + const { elementType, itemStatus, themeId } = dto; + + if (!userId) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: "Missing userId. You must pass a valid userId.", + }); + } + + const updatedProgress = await this.progressService.saveStatusProgress({ + elementType, + itemId, + itemStatus, + themeId, + topicId, + userId, + }); + + return res.status(STATUS_CODE.OK).json(updatedProgress); + } catch (_error) { + return res.status(STATUS_CODE.INTERNAL_SERVER_ERROR).json({ + message: "Internal server error while processing the request", + }); + } + } + + async getTopicExercisesStatusProgress(req: Request, res: Response) { + const dto = plainToInstance(ProgressDTO, req.params); + const userId = req.user?.id; + + try { + await validateOrReject(dto); + const { idType, id } = dto; + + if (!userId) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: "Missing userId. You must pass a valid userId.", + }); + } + + if (!idType || !id) { + return res + .status(STATUS_CODE.BAD_REQUEST) + .json({ message: "You must pass an id and an idType as params." }); + } + const allProgressByTopic = + await this.progressService.getAllStatusProgressById({ + id, + idType: IdType.TOPIC_ID, + userId, + }); + + if (allProgressByTopic.length === 0) { + return res + .status(STATUS_CODE.NOT_FOUND) + .json({ message: "Progress not found" }); + } + + return res.status(STATUS_CODE.OK).json(allProgressByTopic); + } catch (_error) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: "Error processing the request" }); + } + } + + async getExerciseStatusProgress(req: Request, res: Response) { + const { itemId } = req.params; + const userId = req.user?.id; + + if (!userId) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: "Missing userId. You must pass a valid userId.", + }); + } + + if (!itemId) { + return res + .status(STATUS_CODE.BAD_REQUEST) + .json({ message: "You must pass an itemId and a topicId as params." }); + } + + try { + const exerciseStatus = + await this.progressService.getSingleStatusProgressByItemId( + itemId, + userId, + ); + + if (!exerciseStatus) { + return res + .status(STATUS_CODE.NOT_FOUND) + .json({ message: "Status not found" }); + } + + return res.status(STATUS_CODE.OK).json(exerciseStatus); + } catch (_error) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: "Error processing the request" }); + } + } +} diff --git a/src/controllers/stackby/StackbyController.test.ts b/src/controllers/stackby/StackbyController.test.ts new file mode 100644 index 0000000..e459136 --- /dev/null +++ b/src/controllers/stackby/StackbyController.test.ts @@ -0,0 +1,87 @@ +import type { NextFunction, Request, Response } from "express"; +import { StackbyEndpoint } from "../../types/types.js"; +import { STATUS_CODE } from "../../utils/constants.js"; +import { StackbyController } from "./StackbyController.js"; + +describe("StackbyController", () => { + let controller: StackbyController; + let req: Partial; + let res: Partial; + let next: jest.MockedFunction; + + beforeEach(() => { + controller = new StackbyController(); + req = { params: {} }; + res = { + json: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + next = jest.fn() as jest.MockedFunction; + jest.clearAllMocks(); + }); + + describe("getStackbyData", () => { + it("retorna 400 se endpoint for inválido", async () => { + req.params = { endpoint: "Invalid" }; + await controller.getStackbyData( + req as Request, + res as Response, + next as NextFunction, + ); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.BAD_REQUEST); + expect(res.json).toHaveBeenCalledWith({ + message: "Endpoint must be one of: Exercises, Topics, Themes", + }); + }); + + it("retorna 400 se endpoint não for informado", async () => { + req.params = {}; + await controller.getStackbyData( + req as Request, + res as Response, + next as NextFunction, + ); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.BAD_REQUEST); + expect(res.json).toHaveBeenCalledWith({ + message: "Endpoint must be one of: Exercises, Topics, Themes", + }); + }); + + it("retorna 200 e os dados em caso de sucesso", async () => { + req.params = { endpoint: StackbyEndpoint.TOPICS }; + const fetchMock = jest + // biome-ignore lint/suspicious/noExplicitAny: TODO: WIP + .spyOn((controller as any).stackyByService, "fetchStackbyData") + .mockResolvedValue({ data: "ok" }); + await controller.getStackbyData( + req as Request, + res as Response, + next as NextFunction, + ); + expect(fetchMock).toHaveBeenCalledWith(StackbyEndpoint.TOPICS); + expect(res.status).toHaveBeenCalledWith(STATUS_CODE.OK); + expect(res.json).toHaveBeenCalledWith({ data: "ok" }); + fetchMock.mockRestore(); + }); + + it("retorna 500 em erro interno", async () => { + req.params = { endpoint: StackbyEndpoint.THEMES }; + const fetchMock = jest + // biome-ignore lint/suspicious/noExplicitAny: TODO: WIP + .spyOn((controller as any).stackyByService, "fetchStackbyData") + .mockRejectedValue(new Error("fail")); + await controller.getStackbyData( + req as Request, + res as Response, + next as NextFunction, + ); + expect(res.status).toHaveBeenCalledWith( + STATUS_CODE.INTERNAL_SERVER_ERROR, + ); + expect(res.json).toHaveBeenCalledWith({ + message: "Error processing the request", + }); + fetchMock.mockRestore(); + }); + }); +}); diff --git a/src/controllers/stackby/StackbyController.ts b/src/controllers/stackby/StackbyController.ts new file mode 100644 index 0000000..11bb069 --- /dev/null +++ b/src/controllers/stackby/StackbyController.ts @@ -0,0 +1,43 @@ +import { plainToInstance } from "class-transformer"; +import { validateOrReject } from "class-validator"; +import type { NextFunction, Request, Response } from "express"; +import { StackbyParamsDto } from "../../dtos/StackbyEndpoint.dto.js"; +import { BadRequestError } from "../../errors/HttpErrors.js"; +import { StackbyService } from "../../services/StackbyService.js"; +import { STATUS_CODE } from "../../utils/constants.js"; +import { buildStackbyFilter } from "../../utils/filter-factory.js"; + +export class StackbyController { + private stackbyService: StackbyService; + + constructor() { + this.stackbyService = new StackbyService(); + } + + async getStackbyData(req: Request, res: Response, next: NextFunction) { + try { + const payload = { ...req.params, ...req.query }; + + const dto = plainToInstance(StackbyParamsDto, payload, { + enableImplicitConversion: true, + }); + + await validateOrReject(dto); + + if (!dto.endpoint) { + throw new BadRequestError( + "An endpoint is required. Must be 'Exercises', 'Topics' or 'Themes'.", + ); + } + + const { endpoint } = dto; + + const filter = buildStackbyFilter(dto); + + const data = await this.stackbyService.fetchStackbyData(endpoint, filter); + return res.status(STATUS_CODE.OK).json(data); + } catch (error) { + next(error); + } + } +} diff --git a/src/controllers/theme/ThemeController.ts b/src/controllers/theme/ThemeController.ts new file mode 100644 index 0000000..e8aa637 --- /dev/null +++ b/src/controllers/theme/ThemeController.ts @@ -0,0 +1,136 @@ +import { plainToInstance } from "class-transformer"; +import { ValidationError, validateOrReject } from "class-validator"; +import type { Request, Response } from "express"; +import { GetThemeByCategoryDTO } from "../../dtos/GetThemeByCategory.dto.js"; +import { GetThemeByIdDTO } from "../../dtos/GetThemeById.dto.js"; +import { CreateThemeDTO } from "../../dtos/CreateTheme.dto.js"; +import { UpdateThemeDTO } from "../../dtos/UpdateTheme.dto.js"; +import { ThemeService } from "../../services/theme/ThemeService.js"; +import { STATUS_CODE } from "../../utils/constants.js"; +import { getPaginationParams } from "../../utils/pagination.js"; + +export class ThemeController { + private themeService: ThemeService; + + constructor() { + this.themeService = new ThemeService(); + } + + async createTheme(req: Request, res: Response) { + const dto = plainToInstance(CreateThemeDTO, req.body, { + enableImplicitConversion: true, + }); + + try { + await validateOrReject(dto); + + const theme = await this.themeService.createTheme(dto); + + return res.status(STATUS_CODE.CREATED).json(theme); + } catch (error: any) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: error[0].constraints?.isNotEmpty || "Invalid data", + }); + } + + return res.status(STATUS_CODE.INTERNAL_SERVER_ERROR).json({ + message: "Error creating theme", + details: error, + }); + } + } + + async getThemes(req: Request, res: Response) { + const dto = plainToInstance(GetThemeByCategoryDTO, req.query, { + enableImplicitConversion: true, + }); + try { + await validateOrReject(dto); + const { page, limit } = getPaginationParams(req); + const result = await this.themeService.getThemes(dto.category, page, limit); + return res.status(STATUS_CODE.OK).json(result); + } catch (_error) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: "Error fetching themes", details: _error }); + } + } + + async getThemeById(req: Request, res: Response) { + const dto = plainToInstance(GetThemeByIdDTO, req.params, { + enableImplicitConversion: true, + }); + try { + await validateOrReject(dto); + const theme = await this.themeService.getThemeById(dto.id); + + if (!theme) { + return res + .status(STATUS_CODE.NOT_FOUND) + .json({ message: "Theme not found" }); + } + return res.status(STATUS_CODE.OK).json(theme); + } catch (error) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: error[0].constraints?.isNotEmpty || "Invalid Theme ID", + }); + } + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ details: error, message: "Error fetching theme" }); + } + } + + + async updateTheme(req: Request, res: Response) { + const id = req.params.id.trim(); + + const dto = plainToInstance(UpdateThemeDTO, req.body, { + enableImplicitConversion: true, + }); + + try { + await validateOrReject(dto); + + const theme = await this.themeService.updateTheme(id, dto); + + return res.status(STATUS_CODE.OK).json(theme); + } catch (error: any) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: "Invalid data for update", + }); + } + + return res.status(STATUS_CODE.INTERNAL_SERVER_ERROR).json({ + message: "Error updating theme", + details: error, + }); + } + } + + async deleteTheme(req: Request, res: Response) { + const id = req.params.id.trim(); + + try { + const theme = await this.themeService.deleteTheme(id); + return res.status(STATUS_CODE.OK).json(theme); + } catch (error: any) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: "Error deleting theme", details: error }); + } + } + } + diff --git a/src/controllers/topic/TopicController.ts b/src/controllers/topic/TopicController.ts new file mode 100644 index 0000000..bd19040 --- /dev/null +++ b/src/controllers/topic/TopicController.ts @@ -0,0 +1,158 @@ +import { plainToInstance } from 'class-transformer'; +import { ValidationError, validateOrReject } from 'class-validator'; +import type { Request, Response } from 'express'; +import { GetTopicByIdDTO } from '../../dtos/GetTopicById.dto.js'; +import { GetTopicsByThemeIdDTO } from '../../dtos/GetTopicsByThemeId.dto.js'; +import { TopicService } from '../../services/topic/TopicService.js'; +import { STATUS_CODE } from '../../utils/constants.js'; +import { CreateTopicDTO } from '../../dtos/CreateTopic.dto.js'; +import { UpdateTopicDTO } from '../../dtos/UpdateTopic.dto.js'; +import { getPaginationParams } from '../../utils/pagination.js'; + +export class TopicController { + private topicService: TopicService; + + constructor() { + this.topicService = new TopicService(); + } + + async createTopic(req: Request, res: Response) { + const dto = plainToInstance(CreateTopicDTO, req.body, { + enableImplicitConversion: true, + }); + + try { + await validateOrReject(dto); + + const topic = await this.topicService.createTopic(dto); + + return res.status(STATUS_CODE.CREATED).json(topic); + } catch (error: any) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: error[0].constraints?.isNotEmpty || 'Invalid data', + }); + } + + return res.status(STATUS_CODE.INTERNAL_SERVER_ERROR).json({ + message: 'Error creating topic', + details: error, + }); + } + } + + async getAllTopics(req: Request, res: Response) { + try { + const { page, limit } = getPaginationParams(req); + const topics = await this.topicService.getAllTopics(page, limit); + return res.status(STATUS_CODE.OK).json(topics); + } catch (_error) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: 'Error fetching topics' }); + } + } + + async getTopicById(req: Request, res: Response) { + const dto = plainToInstance(GetTopicByIdDTO, req.params, { + enableImplicitConversion: true, + }); + + try { + await validateOrReject(dto); + const topic = await this.topicService.getTopicById(dto.id); + + if (!topic) { + return res + .status(STATUS_CODE.NOT_FOUND) + .json({ message: 'Topic not found' }); + } + + return res.status(STATUS_CODE.OK).json(topic); + } catch (error) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res + .status(STATUS_CODE.BAD_REQUEST) + .json({ message: 'Invalid Topic ID' }); + } + + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: 'Error fetching topic' }); + } + } + + async getTopicsByThemeId(req: Request, res: Response) { + const dto = plainToInstance(GetTopicsByThemeIdDTO, req.params, { + enableImplicitConversion: true, + }); + + try { + await validateOrReject(dto); + const topics = await this.topicService.getTopicsByThemeId(dto.themeId); + return res.status(STATUS_CODE.OK).json(topics); + } catch (error) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res + .status(STATUS_CODE.BAD_REQUEST) + .json({ message: 'Invalid Theme ID' }); + } + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: 'Error fetching topics by theme ID' }); + } + } + + async updateTopic(req: Request, res: Response) { + const id = req.params.id.trim(); + + const dto = plainToInstance(UpdateTopicDTO, req.body, { + enableImplicitConversion: true, + }); + + try { + await validateOrReject(dto); + + const topic = await this.topicService.updateTopic(id, dto); + + return res.status(STATUS_CODE.OK).json(topic); + } catch (error: any) { + if ( + Array.isArray(error) && + error.every((err) => err instanceof ValidationError) + ) { + return res.status(STATUS_CODE.BAD_REQUEST).json({ + message: 'Invalid data for update', + }); + } + + return res.status(STATUS_CODE.INTERNAL_SERVER_ERROR).json({ + message: 'Error updating topic', + details: error, + }); + } + } + + async deleteTopic(req: Request, res: Response) { + const id = req.params.id.trim(); + try { + await this.topicService.deleteTopic(id); + return res + .status(STATUS_CODE.OK) + .json({ message: 'Topic deleted with success' }); + } catch (error: any) { + return res + .status(STATUS_CODE.INTERNAL_SERVER_ERROR) + .json({ message: 'Error deleting topic', details: error }); + } + } +} diff --git a/src/dtos/CreateExercise.dto.ts b/src/dtos/CreateExercise.dto.ts new file mode 100644 index 0000000..96dc72f --- /dev/null +++ b/src/dtos/CreateExercise.dto.ts @@ -0,0 +1,23 @@ +import { IsBoolean, IsInt, IsNotEmpty, IsOptional, IsString } from "class-validator"; + +export class CreateExerciseDTO { + @IsString() + @IsNotEmpty({ message: "Title is required" }) + title!: string; + + @IsString() + @IsNotEmpty({ message: "Short description is required" }) + shortDescription!: string; + + @IsString() + @IsNotEmpty({ message: "Description is required" }) + description!: string; + + @IsOptional() + @IsInt() + sequence?: number; + + @IsOptional() + @IsString() + topicId?: string; +} diff --git a/src/dtos/CreateTheme.dto.ts b/src/dtos/CreateTheme.dto.ts new file mode 100644 index 0000000..9003f20 --- /dev/null +++ b/src/dtos/CreateTheme.dto.ts @@ -0,0 +1,27 @@ +import { ThemeCategory } from "@prisma/client"; +import { IsEnum, IsNotEmpty, IsOptional, IsString, IsInt } from "class-validator"; + +export class CreateThemeDTO { + @IsString() + @IsNotEmpty() + title!: string; + + @IsString() + description!: string; + + @IsString() + shortDescription!: string; + + @IsString() + image!: string; + + @IsString() + alt!: string; + + @IsEnum(ThemeCategory) + category!: ThemeCategory; + + @IsOptional() + @IsInt() + sequence?: number; +} diff --git a/src/dtos/CreateTopic.dto.ts b/src/dtos/CreateTopic.dto.ts new file mode 100644 index 0000000..79c1c5c --- /dev/null +++ b/src/dtos/CreateTopic.dto.ts @@ -0,0 +1,20 @@ +import { IsNotEmpty, IsOptional, IsString } from "class-validator"; + +export class CreateTopicDTO { + @IsString() + @IsNotEmpty() + title!: string; + + @IsString() + description!: string; + + @IsString() + shortDescription!: string; + + @IsString() + references!: string; + + @IsString() + @IsOptional() + themeId?: string; +} diff --git a/src/dtos/GetExerciseById.dto.ts b/src/dtos/GetExerciseById.dto.ts new file mode 100644 index 0000000..02843a9 --- /dev/null +++ b/src/dtos/GetExerciseById.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from "class-validator"; + +export class GetExerciseByIdDTO { + @IsString() + @IsNotEmpty({ message: "Exercise ID is required" }) + id!: string; +} diff --git a/src/dtos/GetExercisesByTopicId.dto.ts b/src/dtos/GetExercisesByTopicId.dto.ts new file mode 100644 index 0000000..6cb0a11 --- /dev/null +++ b/src/dtos/GetExercisesByTopicId.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from "class-validator"; + +export class GetExercisesByTopicIdDTO { + @IsString() + @IsNotEmpty({ message: "Topic ID is required" }) + topicId!: string; +} diff --git a/src/dtos/GetThemeByCategory.dto.ts b/src/dtos/GetThemeByCategory.dto.ts new file mode 100644 index 0000000..91837af --- /dev/null +++ b/src/dtos/GetThemeByCategory.dto.ts @@ -0,0 +1,11 @@ +import { ThemeCategory } from "@prisma/client"; +import { IsEnum, IsOptional } from "class-validator"; + +export class GetThemeByCategoryDTO { + @IsOptional() + @IsEnum(ThemeCategory, { + always: true, + message: `Category must be one of: ${Object.values(ThemeCategory).join(", ")}`, + }) + category!: ThemeCategory; +} diff --git a/src/dtos/GetThemeById.dto.ts b/src/dtos/GetThemeById.dto.ts new file mode 100644 index 0000000..88c14a1 --- /dev/null +++ b/src/dtos/GetThemeById.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from "class-validator"; + +export class GetThemeByIdDTO { + @IsString() + @IsNotEmpty({ message: "Theme ID is required" }) + id!: string; +} diff --git a/src/dtos/GetThemes.dto.ts b/src/dtos/GetThemes.dto.ts new file mode 100644 index 0000000..00dd1c9 --- /dev/null +++ b/src/dtos/GetThemes.dto.ts @@ -0,0 +1,10 @@ +import { IsEnum, IsOptional } from "class-validator"; +import { ThemeType } from "../types/types.js"; + +export class GetThemesDTO { + @IsOptional() + @IsEnum(ThemeType, { + message: "Invalid type parameter. Must be 'nivelamento' or 'autoestudo'.", + }) + themeType?: ThemeType; +} diff --git a/src/dtos/GetTopicById.dto.ts b/src/dtos/GetTopicById.dto.ts new file mode 100644 index 0000000..354425e --- /dev/null +++ b/src/dtos/GetTopicById.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from "class-validator"; + +export class GetTopicByIdDTO { + @IsString() + @IsNotEmpty({ message: "Topic ID is required" }) + id!: string; +} diff --git a/src/dtos/GetTopicsByThemeId.dto.ts b/src/dtos/GetTopicsByThemeId.dto.ts new file mode 100644 index 0000000..37a9838 --- /dev/null +++ b/src/dtos/GetTopicsByThemeId.dto.ts @@ -0,0 +1,7 @@ +import { IsNotEmpty, IsString } from "class-validator"; + +export class GetTopicsByThemeIdDTO { + @IsString() + @IsNotEmpty({ message: "Theme ID is required" }) + themeId!: string; +} diff --git a/src/dtos/Progress.dto.ts b/src/dtos/Progress.dto.ts new file mode 100644 index 0000000..f2dff0f --- /dev/null +++ b/src/dtos/Progress.dto.ts @@ -0,0 +1,11 @@ +import { IsEnum } from "class-validator"; +import { IdType } from "../types/types.js"; + +export class ProgressDTO { + id!: string; + + @IsEnum(IdType, { + message: "Invalid or missing element idType.", + }) + idType!: IdType; +} diff --git a/src/dtos/SaveStatusProgress.dto.ts b/src/dtos/SaveStatusProgress.dto.ts new file mode 100644 index 0000000..2a29747 --- /dev/null +++ b/src/dtos/SaveStatusProgress.dto.ts @@ -0,0 +1,16 @@ +import { ElementType, ItemStatus } from "@prisma/client"; +import { IsEnum } from "class-validator"; + +export class SaveStatusProgressDTO { + themeId!: string; + + @IsEnum(ElementType, { + message: "Invalid or missing element type.", + }) + elementType!: ElementType; + + @IsEnum(ItemStatus, { + message: "Invalid or missing status value.", + }) + itemStatus!: ItemStatus; +} diff --git a/src/dtos/StackbyEndpoint.dto.ts b/src/dtos/StackbyEndpoint.dto.ts new file mode 100644 index 0000000..80411ff --- /dev/null +++ b/src/dtos/StackbyEndpoint.dto.ts @@ -0,0 +1,20 @@ +import { IsEnum, IsOptional, IsString } from "class-validator"; +import { StackbyEndpoint } from "../types/types.js"; +import { STACKBY_FILTER_OPERATORS } from "../utils/stackby-filter.js"; +export class StackbyParamsDto { + @IsEnum(StackbyEndpoint, { + message: "Endpoint must be one of: Exercises, Topics, Themes", + }) + endpoint: StackbyEndpoint | undefined; + + @IsOptional() + @IsEnum(STACKBY_FILTER_OPERATORS) + operator?: STACKBY_FILTER_OPERATORS; + + @IsOptional() + @IsString() + column?: string; + + @IsOptional() + value?: string | number; +} diff --git a/src/dtos/UpdateExercise.dto.ts b/src/dtos/UpdateExercise.dto.ts new file mode 100644 index 0000000..fc1f01b --- /dev/null +++ b/src/dtos/UpdateExercise.dto.ts @@ -0,0 +1,27 @@ +import { IsBoolean, IsInt, IsOptional, IsString } from "class-validator"; + +export class UpdateExerciseDTO { + @IsOptional() + @IsString() + title?: string; + + @IsOptional() + @IsString() + shortDescription?: string; + + @IsOptional() + @IsString() + description?: string; + + @IsOptional() + @IsInt() + sequence?: number; + + @IsOptional() + @IsString() + topicId?: string; + + @IsOptional() + @IsBoolean() + isActive?: boolean; +} diff --git a/src/dtos/UpdateTheme.dto.ts b/src/dtos/UpdateTheme.dto.ts new file mode 100644 index 0000000..a374790 --- /dev/null +++ b/src/dtos/UpdateTheme.dto.ts @@ -0,0 +1,36 @@ +import { IsOptional, IsString, IsEnum, IsNumber, IsBoolean } from "class-validator"; +import { ThemeCategory } from "@prisma/client"; + +export class UpdateThemeDTO { + @IsOptional() + @IsString() + title?: string; + + @IsOptional() + @IsString() + description?: string; + + @IsOptional() + @IsString() + shortDescription?: string; + + @IsOptional() + @IsString() + image?: string; + + @IsOptional() + @IsString() + alt?: string; + + @IsOptional() + @IsEnum(ThemeCategory) + category?: ThemeCategory; + + @IsOptional() + @IsNumber() + sequence?: number; + + @IsOptional() + @IsBoolean() + isActive?: boolean; +} diff --git a/src/dtos/UpdateTopic.dto.ts b/src/dtos/UpdateTopic.dto.ts new file mode 100644 index 0000000..c234e8d --- /dev/null +++ b/src/dtos/UpdateTopic.dto.ts @@ -0,0 +1,28 @@ +import { IsBoolean, IsNotEmpty, IsOptional, IsString } from "class-validator"; + +export class UpdateTopicDTO { + @IsOptional() + @IsString() + @IsNotEmpty() + title?: string; + + @IsOptional() + @IsString() + description?: string; + + @IsOptional() + @IsString() + shortDescription?: string; + + @IsOptional() + @IsString() + references?: string; + + @IsOptional() + @IsBoolean() + isActive?: boolean; + + @IsString() + @IsOptional() + themeId?: string; +} diff --git a/src/errors/AppError.ts b/src/errors/AppError.ts new file mode 100644 index 0000000..b73b95a --- /dev/null +++ b/src/errors/AppError.ts @@ -0,0 +1,12 @@ +export class AppError extends Error { + public readonly statusCode: number; + public readonly details?: unknown; + + constructor(message: string, statusCode = 400, details?: unknown) { + super(message); + this.name = this.constructor.name; + this.statusCode = statusCode; + this.details = details; + Object.setPrototypeOf(this, new.target.prototype); + } +} diff --git a/src/errors/HttpErrors.ts b/src/errors/HttpErrors.ts new file mode 100644 index 0000000..bf3c024 --- /dev/null +++ b/src/errors/HttpErrors.ts @@ -0,0 +1,25 @@ +import { AppError } from "./AppError.js"; + +export class BadRequestError extends AppError { + constructor(message: string, details?: unknown) { + super(message, 400, details); + } +} + +export class NotFoundError extends AppError { + constructor(message: string, details?: unknown) { + super(message, 404, details); + } +} + +export class UnauthorizedError extends AppError { + constructor(message: string, details?: unknown) { + super(message, 401, details); + } +} + +export class ForbiddenError extends AppError { + constructor(message: string, details?: unknown) { + super(message, 403, details); + } +} diff --git a/src/errors/StackbyErrors.ts b/src/errors/StackbyErrors.ts new file mode 100644 index 0000000..aa04635 --- /dev/null +++ b/src/errors/StackbyErrors.ts @@ -0,0 +1,25 @@ +import { AppError } from "./AppError.js"; + +export class StackbyFilterError extends AppError { + constructor(message: string, details?: unknown) { + super(message, 400, details); + } +} + +export class UnsupportedOperatorError extends StackbyFilterError { + constructor(operator: string) { + super(`Unsupported operator: ${operator}`, { operator }); + } +} + +export class MissingValueError extends StackbyFilterError { + constructor(operator: string) { + super(`Missing value for operator: ${operator}`, { operator }); + } +} + +export class MissingColumnError extends StackbyFilterError { + constructor(operator: string) { + super(`Missing column for operator: ${operator}`, { operator }); + } +} diff --git a/src/index.ts b/src/index.ts index 6d193d2..8e5412d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,15 +1,32 @@ -import express from 'express' -import router from './routes/index' +import 'reflect-metadata'; +import express from 'express'; +import router from './routes/index.js'; +import { errorHandlerMiddleware } from './middleware/errorHandlerMiddleware.js'; +import cors from 'cors'; -const app = express() -const port = 5002 +const PORT = 5002; +const app = express(); -app.listen(port, () => { - console.log(`Server is running on port ${port}`) -}) +app.use( + cors({ + origin: 'http://localhost:3000', + credentials: true, + }), +); -app.use('/', router) +app.use(express.json()); +app.use(router); -app.use('/user', router) +app.use((req, res) => { + res.status(404).json({ + status: 404, + error: 'Not Found', + message: 'A rota que você tentou acessar não existe.', + }); +}); -app.use('/login', router) +app.use(errorHandlerMiddleware); + +app.listen(PORT, () => { + console.log(`Server is running on port http://localhost:${PORT}`); +}); diff --git a/src/lib/redis.ts b/src/lib/redis.ts new file mode 100644 index 0000000..45ac398 --- /dev/null +++ b/src/lib/redis.ts @@ -0,0 +1,4 @@ +import { Redis } from '@upstash/redis'; +import { IS_CACHE_ENABLED } from '../utils/constants.js'; + +export const redis = IS_CACHE_ENABLED ? Redis.fromEnv() : null; diff --git a/src/middleware/authorizeRoleMiddleware.ts b/src/middleware/authorizeRoleMiddleware.ts new file mode 100644 index 0000000..4e865cd --- /dev/null +++ b/src/middleware/authorizeRoleMiddleware.ts @@ -0,0 +1,19 @@ +import type { Request, Response, NextFunction } from 'express'; +import { STATUS_CODE } from '../utils/constants.js'; +import { Role } from '@prisma/client'; + +export const authorizeRoleMiddleware = ( + req: Request, + res: Response, + next: NextFunction, +) => { + const user = req.user; + + if (!user || user.role === Role.VIEWER) { + return res.status(STATUS_CODE.FORBIDDEN).json({ + message: 'You do not have permission to perform this action', + }); + } + + next(); +}; diff --git a/src/middleware/errorHandlerMiddleware.ts b/src/middleware/errorHandlerMiddleware.ts new file mode 100644 index 0000000..c8c9642 --- /dev/null +++ b/src/middleware/errorHandlerMiddleware.ts @@ -0,0 +1,31 @@ +import type { NextFunction, Request, Response } from 'express'; +import { AppError } from '../errors/AppError.js'; + +export function errorHandlerMiddleware( + // biome-ignore lint/suspicious/noExplicitAny: TODO: WIP + err: any, + _req: Request, + res: Response, + _next: NextFunction, +) { + if (err instanceof AppError) { + return res.status(err.statusCode).json({ + details: err.details, + error: err.message, + }); + } + + if (Array.isArray(err)) { + return res.status(400).json({ + details: err.map((e) => ({ + constraints: e.constraints, + property: e.property, + })), + error: 'Validation failed', + }); + } + + // biome-ignore lint/suspicious/noConsole: TODO: Melhorar observalidade do projeto através de logs mais robustos. + console.error(err); + return res.status(500).json({ error: 'Internal Server Error' }); +} diff --git a/src/middleware/validateTokenMiddleware.ts b/src/middleware/validateTokenMiddleware.ts new file mode 100644 index 0000000..916170f --- /dev/null +++ b/src/middleware/validateTokenMiddleware.ts @@ -0,0 +1,51 @@ +import type { NextFunction, Request, Response } from 'express'; +import prisma from '../../client.js'; +import { TokenService } from '../services/TokenService.js'; +import { STATUS_CODE } from '../utils/constants.js'; +import { Role } from '@prisma/client'; + +export async function validateTokenMiddleware( + req: Request, + res: Response, + next: NextFunction, +) { + const tokenService = new TokenService(); + const token = req.headers.authorization?.split(' ')[1]; + + if (!token) { + return res + .status(STATUS_CODE.UNAUTHORIZED) + .json({ message: 'Token was not provided' }); + } + + const extractToken = await tokenService.extractToken(token); + const email = extractToken?.email; + + try { + if (!email) { + return res + .status(STATUS_CODE.TOKEN_EXPIRED) + .json({ message: 'Token invalid' }); + } + + const user = await prisma.user.findUnique({ + where: { + email, + }, + }); + + if (!user) { + return res + .status(STATUS_CODE.NOT_FOUND) + .json({ message: 'User not found' }); + } + + // TODO: Propriedade role não deveria estar estatica no login, ao invés disso olhar na documentação do OAUTH como passar essa propriedade dependendo da conta. + req.user = { email, id: +user.id, role: Role.VIEWER }; + next(); + } catch (_error) { + return res + .status(STATUS_CODE.UNAUTHORIZED) + .json({ message: 'Authentication failed' }); + } +} diff --git a/src/routes/index.ts b/src/routes/index.ts index 18ff605..4fba6cb 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1,17 +1,123 @@ import express from 'express'; +import { validateTokenMiddleware } from '../middleware/validateTokenMiddleware.js'; +import { authorizeRoleMiddleware } from '../middleware/authorizeRoleMiddleware.js'; +import { LoginController } from '../controllers/login/LoginController.js'; +import { ProgressController } from '../controllers/progress/ProgressController.js'; +import { StackbyController } from '../controllers/stackby/StackbyController.js'; +import { Flagsmith } from 'flagsmith-nodejs'; +import { ThemeController } from '../controllers/theme/ThemeController.js'; +import { TopicController } from '../controllers/topic/TopicController.js'; +import { ExerciseController } from '../controllers/exercise/ExerciseController.js'; + +if (!process.env.FLAGSMITH_SERVER_KEY) { + throw new Error( + 'FATAL: A variável de ambiente FLAGSMITH_SERVER_KEY não está definida.', + ); +} + +new Flagsmith({ + // biome-ignore lint/style/noNonNullAssertion: TODO: Remover non null assertion + environmentKey: process.env.FLAGSMITH_SERVER_KEY!, +}); const router = express.Router(); -router.get('/', (req, res) => { - res.send('Welcome to the homepage'); +router.get('/', (_, res) => { + res.send('Welcome to the homepage'); +}); + +router.post('/login', (req, res) => + new LoginController().registerUser(req, res), +); + +router.post('/themes', async (req, res) => { + new ThemeController().createTheme(req, res); +}); + +router.patch('/themes/:id', (req, res) => { + new ThemeController().updateTheme(req, res); +}); + +router.get('/themes', (req, res) => { + new ThemeController().getThemes(req, res); +}); + +router.get('/themes/:id', (req, res) => { + new ThemeController().getThemeById(req, res); +}); + +router.post('/topics', async (req, res) => { + new TopicController().createTopic(req, res); +}); + +router.patch('/topics/:id', (req, res) => { + new TopicController().updateTopic(req, res); +}); + +router.get('/topics', (req, res) => { + new TopicController().getAllTopics(req, res); +}); + +router.get('/topics/:id', (req, res) => { + new TopicController().getTopicById(req, res); +}); + +router.delete('/topics/:id', (req, res) => { + new TopicController().deleteTopic(req, res); }); -router.get('/user', (req, res) => { - res.send('User page'); +router.get('/exercises', (req, res) => { + new ExerciseController().getAllExercises(req, res); }); -router.get('/login', (req, res) => { - res.send('Login page'); +router.get('/stackby/:endpoint', (req, res, next) => + new StackbyController().getStackbyData(req, res, next), +); + +router.use(validateTokenMiddleware); + +router.get('/status/:id/:idType', (req, res) => + new ProgressController().getTopicExercisesStatusProgress(req, res), +); + +router.put('/status/:topicId/item/:itemId', (req, res) => + new ProgressController().saveStatusProgress(req, res), +); + +router.get('/status/:topicId/item/:itemId', (req, res) => + new ProgressController().getExerciseStatusProgress(req, res), +); + +router.get('/progress/:id/:idType', (req, res) => + new ProgressController().getProgressPercentageById(req, res), +); + +router.use(authorizeRoleMiddleware); + +router.post('/themes', async (req, res) => { + new ThemeController().createTheme(req, res); +}); + +router.patch('/themes/:id', (req, res) => { + new ThemeController().updateTheme(req, res); +}); + +router.post('/exercises', (req, res) => { + new ExerciseController().createExercise(req, res); +}); + +router.patch('/exercises/:id', (req, res) => { + new ExerciseController().updateExercise(req, res); +}); + +router.delete('/exercises/:id', (req, res) => { + new ExerciseController().deleteExercise(req, res); +}); +/* +* to-do:wip +router.delete("/themes/:id", (req, res) => { + new ThemeController().deleteTheme(req, res); }); +*/ export default router; diff --git a/src/services/StackbyService.test.ts b/src/services/StackbyService.test.ts new file mode 100644 index 0000000..1317927 --- /dev/null +++ b/src/services/StackbyService.test.ts @@ -0,0 +1,198 @@ +process.env.STACKBY_BASE_URL = "http://fakeurl"; +process.env.STACKBY_SECRET_KEY = "fakekey"; + +import { StackbyService } from "../services/StackbyService.js"; +import { type StackbyDataResponse, StackbyEndpoint } from "../types/types.js"; + +describe("StackbyService", () => { + let service: StackbyService; + + beforeEach(() => { + service = new StackbyService(); + jest.clearAllMocks(); + }); + + describe("fetchStackbyData", () => { + beforeAll(() => { + global.fetch = jest.fn(); + jest.clearAllMocks(); + }); + + it("retorna dados em caso de sucesso", async () => { + const mockJson = jest.fn().mockResolvedValue({ data: "ok" }); + (fetch as jest.Mock).mockResolvedValue({ json: mockJson, ok: true }); + const result = await service.fetchStackbyData("endpoint", null); + expect(fetch).toHaveBeenCalledWith( + expect.stringContaining("http://fakeurl/endpoint"), + expect.objectContaining({ + headers: expect.objectContaining({ + "x-api-key": "fakekey", + }), + method: "GET", + }), + ); + expect(result).toEqual({ data: "ok" }); + }); + + it.skip("retorna erro se response.ok for false", async () => { + (fetch as jest.Mock).mockResolvedValue({ ok: false }); + const result = await service.fetchStackbyData("endpoint", null); + expect(result).toEqual({ + error: "Failed to fetch data from the API. Please try again later.", + }); + }); + + it.skip("retorna erro se lançar exceção", async () => { + (fetch as jest.Mock).mockRejectedValue(new Error("fail")); + const result = await service.fetchStackbyData("endpoint", null); + expect(result).toEqual({ + error: "Internal server error: Error: fail", + }); + }); + }); + + describe("calculateTotalItems", () => { + it("calcula corretamente para THEMES", () => { + const mockThemes: StackbyDataResponse = { + data: [ + { + field: { + alt: "", + cardDescription: "", + category: "", + checklistId: null, + completedItems: null, + createdAt: "", + description: "", + dueDateTimestamp: null, + favourite: 0, + image: null, + isConfigure: 0, + remainderId: null, + rowId: "1", + sequence: 1, + title: "", + topics: "", + topicsDescription: "", + topicsInfo: "topic1,topic2", + totalItems: null, + updatedAt: "", + }, + id: "theme1", + }, + ], + }; + const mockTopics: StackbyDataResponse = { + data: [ + { + field: { + cardDescription: "", + checklistId: null, + completedItems: null, + createdAt: "", + description: "", + dueDateTimestamp: null, + exercises: "", + exercisesDescription: "", + exercisesInfo: "ex1,ex2", + favourite: 0, + isConfigure: 0, + references: "", + remainderId: null, + rowId: "1", + sequence: 1, + theme: "", + title: "", + totalItems: null, + updatedAt: "", + video: "", + videoDescription: "", + videoInfo: "video1", + videoLink: "", + videoReference: "", + }, + id: "topic1", + }, + { + field: { + cardDescription: "", + checklistId: null, + completedItems: null, + createdAt: "", + description: "", + dueDateTimestamp: null, + exercises: "", + exercisesDescription: "", + exercisesInfo: "ex3,ex4", + favourite: 0, + isConfigure: 0, + references: "", + remainderId: null, + rowId: "2", + sequence: 2, + theme: "", + title: "", + totalItems: null, + updatedAt: "", + video: "", + videoDescription: "", + videoInfo: "video2", + videoLink: "", + videoReference: "", + }, + id: "topic2", + }, + ], + }; + const result = service.calculateTotalItems( + "theme1", + StackbyEndpoint.THEMES, + mockThemes, + mockTopics, + ); + expect(result).toBe(6); + }); + + it("calcula corretamente para TOPICS", () => { + const mockTopics: StackbyDataResponse = { + data: [ + { + field: { + cardDescription: "", + checklistId: null, + completedItems: null, + createdAt: "", + description: "", + dueDateTimestamp: null, + exercises: "", + exercisesDescription: "", + exercisesInfo: "ex1,ex2,ex3", + favourite: 0, + isConfigure: 0, + references: "", + remainderId: null, + rowId: "1", + sequence: 1, + theme: "", + title: "", + totalItems: null, + updatedAt: "", + video: "", + videoDescription: "", + videoInfo: "video1", + videoLink: "", + videoReference: "", + }, + id: "topic1", + }, + ], + }; + const result = service.calculateTotalItems( + "topic1", + StackbyEndpoint.TOPICS, + mockTopics, + ); + expect(result).toBe(4); + }); + }); +}); diff --git a/src/services/StackbyService.ts b/src/services/StackbyService.ts new file mode 100644 index 0000000..759b408 --- /dev/null +++ b/src/services/StackbyService.ts @@ -0,0 +1,88 @@ +import { type StackbyDataResponse, StackbyEndpoint } from "../types/types.js"; +import { cacheOrFetch } from "../utils/cache.js"; +import { + REDIS_STACKBY_KEYS, + STACKBY_BASE_URL, + STACKBY_SECRET_KEY, +} from "../utils/constants.js"; +import { PROGRESS_CALCULATION_BY_ENTITY } from "../utils/progressCalculationByEntity.js"; +import { + type StackbyFilter, + StackbyStandardFilter, +} from "../utils/stackby-filter.js"; + +export class StackbyService { + async fetchStackbyData( + endpoint: string, + filter?: StackbyFilter | null, + ): Promise { + + const apiKey: string = STACKBY_SECRET_KEY || ""; + let url: string = `${STACKBY_BASE_URL}/${endpoint}?latest=true`; + let filterKey = ""; + + if (filter) { + url += `&${filter.getStackbyFilterString()}`; + filterKey += + filter instanceof StackbyStandardFilter + ? `${filter.operator}-${filter.column}-${filter.value}` + : `${filter.value}`; + } + + const result = await cacheOrFetch( + REDIS_STACKBY_KEYS[endpoint as keyof typeof REDIS_STACKBY_KEYS]( + filterKey ? `${filterKey}` : undefined, + ), + async () => { + + const response = await fetch(url, { + headers: { + "Content-Type": "application/json", + "x-api-key": apiKey, + }, + method: "GET", + }); + + if (!response.ok) { + const text = await response.text(); + throw new Error(`Stackby API error: ${text}`); + } + + const data = await response.json(); + + const orderedData = data.data + .map((t: any) => ({ + ...t, + field: { + ...t.field, + sequence: Number(t.field.sequence), + }, + })) + .sort((a: any, b: any) => a.field.sequence - b.field.sequence); + + return !filter || filter instanceof StackbyStandardFilter + ? { data: orderedData } + : { data: [orderedData[0]] }; + }, + ); + + return result as StackbyDataResponse; + } + + calculateTotalItems( + id: string, + endpoint: StackbyEndpoint, + items: StackbyDataResponse, + topics?: StackbyDataResponse, + ) { + if (endpoint === StackbyEndpoint.THEMES) { + return PROGRESS_CALCULATION_BY_ENTITY[endpoint]( + id, + items, + topics as StackbyDataResponse, + ); + } + + return PROGRESS_CALCULATION_BY_ENTITY[endpoint](id, items); + } +} \ No newline at end of file diff --git a/src/services/TokenService.ts b/src/services/TokenService.ts new file mode 100644 index 0000000..995bd30 --- /dev/null +++ b/src/services/TokenService.ts @@ -0,0 +1,95 @@ +import * as crypto from "node:crypto"; +import * as dotenv from "dotenv"; +import * as jose from "jose"; +import prisma from "../../client.js"; +import type { UserToken } from "../types/types.js"; + +dotenv.config(); + +export class TokenService { + private secretKey = process.env.NEXTAUTH_SECRET || ""; + + async extractToken(token: string): Promise { + if (!this.secretKey) { + throw new Error("Secret key not found"); + } + try { + const salt = Buffer.alloc(16); + + const key = await new Promise((resolve, reject) => { + crypto.hkdf( + "sha256", + Buffer.from(this.secretKey, "utf-8"), + salt, + Buffer.from("NextAuth.js Generated Encryption Key", "utf-8"), + 32, + (err, derivedKey) => { + if (err) reject(err); + else resolve(Buffer.from(derivedKey)); + }, + ); + }); + + const keyUint8Array = new Uint8Array(key); + + const { plaintext } = await jose.compactDecrypt(token, keyUint8Array); + const decodedToken = JSON.parse(new TextDecoder().decode(plaintext)); + + if (!decodedToken) { + console.error("Invalid token"); + return null; + } + + return decodedToken; + } catch (error) { + console.error("Error decrypting token:", error); + return null; + } + } + + async convertIatToDateTime(extractToken: UserToken) { + const brasiliaTimeZone = 10800; + const iat = extractToken.iat - brasiliaTimeZone; + + const convertDate = (iat: number): Date => { + return new Date(iat * 1000); + }; + + const dateTime = convertDate(iat); + + return dateTime; + } + + async registerUser(extractToken: UserToken) { + try { + const dateTime = await this.convertIatToDateTime(extractToken); + + const createUser = await prisma.user.create({ + data: { + email: extractToken.email, + loginDate: dateTime, + provider: extractToken.provider, + }, + }); + + return createUser; + } catch (error) { + console.error(error); + return null; + } + } + + async findUserByEmail(extractToken: UserToken) { + try { + const loginDate = await this.convertIatToDateTime(extractToken); + + const updateUser = await prisma.user.update({ + data: { loginDate, provider: extractToken.provider }, + where: { email: extractToken.email }, + }); + return updateUser; + } catch { + return null; + } + } +} diff --git a/src/services/UserService.ts b/src/services/UserService.ts new file mode 100644 index 0000000..54378ff --- /dev/null +++ b/src/services/UserService.ts @@ -0,0 +1,13 @@ +import prisma from "../../client.js"; + +export class UserService { + async findUserByEmail(email: string) { + try { + const user = await prisma.user.findUnique({ where: { email } }); + if (!user) throw new Error("User not found."); + return user; + } catch (error) { + throw new Error("Error fetching user from database"); + } + } +} diff --git a/src/services/exercise/ExerciseService.ts b/src/services/exercise/ExerciseService.ts new file mode 100644 index 0000000..32777f4 --- /dev/null +++ b/src/services/exercise/ExerciseService.ts @@ -0,0 +1,82 @@ +import prisma from '../../../client.js'; +import { CreateExerciseDTO } from '../../dtos/CreateExercise.dto.js'; +import { UpdateExerciseDTO } from '../../dtos/UpdateExercise.dto.js'; +import { createPaginationMeta, pagination } from '../../utils/pagination.js'; + +export class ExerciseService { + async getAllExercises(page: number = 1, limit: number = 10) { + const { skip, take } = pagination(page, limit); + + const total = await prisma.exercise.count(); + const exercises = await prisma.exercise.findMany({ + include: { + topic: true, + }, + orderBy: { + sequence: 'asc', + }, + skip, + take, + }); + return { + data: exercises, + meta: createPaginationMeta(total, page, take), + }; + } + + async createExercise(dto: CreateExerciseDTO) { + const exercise = await prisma.exercise.create({ + data: { + title: dto.title, + shortDescription: dto.shortDescription, + description: dto.description, + sequence: dto.sequence || 0, + topicId: dto.topicId || null, + isActive: true, + }, + include: { topic: true }, + }); + + return exercise; + } + + async updateExercise(id: string, dto: UpdateExerciseDTO) { + const existing = await prisma.exercise.findUnique({ where: { id } }); + if (!existing) { + throw new Error('Exercise not found'); + } + + const updated = await prisma.exercise.update({ + where: { id }, + data: { + ...dto, + }, + include: { topic: true }, + }); + + return updated; + } + + async deleteExercise(id: string) { + const deleted = await prisma.exercise.delete({ where: { id } }); + return deleted; + } + + async getExerciseById(id: string) { + return await prisma.exercise.findUnique({ + include: { + topic: true, + }, + where: { id }, + }); + } + + async getExercisesByTopicId(topicId: string) { + return await prisma.exercise.findMany({ + orderBy: { + sequence: 'asc', + }, + where: { topicId }, + }); + } +} diff --git a/src/services/progress/ProgressService.test.ts b/src/services/progress/ProgressService.test.ts new file mode 100644 index 0000000..2228da0 --- /dev/null +++ b/src/services/progress/ProgressService.test.ts @@ -0,0 +1,355 @@ +import { ElementType, ItemStatus } from "@prisma/client"; +import { prismaMock } from "../../../singleton.js"; +import { IdType } from "../../types/types.js"; +import { ProgressService } from "./ProgressService.js"; + +let progressService: ProgressService; +beforeEach(() => { + jest.clearAllMocks(); + progressService = new ProgressService(); +}); + +describe("ProgressService", () => { + describe("calculateProgressPercentage", () => { + it("retorna 0 quando totalUserItens ou totalItens for 0", () => { + expect(progressService.calculateProgressPercentage(0, 0)).toEqual({ + progress: 0, + }); + expect(progressService.calculateProgressPercentage(5, 0)).toEqual({ + progress: 0, + }); + expect(progressService.calculateProgressPercentage(0, 10)).toEqual({ + progress: 0, + }); + }); + + it("calcula corretamente e arredonda para baixo", () => { + expect(progressService.calculateProgressPercentage(6, 12)).toEqual({ + progress: 50, + }); + expect(progressService.calculateProgressPercentage(1, 3)).toEqual({ + progress: 33, + }); + expect(progressService.calculateProgressPercentage(2, 5)).toEqual({ + progress: 40, + }); + }); + + it("lida com totalUserItens > totalItens", () => { + expect(progressService.calculateProgressPercentage(10, 2)).toEqual({ + progress: 500, + }); + }); + }); + + describe("getProgressPercentageById", () => { + it("retorna progresso 0 se totalItens for 0", async () => { + const result = await progressService.getProgressPercentageById( + { id: "1", idType: IdType.TOPIC_ID, userId: 1 }, + 0, + ); + expect(result).toEqual({ progress: 0 }); + }); + + it("calcula corretamente o progresso quando há itens completados", async () => { + prismaMock.progress.count.mockResolvedValue(2); + const result = await progressService.getProgressPercentageById( + { id: "1", idType: IdType.TOPIC_ID, userId: 1 }, + 10, + ); + expect(result).toEqual({ progress: 20 }); + }); + + it("lança erro se o count falhar", async () => { + prismaMock.progress.count.mockRejectedValue(new Error("DB fail")); + await expect( + progressService.getProgressPercentageById( + { id: "1", idType: IdType.TOPIC_ID, userId: 1 }, + 5, + ), + ).rejects.toThrow("Error fetching user progress from database"); + }); + + it("retorna {progress: 0, topics: []} se theme não encontrado", async () => { + const themes = { data: [] }; + const topics = { data: [] }; + const result = await progressService.getProgressPercentageById( + { id: "notfound", idType: IdType.THEME_ID, userId: 1 }, + 10, + themes, + topics, + ); + expect(result).toEqual({ progress: 0, topics: [] }); + }); + + it("retorna progresso 0 se topicsInfo está vazio", async () => { + const themes = { + data: [ + { + field: { + alt: "", + cardDescription: "", + category: "", + checklistId: null, + completedItems: null, + createdAt: "", + description: "", + dueDateTimestamp: null, + favourite: 0, + image: null, + isConfigure: 0, + remainderId: null, + rowId: "", + sequence: 0, + title: "", + topics: "", + topicsDescription: "", + topicsInfo: "", + totalItems: null, + updatedAt: "", + }, + id: "theme1", + }, + ], + }; + const topics = { data: [] }; + const result = await progressService.getProgressPercentageById( + { id: "theme1", idType: IdType.THEME_ID, userId: 1 }, + 10, + themes, + topics, + ); + expect(result).toEqual({ progress: 0, topics: [] }); + }); + + it("calcula progresso de theme com tópicos e exercícios", async () => { + const themes = { + data: [ + { + field: { + alt: "", + cardDescription: "", + category: "", + checklistId: null, + completedItems: null, + createdAt: "", + description: "", + dueDateTimestamp: null, + favourite: 0, + image: null, + isConfigure: 0, + remainderId: null, + rowId: "", + sequence: 0, + title: "", + topics: "", + topicsDescription: "", + topicsInfo: "topic1,topic2", + totalItems: null, + updatedAt: "", + }, + id: "theme1", + }, + ], + }; + const topics = { + data: [ + { + field: { + cardDescription: "", + checklistId: null, + completedItems: null, + createdAt: "", + description: "", + dueDateTimestamp: null, + exercises: "", + exercisesDescription: "", + exercisesInfo: "ex1,ex2", + favourite: 0, + isConfigure: 0, + references: "", + remainderId: null, + rowId: "", + sequence: 0, + theme: "", + title: "", + totalItems: null, + updatedAt: "", + video: "", + videoDescription: "", + videoInfo: "video1", + videoLink: "", + videoReference: "", + }, + id: "topic1", + }, + { + field: { + cardDescription: "", + checklistId: null, + completedItems: null, + createdAt: "", + description: "", + dueDateTimestamp: null, + exercises: "", + exercisesDescription: "", + exercisesInfo: "", + favourite: 0, + isConfigure: 0, + references: "", + remainderId: null, + rowId: "", + sequence: 0, + theme: "", + title: "", + totalItems: null, + updatedAt: "", + video: "", + videoDescription: "", + videoInfo: "", + videoLink: "", + videoReference: "", + }, + id: "topic2", + }, + ], + }; + prismaMock.progress.count.mockResolvedValue(1); + const result = await progressService.getProgressPercentageById( + { id: "theme1", idType: IdType.THEME_ID, userId: 1 }, + 3, + themes, + topics, + ); + expect(result.progress).toBeGreaterThanOrEqual(0); + if ("topics" in result) { + expect(Array.isArray(result.topics)).toBe(true); + } + }); + }); + + describe("getSingleStatusProgressByItemId", () => { + it("retorna o progresso correto para o itemId e userId", async () => { + const mockProgress = { + elementType: ElementType.Exercise, + itemId: "item1", + itemStatus: ItemStatus.Completed, + modifiedAt: new Date(), + themeId: "theme1", + topicId: "topic1", + userId: 1, + }; + prismaMock.progress.findFirst.mockResolvedValue(mockProgress); + const result = await progressService.getSingleStatusProgressByItemId( + "item1", + 1, + ); + expect(result).toEqual(mockProgress); + }); + + it("lança erro quando findFirst falhar", async () => { + prismaMock.progress.findFirst.mockRejectedValue(new Error("DB error")); + await expect( + progressService.getSingleStatusProgressByItemId("item1", 1), + ).rejects.toThrow("Error fetching user progress from database"); + }); + }); + + describe("getAllStatusProgressById", () => { + it("retorna todos os status para o id e userId", async () => { + const mockList = [ + { + elementType: ElementType.Exercise, + itemId: "item1", + itemStatus: ItemStatus.Completed, + modifiedAt: new Date(), + themeId: "theme1", + topicId: "topic1", + userId: 1, + }, + { + elementType: ElementType.Video, + itemId: "item2", + itemStatus: ItemStatus.InProgress, + modifiedAt: new Date(), + themeId: "theme2", + topicId: "topic2", + userId: 1, + }, + ]; + prismaMock.progress.findMany.mockResolvedValue(mockList); + const result = await progressService.getAllStatusProgressById({ + id: "item1", + idType: IdType.TOPIC_ID, + userId: 1, + }); + expect(result).toEqual(mockList); + }); + + it("lança erro quando findMany falhar", async () => { + prismaMock.progress.findMany.mockRejectedValue(new Error("DB error")); + await expect( + progressService.getAllStatusProgressById({ + id: "item1", + idType: IdType.TOPIC_ID, + userId: 1, + }), + ).rejects.toThrow("Error fetching user progress from database"); + }); + }); + + describe("saveStatusProgress", () => { + it("chama prisma.progress.upsert com os dados corretos e retorna o progresso criado", async () => { + const mockProgress = { + elementType: ElementType.Video, + itemId: "item123", + itemStatus: ItemStatus.Completed, + modifiedAt: new Date(), + themeId: "theme123", + topicId: "topic123", + userId: 1, + }; + prismaMock.progress.upsert.mockResolvedValue(mockProgress); + const result = await progressService.saveStatusProgress({ + elementType: mockProgress.elementType, + itemId: mockProgress.itemId, + itemStatus: mockProgress.itemStatus, + themeId: mockProgress.themeId, + topicId: mockProgress.topicId, + userId: mockProgress.userId, + }); + expect(prismaMock.progress.upsert).toHaveBeenCalledWith({ + create: { + elementType: mockProgress.elementType, + itemId: mockProgress.itemId, + itemStatus: mockProgress.itemStatus, + themeId: mockProgress.themeId, + topicId: mockProgress.topicId, + userId: mockProgress.userId, + }, + update: { itemStatus: mockProgress.itemStatus }, + where: { + itemId_userId: { + itemId: mockProgress.itemId, + userId: mockProgress.userId, + }, + }, + }); + expect(result).toEqual(mockProgress); + }); + + it("lança erro quando o upsert falha", async () => { + prismaMock.progress.upsert.mockRejectedValue(new Error("DB error")); + await expect( + progressService.saveStatusProgress({ + elementType: ElementType.Video, + itemId: "item123", + itemStatus: ItemStatus.Completed, + themeId: "theme123", + topicId: "topic123", + userId: 1, + }), + ).rejects.toThrow("Error saving progress status"); + }); + }); +}); diff --git a/src/services/progress/ProgressService.ts b/src/services/progress/ProgressService.ts new file mode 100644 index 0000000..101e447 --- /dev/null +++ b/src/services/progress/ProgressService.ts @@ -0,0 +1,206 @@ +import { ItemStatus } from "@prisma/client"; +import prisma from "../../../client.js"; +import { + type DataItem, + type GetProgress, + IdType, + type SaveStatusProgress, + type StackbyDataResponse, + type ThemeField, + type TopicField, +} from "../../types/types.js"; + +export class ProgressService { + calculateProgressPercentage( + totalUserItens: number, + totalItens: number, + ): { progress: number } { + return { + progress: + totalUserItens && totalItens + ? Math.floor((totalUserItens / totalItens) * 100) + : 0, + }; + } + + private filterTheme( + themes: StackbyDataResponse, + themeId: string, + ): DataItem | undefined { + return themes.data.find((theme) => theme.id === themeId); + } + + private filterTopics( + topics: StackbyDataResponse, + topicIds: string[], + ): DataItem[] { + return topics.data.filter((topic) => topicIds.includes(topic.id)); + } + + private getTopicTotalItems(topicField: TopicField): number { + let exerciseCount = 0; + if (topicField.exercisesInfo && topicField.exercisesInfo !== "Untitle") { + exerciseCount = topicField.exercisesInfo + .split(",") + .filter(Boolean).length; + } + const videoCount = topicField.videoInfo ? 1 : 0; + return exerciseCount + videoCount; + } + + private async getTopicCompletedCount( + userId: number, + topicId: string, + ): Promise { + return await prisma.progress.count({ + where: { + itemStatus: ItemStatus.Completed, + topicId, + userId, + }, + }); + } + + private async calculateTopicProgress( + userId: number, + topic: DataItem, + ): Promise<{ + topicId: string; + progress: number; + completed: number; + total: number; + }> { + const topicField = topic.field as TopicField; + const total = this.getTopicTotalItems(topicField); + const completed = await this.getTopicCompletedCount(userId, topic.id); + const progress = total ? Math.floor((completed / total) * 100) : 0; + return { completed, progress, topicId: topic.id, total }; + } + + private async calculateAllTopicsProgress( + userId: number, + topics: DataItem[], + ): Promise<{ + topicsProgress: { topicId: string; progress: number }[]; + totalCompleted: number; + }> { + const topicsProgress: { topicId: string; progress: number }[] = []; + let totalCompleted = 0; + for (const topic of topics) { + const { topicId, progress, completed } = + await this.calculateTopicProgress(userId, topic); + topicsProgress.push({ progress, topicId }); + totalCompleted += completed; + } + return { topicsProgress, totalCompleted }; + } + + private async calculateThemeProgress( + userId: number, + topics: DataItem[], + totalItems: number, + ) { + const { topicsProgress, totalCompleted } = + await this.calculateAllTopicsProgress(userId, topics); + const progress = totalItems + ? Math.floor((totalCompleted / totalItems) * 100) + : 0; + return { progress, topics: topicsProgress }; + } + + async getProgressPercentageById( + { userId, id, idType }: GetProgress, + totalItems: number, + themes?: StackbyDataResponse, + topics?: StackbyDataResponse, + ) { + try { + if (idType === IdType.THEME_ID && themes && topics) { + const theme = this.filterTheme(themes, id); + if (!theme) return { progress: 0, topics: [] }; + + const field = theme.field as ThemeField; + const topicIds = field.topicsInfo + ? field.topicsInfo.split(",").filter(Boolean) + : []; + const filteredTopics = this.filterTopics(topics, topicIds); + + return await this.calculateThemeProgress( + userId, + filteredTopics, + totalItems, + ); + } else { + const completedCount = await prisma.progress.count({ + where: { + userId, + [idType]: id, + itemStatus: ItemStatus.Completed, + }, + }); + return this.calculateProgressPercentage(completedCount, totalItems); + } + } catch (_error) { + throw new Error("Error fetching user progress from database"); + } + } + + async getSingleStatusProgressByItemId(itemId: string, userId: number) { + try { + return await prisma.progress.findFirst({ + where: { + itemId, + userId, + }, + }); + } catch (_error) { + throw new Error("Error fetching user progress from database"); + } + } + + async getAllStatusProgressById({ id, idType, userId }: GetProgress) { + try { + return await prisma.progress.findMany({ + where: { + userId, + [idType]: id, + }, + }); + } catch (_error) { + throw new Error("Error fetching user progress from database"); + } + } + + async saveStatusProgress({ + elementType, + itemId, + itemStatus, + themeId, + topicId, + userId, + }: SaveStatusProgress) { + try { + const createdProgress = await prisma.progress.upsert({ + create: { + elementType, + itemId, + itemStatus, + themeId, + topicId, + userId, + }, + update: { itemStatus }, + where: { + itemId_userId: { + itemId, + userId, + }, + }, + }); + + return createdProgress; + } catch (_error) { + throw new Error("Error saving progress status"); + } + } +} diff --git a/src/services/theme/ThemeService.ts b/src/services/theme/ThemeService.ts new file mode 100644 index 0000000..8b153c5 --- /dev/null +++ b/src/services/theme/ThemeService.ts @@ -0,0 +1,79 @@ +import { ThemeCategory } from '@prisma/client'; +import prisma from '../../../client.js'; +import { CreateThemeDTO } from '../../dtos/CreateTheme.dto.js'; +import { UpdateThemeDTO } from '../../dtos/UpdateTheme.dto.js'; +import { createPaginationMeta, pagination } from '../../utils/pagination.js'; +export class ThemeService { + async getThemes( + category?: ThemeCategory, + page: number = 1, + limit: number = 10, + ) { + const where = category ? { category } : {}; + const { skip, take } = pagination(page, limit); + + const total = await prisma.theme.count({ where: {} }); + const themes = await prisma.theme.findMany({ + where, + orderBy: { sequence: 'asc' }, + skip, + take, + }); + +themes.forEach(t => console.log(t.title, t.sequence)); + return { + data: themes, + meta: createPaginationMeta(total, page, take), + }; + } + + async getThemeById(id: string) { + return await prisma.theme.findUnique({ + include: { topic: true }, + where: { id }, + }); + } + + async createTheme(dto: CreateThemeDTO) { + const theme = await prisma.theme.create({ + data: { + title: dto.title, + description: dto.description, + shortDescription: dto.shortDescription, + image: dto.image, + alt: dto.alt, + category: dto.category, + sequence: dto.sequence, + isActive: true, + }, + }); + return theme; + } + + async updateTheme(id: string, dto: UpdateThemeDTO) { + const existingTheme = await prisma.theme.findUnique({ + where: { id }, + }); + + if (!existingTheme) { + throw new Error('Theme not found'); + } + + const theme = await prisma.theme.update({ + where: { id }, + data: { + ...dto, + }, + }); + + return theme; + } + + async deleteTheme(id: string) { + const theme = await prisma.theme.update({ + where: { id }, + data: { isActive: false }, + }); + return theme; + } +} diff --git a/src/services/topic/TopicService.ts b/src/services/topic/TopicService.ts new file mode 100644 index 0000000..768e90d --- /dev/null +++ b/src/services/topic/TopicService.ts @@ -0,0 +1,97 @@ +import prisma from '../../../client.js'; +import { CreateTopicDTO } from '../../dtos/CreateTopic.dto.js'; +import { UpdateTopicDTO } from '../../dtos/UpdateTopic.dto.js'; +import { createPaginationMeta, pagination } from '../../utils/pagination.js'; + +export class TopicService { + async createTopic(dto: CreateTopicDTO) { + const topic = await prisma.topic.create({ + data: { + title: dto.title, + description: dto.description, + shortDescription: dto.shortDescription, + references: dto.references, + themeId: dto.themeId, + isActive: true, + }, + }); + return topic; + } + + async getAllTopics(page: number = 1, limit: number = 10) { + const { skip, take } = pagination(page, limit); + + const total = await prisma.topic.count(); + const topics = await prisma.topic.findMany({ + include: { + exercises: true, + theme: true, + video: true, + }, + skip, + take, + }); + + return { + data: topics, + meta: createPaginationMeta(total, page, take), + }; + } + + async getTopicById(id: string) { + return await prisma.topic.findUnique({ + include: { + exercises: true, + theme: true, + video: true, + }, + where: { id }, + }); + } + + async getTopicsByThemeId(themeId: string) { + return await prisma.topic.findMany({ + include: { + exercises: true, + video: true, + }, + where: { themeId }, + }); + } + + async updateTopic(id: string, dto: UpdateTopicDTO) { + const existingTopic = await prisma.topic.findUnique({ + where: { id }, + }); + + if (!existingTopic) { + throw new Error('Topic not found'); + } + + const topic = await prisma.topic.update({ + where: { id }, + data: { + ...dto, + }, + }); + + return topic; + } + + async deleteTopic(id: string) { + const existingTopic = await prisma.topic.findUnique({ + where: { id }, + }); + + if (!existingTopic) { + throw new Error('Topic not found'); + } + if (existingTopic.isActive) { + throw new Error("Can't delete active topic"); + } + + await prisma.topic.delete({ + where: { id }, + }); + } +} diff --git a/src/types/express/express.d.ts b/src/types/express/express.d.ts new file mode 100644 index 0000000..f701449 --- /dev/null +++ b/src/types/express/express.d.ts @@ -0,0 +1,13 @@ +import { Role } from '@prisma/client'; +import express from 'express'; +declare global { + namespace Express { + interface Request { + user?: { + email: string; + id: number; + role: Role; + }; + } + } +} diff --git a/src/types/types.ts b/src/types/types.ts new file mode 100644 index 0000000..7bb1d7d --- /dev/null +++ b/src/types/types.ts @@ -0,0 +1,110 @@ +import type { ElementType, ItemStatus } from "@prisma/client"; + +export interface UserToken { + name: string; + email: string; + sub: string; + id: string; + provider: string; + accessToken: string; + iat: number; + exp: number; + jti: string; +} + +export interface SaveStatusProgress { + itemId: string; + elementType: ElementType; + userId: number; + itemStatus: ItemStatus; + topicId: string; + themeId: string; +} + +export enum StackbyEndpoint { + EXERCISES = "Exercises", + TOPICS = "Topics", + THEMES = "Themes", +} + +export enum ThemeType { + LEVELING = "nivelamento", + SELFSTUDY = "autoestudo", +} + +export enum IdType { + TOPIC_ID = "topicId", + THEME_ID = "themeId", +} + +export interface GetProgress { + userId: number; + id: string; + idType: IdType; +} +export interface SingleProgressResponse extends SaveStatusProgress { + modifiedAt: Date; +} + +export interface StackbyDataResponse { + data: DataItem[]; +} +export interface DataItem { + id: string; + field: CommonField | ThemeField | TopicField | VideoField | ExercisesField; +} +export interface CommonField { + rowId: string; + sequence: number; + isConfigure: number; + favourite: number; + totalItems: number | null; + completedItems: number | null; + dueDateTimestamp: number | null; + checklistId: string | null; + remainderId: string | null; + updatedAt: string; + createdAt: string; + title: string; + description: string; + category?: string; +} + +export interface ThemeField extends CommonField { + topicsInfo: string; + cardDescription: string; + image: Image[] | null; + topics: string; + category: string; + topicsDescription: string; + alt: string; +} + +export interface TopicField extends CommonField { + cardDescription: string; + video: string; + references: string; + theme: string; + exercises: string; + exercisesDescription: string; + exercisesInfo: string; + videoDescription: string; + videoLink: string; + videoReference: string; + videoInfo: string; +} + +export interface VideoField extends CommonField { + link: string; + topics: string; +} + +export interface ExercisesField extends CommonField { + image: Image[] | null; + topics: string; +} +export interface Image { + filename: string; + type: string; + url: string; +} diff --git a/src/utils/cache.ts b/src/utils/cache.ts new file mode 100644 index 0000000..425b844 --- /dev/null +++ b/src/utils/cache.ts @@ -0,0 +1,26 @@ +import { redis } from "../lib/redis.js"; +import { CACHE_TTL, IS_CACHE_ENABLED } from "../utils/constants.js"; + +export async function cacheOrFetch( + key: string, + fetchFunction: () => Promise, +) { + try { + if (!IS_CACHE_ENABLED) { + return await fetchFunction(); + } + + const cached: string | null = await redis!.get(key); + + if (cached) { + return cached; + } + + const data = await fetchFunction(); + await redis!.set(key, JSON.stringify(data), { ex: CACHE_TTL }); + return data; + } catch (error) { + console.error(`Error fetching data for key ${key}:`, error); + throw error; + } +} diff --git a/src/utils/constants.ts b/src/utils/constants.ts new file mode 100644 index 0000000..1dc15d1 --- /dev/null +++ b/src/utils/constants.ts @@ -0,0 +1,48 @@ +import { IdType, StackbyEndpoint } from "../types/types.js"; + +export enum STATUS_CODE { + OK = 200, + CREATED = 201, + NO_CONTENT = 204, + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + FORBIDDEN = 403, + NOT_FOUND = 404, + TOKEN_EXPIRED = 498, + INTERNAL_SERVER_ERROR = 500, +} + +export const STACKBY_ENDPOINTS_HASHTABLE: Partial< + Record +> = { + [IdType.TOPIC_ID]: StackbyEndpoint.TOPICS, + [IdType.THEME_ID]: StackbyEndpoint.THEMES, +}; + +export const STACKBY_SECRET_KEY = process.env.STACKBY_SECRET_KEY; +export const STACKBY_BASE_URL = process.env.STACKBY_BASE_URL; + +export const IS_CACHE_ENABLED = process.env.CACHE_ENABLED === "TRUE"; +export const DEFAULT_CACHE_TTL = 60 * 60 * 8; +export const CACHE_TTL = process.env.CACHE_TTL + ? parseInt(process.env.CACHE_TTL, 10) + : DEFAULT_CACHE_TTL; + +export const makeRedisKey = ( + prefix: string, + key: string, + filterKey?: string, +): string => `${prefix}:${key}${filterKey ? `:${filterKey}` : ""}`; + +export const REDIS_STACKBY_KEYS = { + Exercises: (filterKey?: string) => + makeRedisKey("stackby", StackbyEndpoint.EXERCISES, filterKey), + Themes: (filterKey?: string) => + makeRedisKey("stackby", StackbyEndpoint.THEMES, filterKey), + Topics: (filterKey?: string) => + makeRedisKey("stackby", StackbyEndpoint.TOPICS, filterKey), +}; +export const REDIS_PROGRESS_CALCULATION_BY_ENTITY_KEYS = { + Themes: makeRedisKey("progressCalculation", StackbyEndpoint.THEMES), + Topics: makeRedisKey("progressCalculation", StackbyEndpoint.TOPICS), +}; diff --git a/src/utils/filter-factory.ts b/src/utils/filter-factory.ts new file mode 100644 index 0000000..8b50a99 --- /dev/null +++ b/src/utils/filter-factory.ts @@ -0,0 +1,29 @@ +import type { StackbyParamsDto } from "../dtos/StackbyEndpoint.dto.js"; +import { + MissingColumnError, + MissingValueError, +} from "../errors/StackbyErrors.js"; +import { + STACKBY_FILTER_OPERATORS, + StackbyFilterById, + StackbyStandardFilter, +} from "../utils/stackby-filter.js"; + +export function buildStackbyFilter(dto: StackbyParamsDto) { + if (!dto.operator) { + return null; + } + + if (dto.operator === STACKBY_FILTER_OPERATORS.BY_ID) { + if (!dto.value) { + throw new MissingValueError(dto.operator); + } + return new StackbyFilterById(dto.value as string); + } + + if (!dto.column) { + throw new MissingColumnError(dto.operator); + } + + return new StackbyStandardFilter(dto.operator, dto.column, dto.value); +} diff --git a/src/utils/formatDateTime.ts b/src/utils/formatDateTime.ts new file mode 100644 index 0000000..e14e578 --- /dev/null +++ b/src/utils/formatDateTime.ts @@ -0,0 +1,4 @@ +export function formatDateTime(): Date { + const offset = -3 * 60 * 60 * 1000; + return new Date(Date.now() + offset); +} diff --git a/src/utils/pagination.ts b/src/utils/pagination.ts new file mode 100644 index 0000000..724d1e4 --- /dev/null +++ b/src/utils/pagination.ts @@ -0,0 +1,28 @@ +import { Request } from "express"; + +export function pagination(page: number, limit: number) { + const allowedLimits = [10, 25, 50]; + const finalLimit = allowedLimits.includes(limit) ? limit : 10; + + const skip = (page - 1) * finalLimit; + + return {skip, take: finalLimit} +} + +export function createPaginationMeta(total: number, page: number, limit: number) { + return { + total, + page, + limit, + totalPages: Math.ceil(total / limit) + }; +} + +export function getPaginationParams (req: Request) { + const page = parseInt(req.query.page as string) || 1; + const limit = parseInt(req.query.limit as string) || 10; +return { page, limit }; +} + + + diff --git a/src/utils/progressCalculationByEntity.test.ts b/src/utils/progressCalculationByEntity.test.ts new file mode 100644 index 0000000..e066018 --- /dev/null +++ b/src/utils/progressCalculationByEntity.test.ts @@ -0,0 +1,160 @@ +import { + type StackbyDataResponse, + StackbyEndpoint, + type ThemeField, + type TopicField, +} from "../types/types.js"; +import { + countThemeItems, + countTopicItems, + PROGRESS_CALCULATION_BY_ENTITY, +} from "./progressCalculationByEntity.js"; + +describe("progressCalculationByEntity util", () => { + function makeTopicField(overrides: Partial = {}): TopicField { + return { + cardDescription: "", + checklistId: null, + completedItems: null, + createdAt: "", + description: "", + dueDateTimestamp: null, + exercises: "", + exercisesDescription: "", + exercisesInfo: "", + favourite: 0, + isConfigure: 0, + references: "", + remainderId: null, + rowId: "1", + sequence: 1, + theme: "", + title: "", + totalItems: null, + updatedAt: "", + video: "", + videoDescription: "", + videoInfo: "", + videoLink: "", + videoReference: "", + ...overrides, + }; + } + + function makeThemeField(overrides: Partial = {}): ThemeField { + return { + alt: "", + cardDescription: "", + category: "", + checklistId: null, + completedItems: null, + createdAt: "", + description: "", + dueDateTimestamp: null, + favourite: 0, + image: null, + isConfigure: 0, + remainderId: null, + rowId: "1", + sequence: 1, + title: "", + topics: "", + topicsDescription: "", + topicsInfo: "", + totalItems: null, + updatedAt: "", + ...overrides, + }; + } + + const mockTopics: StackbyDataResponse = { + data: [ + { + field: makeTopicField({ + exercisesInfo: "ex1,ex2,ex3", + videoInfo: "video1", + }), + id: "topic1", + }, + { + field: makeTopicField({ exercisesInfo: "", videoInfo: "" }), + id: "topic2", + }, + { + field: makeTopicField({ exercisesInfo: "Untitle", videoInfo: "" }), + id: "topic3", + }, + ], + }; + + const mockThemes: StackbyDataResponse = { + data: [ + { + field: makeThemeField({ topicsInfo: "topic1,topic2" }), + id: "theme1", + }, + { + field: makeThemeField({ topicsInfo: "" }), + id: "theme2", + }, + { + field: makeThemeField({}), + id: "theme3", + }, + ], + }; + + it("countTopicItems retorna 0 se o tópico não existe", () => { + expect(countTopicItems("notfound", mockTopics)).toBe(0); + }); + + it("countTopicItems retorna 0 se não há exercícios nem vídeo", () => { + expect(countTopicItems("topic2", mockTopics)).toBe(0); + }); + + it("countTopicItems retorna apenas exercícios se não há vídeo", () => { + const topics: StackbyDataResponse = { + data: [ + { + field: makeTopicField({ exercisesInfo: "ex1,ex2", videoInfo: "" }), + id: "topic4", + }, + ], + }; + expect(countTopicItems("topic4", topics)).toBe(2); + }); + + it("countTopicItems retorna exercícios + vídeo", () => { + expect(countTopicItems("topic1", mockTopics)).toBe(4); + }); + + it('countTopicItems retorna 0 se exercisesInfo for "Untitle"', () => { + expect(countTopicItems("topic3", mockTopics)).toBe(0); + }); + + it("countThemeItems retorna 0 se o tema não existe", () => { + expect(countThemeItems("notfound", mockThemes, mockTopics)).toBe(0); + }); + + it("countThemeItems retorna 0 se não há topicsInfo", () => { + expect(countThemeItems("theme3", mockThemes, mockTopics)).toBe(0); + }); + + it("countThemeItems retorna 0 se topicsInfo está vazio", () => { + expect(countThemeItems("theme2", mockThemes, mockTopics)).toBe(0); + }); + + it("countThemeItems soma corretamente os itens dos tópicos", () => { + expect(countThemeItems("theme1", mockThemes, mockTopics)).toBe(4); // topic1: 4, topic2: 0 + }); + + it("PROGRESS_CALCULATION_BY_ENTITY retorna as funções corretas", () => { + expect(PROGRESS_CALCULATION_BY_ENTITY[StackbyEndpoint.TOPICS]).toBe( + countTopicItems, + ); + expect(PROGRESS_CALCULATION_BY_ENTITY[StackbyEndpoint.THEMES]).toBe( + countThemeItems, + ); + expect(PROGRESS_CALCULATION_BY_ENTITY[StackbyEndpoint.EXERCISES]()).toBe(0); + }); +}); diff --git a/src/utils/progressCalculationByEntity.ts b/src/utils/progressCalculationByEntity.ts new file mode 100644 index 0000000..1cf8877 --- /dev/null +++ b/src/utils/progressCalculationByEntity.ts @@ -0,0 +1,57 @@ +import { + type StackbyDataResponse, + StackbyEndpoint, + type ThemeField, + type TopicField, +} from "../types/types.js"; + +export function countTopicItems( + id: string, + topics: StackbyDataResponse, +): number { + const topic = topics.data.find((topic: { id: string }) => topic.id === id); + if (!topic) return 0; + + const field = topic.field as TopicField; + const { exercisesInfo, videoInfo } = field; + + const exerciseIds = + exercisesInfo && exercisesInfo !== "Untitle" + ? exercisesInfo.split(",").filter(Boolean) + : []; + + return exerciseIds.length + (videoInfo ? 1 : 0); +} + +export function countThemeItems( + id: string, + themes: StackbyDataResponse, + topics: StackbyDataResponse, +): number { + const theme = themes.data.find((theme: { id: string }) => { + return theme.id === id; + }); + if (!theme) return 0; + + const field = theme.field as ThemeField; + if (!field.topicsInfo) return 0; + + const topicIds = field.topicsInfo.split(",").filter(Boolean); + + return topicIds.reduce( + (acc: number, topicId: string) => acc + countTopicItems(topicId, topics), + 0, + ); +} + +export const PROGRESS_CALCULATION_BY_ENTITY: Record< + StackbyEndpoint, + // biome-ignore lint/suspicious/noExplicitAny: A função se adapta a entidade recebida. + (...args: any[]) => number +> = { + [StackbyEndpoint.TOPICS]: countTopicItems, + [StackbyEndpoint.THEMES]: countThemeItems, + [StackbyEndpoint.EXERCISES]: () => 0, +}; + +export type ProgressCalculator = typeof PROGRESS_CALCULATION_BY_ENTITY; diff --git a/src/utils/stackby-filter.ts b/src/utils/stackby-filter.ts new file mode 100644 index 0000000..11289c1 --- /dev/null +++ b/src/utils/stackby-filter.ts @@ -0,0 +1,52 @@ +export type FilterValue = string | number; + +export enum STACKBY_FILTER_OPERATORS { + TO_CONTAINS = "toContains", + DOES_NOT_CONTAIN = "doesNotContain", + EQUAL = "equal", + NOT_EQUAL = "notEqual", + IS_EMPTY = "isEmpty", + IS_NOT_EMPTY = "isNotEmpty", + GREATER_THAN = "greaterThan", + GREATER_THAN_EQUAL = "greaterThanEqual", + LESS_THAN = "lessThan", + LESS_THAN_EQUAL = "lessThanEqual", + IS_EXACTLY = "isExactly", + IS_ANY_OF = "isAnyOf", + FILE_NAME = "fileName", + FILE_TYPE = "fileType", + BY_ID = "rowIds", +} + +export abstract class StackbyFilter { + constructor( + public operator: STACKBY_FILTER_OPERATORS, + public value?: FilterValue, + ) {} + + abstract getStackbyFilterString(): string; +} + +export class StackbyStandardFilter extends StackbyFilter { + constructor( + operator: Exclude, + public column: string, + value?: FilterValue, + ) { + super(operator, value); + } + + getStackbyFilterString(): string { + return `filter=${this.operator}({${this.column}},${this.value})`; + } +} + +export class StackbyFilterById extends StackbyFilter { + constructor(value: string) { + super(STACKBY_FILTER_OPERATORS.BY_ID, value); + } + + getStackbyFilterString(): string { + return `${this.operator}[]=${this.value}`; + } +} diff --git a/tsconfig.json b/tsconfig.json index 9246fe4..a40f74d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,15 +1,27 @@ { - "compilerOptions": { - "target": "es6", - "module": "commonjs", - "outDir": "dist", - "strict": true, - "esModuleInterop": true - }, - "include": [ - "src/**/*.ts" - ], - "exclude": [ - "node_modules" - ] + "compilerOptions": { + "target": "es2022", + "module": "NodeNext", + "moduleResolution": "nodenext", + "noEmitOnError": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "forceConsistentCasingInFileNames": true, + }, + "include": [ + "next-env.d.ts", + "src/**/*.ts", + "src/**/*.tsx", + "tests/**/*.ts", + "prisma/seed.js" + ], + "exclude": [ + "node_modules", + ".adminjs", + "dist", + "prisma" + ] } \ No newline at end of file diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..d888d7f --- /dev/null +++ b/vercel.json @@ -0,0 +1,15 @@ +{ + "version": 2, + "builds": [ + { + "src": "src/index.ts", + "use": "@vercel/node" + } + ], + "routes": [ + { + "src": "(.*)", + "dest": "src/index.ts" + } + ] + } \ No newline at end of file