diff --git a/apps/api/.env.example b/apps/api/.env.example index 79a6cf8..a38b86b 100644 --- a/apps/api/.env.example +++ b/apps/api/.env.example @@ -15,4 +15,56 @@ SESSION_DRIVER=cookie #-------------------------------------------------------------------- # CORS (configure allowed origins for API access) #-------------------------------------------------------------------- -# CORS_ORIGIN=http://localhost:5173,http://localhost:3000 \ No newline at end of file +# CORS_ORIGIN=http://localhost:5173,http://localhost:3000 + +#-------------------------------------------------------------------- +# Database (Postgres via docker-compose.dev.yml) +#-------------------------------------------------------------------- +DB_CONNECTION=postgres +PG_HOST=localhost +PG_PORT=5433 +PG_USER=rubis +PG_PASSWORD=rubis +PG_DB_NAME=rubis_dev + +#-------------------------------------------------------------------- +# Redis (BullMQ + cache) +#-------------------------------------------------------------------- +REDIS_HOST=localhost +REDIS_PORT=6380 +REDIS_PASSWORD= + +#-------------------------------------------------------------------- +# Storage (MinIO via S3 driver) +#-------------------------------------------------------------------- +DRIVE_DISK=s3 +S3_ENDPOINT=http://localhost:9100 +S3_REGION=fr-par +S3_BUCKET=rubis-invoices +S3_ACCESS_KEY=rubis +S3_SECRET_KEY=rubis-dev-secret +S3_FORCE_PATH_STYLE=true + +#-------------------------------------------------------------------- +# Mail (Mailhog en dev, Resend en prod) +#-------------------------------------------------------------------- +MAIL_FROM_ADDRESS=relances@rubis-sur-l-ongle.fr +MAIL_FROM_NAME=Rubis Sur l'Ongle +MAIL_DRIVER=smtp +SMTP_HOST=localhost +SMTP_PORT=1025 +RESEND_API_KEY= + +#-------------------------------------------------------------------- +# OCR (Mistral) +#-------------------------------------------------------------------- +OCR_PROVIDER=mock +MISTRAL_API_KEY= + +#-------------------------------------------------------------------- +# Auth (refresh tokens) +#-------------------------------------------------------------------- +ACCESS_TOKEN_TTL_MINUTES=30 +REFRESH_TOKEN_TTL_DAYS=30 +COOKIE_DOMAIN= +COOKIE_SECURE=false diff --git a/apps/api/config/database.ts b/apps/api/config/database.ts index e36cef1..d5de41e 100644 --- a/apps/api/config/database.ts +++ b/apps/api/config/database.ts @@ -1,130 +1,50 @@ import app from '@adonisjs/core/services/app' import { defineConfig } from '@adonisjs/lucid' +import env from '#start/env' const dbConfig = defineConfig({ /** - * Default connection used for all queries. + * Postgres en dev/prod. SQLite reste accessible via DB_CONNECTION=sqlite + * pour les tests rapides ou un usage offline. */ - connection: 'sqlite', + connection: env.get('DB_CONNECTION', 'postgres'), connections: { - /** - * SQLite connection (default). - */ + postgres: { + client: 'pg', + connection: { + host: env.get('PG_HOST'), + port: env.get('PG_PORT'), + user: env.get('PG_USER'), + password: env.get('PG_PASSWORD'), + database: env.get('PG_DB_NAME'), + }, + migrations: { + naturalSort: true, + paths: ['database/migrations'], + }, + schemaGeneration: { + enabled: true, + rulesPaths: ['./database/schema_rules.js'], + }, + debug: app.inDev, + }, + sqlite: { client: 'better-sqlite3', - connection: { filename: app.tmpPath('db.sqlite3'), }, - - /** - * Required by Knex for SQLite defaults. - */ useNullAsDefault: true, - migrations: { - /** - * Sort migration files naturally by filename. - */ naturalSort: true, - - /** - * Paths containing migration files. - */ paths: ['database/migrations'], }, - schemaGeneration: { - /** - * Enable schema generation from Lucid models. - */ enabled: true, - - /** - * Custom schema rules file paths. - */ rulesPaths: ['./database/schema_rules.js'], }, }, - - /** - * PostgreSQL connection. - * Install package to switch: npm install pg - */ - // pg: { - // client: 'pg', - // connection: { - // host: env.get('DB_HOST'), - // port: env.get('DB_PORT'), - // user: env.get('DB_USER'), - // password: env.get('DB_PASSWORD'), - // database: env.get('DB_DATABASE'), - // }, - // migrations: { - // naturalSort: true, - // paths: ['database/migrations'], - // }, - // debug: app.inDev, - // }, - - /** - * MySQL / MariaDB connection. - * Install package to switch: npm install mysql2 - */ - // mysql: { - // client: 'mysql2', - // connection: { - // host: env.get('DB_HOST'), - // port: env.get('DB_PORT'), - // user: env.get('DB_USER'), - // password: env.get('DB_PASSWORD'), - // database: env.get('DB_DATABASE'), - // }, - // migrations: { - // naturalSort: true, - // paths: ['database/migrations'], - // }, - // debug: app.inDev, - // }, - - /** - * Microsoft SQL Server connection. - * Install package to switch: npm install tedious - */ - // mssql: { - // client: 'mssql', - // connection: { - // server: env.get('DB_HOST'), - // port: env.get('DB_PORT'), - // user: env.get('DB_USER'), - // password: env.get('DB_PASSWORD'), - // database: env.get('DB_DATABASE'), - // }, - // migrations: { - // naturalSort: true, - // paths: ['database/migrations'], - // }, - // debug: app.inDev, - // }, - - /** - * libSQL (Turso) connection. - * Install package to switch: npm install @libsql/client - */ - // libsql: { - // client: 'libsql', - // connection: { - // url: env.get('LIBSQL_URL'), - // authToken: env.get('LIBSQL_AUTH_TOKEN'), - // }, - // useNullAsDefault: true, - // migrations: { - // naturalSort: true, - // paths: ['database/migrations'], - // }, - // debug: app.inDev, - // }, }, }) diff --git a/apps/api/package.json b/apps/api/package.json index 554466f..5c71469 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -48,6 +48,7 @@ "@poppinss/ts-exec": "^1.4.4", "@types/luxon": "^3.7.1", "@types/node": "~25.6.0", + "@types/pg": "^8.20.0", "eslint": "^10.2.0", "hot-hook": "^1.0.0", "pino-pretty": "^13.1.3", @@ -67,6 +68,7 @@ "@vinejs/vine": "^4.3.1", "better-sqlite3": "^12.9.0", "luxon": "^3.7.2", + "pg": "^8.20.0", "reflect-metadata": "^0.2.2" }, "hotHook": { diff --git a/apps/api/start/env.ts b/apps/api/start/env.ts index b9252b0..ea60e96 100644 --- a/apps/api/start/env.ts +++ b/apps/api/start/env.ts @@ -24,4 +24,44 @@ export default await Env.create(new URL('../', import.meta.url), { // Session SESSION_DRIVER: Env.schema.enum(['cookie', 'memory', 'database'] as const), + + // Database + DB_CONNECTION: Env.schema.enum.optional(['postgres', 'sqlite'] as const), + PG_HOST: Env.schema.string.optional({ format: 'host' }), + PG_PORT: Env.schema.number.optional(), + PG_USER: Env.schema.string.optional(), + PG_PASSWORD: Env.schema.string.optional(), + PG_DB_NAME: Env.schema.string.optional(), + + // Redis (BullMQ + cache) + REDIS_HOST: Env.schema.string.optional({ format: 'host' }), + REDIS_PORT: Env.schema.number.optional(), + REDIS_PASSWORD: Env.schema.string.optional(), + + // Storage (MinIO via S3 driver) + DRIVE_DISK: Env.schema.enum.optional(['s3', 'fs'] as const), + S3_ENDPOINT: Env.schema.string.optional({ format: 'url', tld: false }), + S3_REGION: Env.schema.string.optional(), + S3_BUCKET: Env.schema.string.optional(), + S3_ACCESS_KEY: Env.schema.string.optional(), + S3_SECRET_KEY: Env.schema.string.optional(), + S3_FORCE_PATH_STYLE: Env.schema.boolean.optional(), + + // Mail + MAIL_FROM_ADDRESS: Env.schema.string.optional(), + MAIL_FROM_NAME: Env.schema.string.optional(), + MAIL_DRIVER: Env.schema.enum.optional(['smtp', 'resend'] as const), + SMTP_HOST: Env.schema.string.optional({ format: 'host' }), + SMTP_PORT: Env.schema.number.optional(), + RESEND_API_KEY: Env.schema.string.optional(), + + // OCR + OCR_PROVIDER: Env.schema.enum.optional(['mock', 'mistral'] as const), + MISTRAL_API_KEY: Env.schema.string.optional(), + + // Auth + ACCESS_TOKEN_TTL_MINUTES: Env.schema.number.optional(), + REFRESH_TOKEN_TTL_DAYS: Env.schema.number.optional(), + COOKIE_DOMAIN: Env.schema.string.optional(), + COOKIE_SECURE: Env.schema.boolean.optional(), }) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..7ad7a4c --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,81 @@ +name: rubis-dev + +services: + postgres: + image: postgres:16-alpine + container_name: rubis-postgres + restart: unless-stopped + environment: + POSTGRES_USER: rubis + POSTGRES_PASSWORD: rubis + POSTGRES_DB: rubis_dev + ports: + - '5433:5432' + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U rubis -d rubis_dev'] + interval: 5s + timeout: 5s + retries: 5 + + redis: + image: redis:7-alpine + container_name: rubis-redis + restart: unless-stopped + ports: + - '6380:6379' + volumes: + - redis_data:/data + healthcheck: + test: ['CMD', 'redis-cli', 'ping'] + interval: 5s + timeout: 5s + retries: 5 + + minio: + image: minio/minio:latest + container_name: rubis-minio + restart: unless-stopped + command: server /data --console-address ':9001' + environment: + MINIO_ROOT_USER: rubis + MINIO_ROOT_PASSWORD: rubis-dev-secret + ports: + - '9100:9000' # API S3 + - '9101:9001' # Console web + volumes: + - minio_data:/data + healthcheck: + test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live'] + interval: 10s + timeout: 5s + retries: 5 + + # Crée le bucket invoices au démarrage puis sort + minio-bootstrap: + image: minio/mc:latest + container_name: rubis-minio-bootstrap + depends_on: + minio: + condition: service_healthy + entrypoint: > + /bin/sh -c " + mc alias set local http://minio:9000 rubis rubis-dev-secret; + mc mb --ignore-existing local/rubis-invoices; + mc anonymous set none local/rubis-invoices; + exit 0; + " + + mailhog: + image: mailhog/mailhog:latest + container_name: rubis-mailhog + restart: unless-stopped + ports: + - '1025:1025' # SMTP + - '8025:8025' # Web UI + +volumes: + postgres_data: + redis_data: + minio_data: diff --git a/docs/tech/dev-setup.md b/docs/tech/dev-setup.md new file mode 100644 index 0000000..4913c8e --- /dev/null +++ b/docs/tech/dev-setup.md @@ -0,0 +1,100 @@ +# Dev setup — environnement local + +> Version : 0.1 · 2026-05-06 + +Tout ce qu'il faut pour faire tourner Rubis en local : services backing (Postgres, Redis, MinIO, Mailhog) + l'API + le SPA. + +## Prérequis + +- **Node 22+** (cf. `engines` dans `package.json`) +- **pnpm 10+** +- **Docker + Docker Compose v2** (pour les services backing) + +## 1. Services backing — docker-compose.dev.yml + +Un seul fichier à la racine fait tourner les 4 services dont l'API a besoin : + +| Service | Port hôte | Port interne | Notes | +|---|---|---|---| +| **Postgres** | 5433 | 5432 | DB applicative `rubis_dev` (user `rubis` / pass `rubis`) | +| **Redis** | 6380 | 6379 | Backend BullMQ + cache | +| **MinIO API** | 9100 | 9000 | S3-compatible. Bucket `rubis-invoices` créé au boot. | +| **MinIO Console** | 9101 | 9001 | UI web : http://localhost:9101 — login `rubis` / `rubis-dev-secret` | +| **Mailhog SMTP** | 1025 | 1025 | Catch-all pour les emails locaux | +| **Mailhog UI** | 8025 | 8025 | UI web : http://localhost:8025 | + +Les ports hôte sont **décalés** (5433, 6380, 9100…) pour éviter les collisions avec un Postgres/Redis perso éventuellement déjà lancé. + +### Commandes raccourcies + +```bash +pnpm dev:up # Démarrage en background +pnpm dev:logs # Suivre les logs +pnpm dev:down # Arrêt (volumes conservés) +pnpm dev:reset # Arrêt + suppression des volumes (reset DB / MinIO complet) +``` + +### Vérifier que ça tourne + +```bash +docker compose -f docker-compose.dev.yml ps +``` + +Tous les services doivent être `healthy` (sauf `minio-bootstrap` qui sort après avoir créé le bucket — c'est normal). + +## 2. API (apps/api) + +```bash +cd apps/api +cp .env.example .env # Si pas déjà fait +pnpm dev:api # Depuis la racine, ou : pnpm -F api dev +``` + +**Première fois** : + +```bash +pnpm -F api exec node ace migration:run +pnpm -F api exec node ace db:seed +``` + +L'API écoute sur http://localhost:3333. + +### Bascule SQLite (mode dégradé) + +Si Docker n'est pas dispo, on peut basculer sur SQLite : + +```bash +# Dans apps/api/.env +DB_CONNECTION=sqlite +``` + +Les migrations tournent sur les deux. Pour les jobs/storage/mail, il faut quand même Redis/MinIO/Mailhog — donc Docker reste recommandé. + +## 3. Web (apps/web) + +```bash +pnpm dev:web +# → http://localhost:5173 +``` + +Tant que `VITE_USE_MOCKS=true` dans `apps/web/.env`, le SPA tape MSW et n'a pas besoin de l'API. Quand le backend est prêt à servir un domaine, on bascule la valeur sur `false`. + +## 4. Trousseau de variables d'env + +Voir `apps/api/.env.example` — c'est la source de vérité. Récap : + +- **PG_*** : connexion Postgres (default ports décalés docker-compose) +- **REDIS_*** : BullMQ +- **S3_*** : MinIO (driver S3 d'@adonisjs/drive) +- **MAIL_*** + **SMTP_*** : Mailhog en dev, Resend en prod (`MAIL_DRIVER=resend` + `RESEND_API_KEY`) +- **OCR_PROVIDER** : `mock` en dev, `mistral` quand l'API key est en place +- **ACCESS_TOKEN_TTL_MINUTES** / **REFRESH_TOKEN_TTL_DAYS** : durées d'auth + +## 5. Données de seed + +`pnpm -F api exec node ace db:seed` lance : + +- `default_plans_seeder` — 4 plans pré-fournis (Standard B2B, Rapide, Patient, Ferme) +- `demo_data_seeder` — compte `demo@rubis.fr` + clients + factures (dev uniquement) + +Les seeders réutilisent les fixtures de `apps/web/src/mocks/seed.ts` pour garantir la cohérence MSW ↔ vraie API. diff --git a/package.json b/package.json index 1578aad..09945e8 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,10 @@ "dev": "turbo run dev --parallel", "dev:web": "turbo run dev --filter=@rubis/web", "dev:api": "turbo run dev --filter=@rubis/api", + "dev:up": "docker compose -f docker-compose.dev.yml up -d", + "dev:down": "docker compose -f docker-compose.dev.yml down", + "dev:logs": "docker compose -f docker-compose.dev.yml logs -f", + "dev:reset": "docker compose -f docker-compose.dev.yml down -v", "build": "turbo run build", "lint": "turbo run lint", "typecheck": "turbo run typecheck", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e659d48..d20bdf1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,7 +34,7 @@ importers: dependencies: '@adonisjs/auth': specifier: ^10.1.0 - version: 10.1.0(34ff5d8723e1f5435ca619cb62021582) + version: 10.1.0(cb463dcab987fc365459355e33b96486) '@adonisjs/core': specifier: ^7.3.1 version: 7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1) @@ -43,13 +43,13 @@ importers: version: 3.0.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1)) '@adonisjs/lucid': specifier: ^22.4.2 - version: 22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2) + version: 22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2)(pg@8.20.0) '@adonisjs/session': specifier: ^8.1.0 - version: 8.1.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/runner@5.3.0)) + version: 8.1.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2)(pg@8.20.0))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/runner@5.3.0)) '@adonisjs/shield': specifier: ^9.0.0 - version: 9.0.0(5f877bcd52ddd9fae9bba041f2afb929) + version: 9.0.0(adb93641c3908819f9462459e2e86e5c) '@japa/api-client': specifier: ^3.2.1 version: 3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0) @@ -65,6 +65,9 @@ importers: luxon: specifier: ^3.7.2 version: 3.7.2 + pg: + specifier: ^8.20.0 + version: 8.20.0 reflect-metadata: specifier: ^0.2.2 version: 0.2.2 @@ -99,6 +102,9 @@ importers: '@types/node': specifier: ~25.6.0 version: 25.6.0 + '@types/pg': + specifier: ^8.20.0 + version: 8.20.0 eslint: specifier: ^10.2.0 version: 10.3.0(jiti@2.7.0) @@ -2257,6 +2263,9 @@ packages: '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/pg@8.20.0': + resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} + '@types/pluralize@0.0.33': resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} @@ -3980,9 +3989,43 @@ packages: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} + pg-cloudflare@1.3.0: + resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} + + pg-connection-string@2.12.0: + resolution: {integrity: sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==} + pg-connection-string@2.6.2: resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.13.0: + resolution: {integrity: sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.13.0: + resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.20.0: + resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -4025,6 +4068,22 @@ packages: resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + powershell-utils@0.1.0: resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} engines: {node: '>=20'} @@ -4943,6 +5002,10 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5046,15 +5109,15 @@ snapshots: transitivePeerDependencies: - babel-plugin-macros - '@adonisjs/auth@10.1.0(34ff5d8723e1f5435ca619cb62021582)': + '@adonisjs/auth@10.1.0(cb463dcab987fc365459355e33b96486)': dependencies: '@adonisjs/core': 7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1) '@adonisjs/presets': 3.0.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1)) basic-auth: 2.0.1 optionalDependencies: '@adonisjs/assembler': 8.4.0(typescript@6.0.3) - '@adonisjs/lucid': 22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2) - '@adonisjs/session': 8.1.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/runner@5.3.0)) + '@adonisjs/lucid': 22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2)(pg@8.20.0) + '@adonisjs/session': 8.1.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2)(pg@8.20.0))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/runner@5.3.0)) '@japa/api-client': 3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0) '@japa/plugin-adonisjs': 5.2.0(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/runner@5.3.0) @@ -5213,7 +5276,7 @@ snapshots: optionalDependencies: pino-pretty: 13.1.3 - '@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2)': + '@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2)(pg@8.20.0)': dependencies: '@adonisjs/core': 7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1) '@adonisjs/presets': 3.0.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1)) @@ -5226,8 +5289,8 @@ snapshots: fast-deep-equal: 3.1.3 igniculus: 1.5.0 kleur: 4.1.5 - knex: 3.2.10(better-sqlite3@12.9.0) - knex-dynamic-connection: 5.0.1(better-sqlite3@12.9.0) + knex: 3.2.10(better-sqlite3@12.9.0)(pg@8.20.0) + knex-dynamic-connection: 5.0.1(better-sqlite3@12.9.0)(pg@8.20.0) pretty-hrtime: 1.0.3 slash: 5.1.0 tarn: 3.0.2 @@ -5261,21 +5324,21 @@ snapshots: '@poppinss/colors': 4.1.6 string-width: 8.2.1 - '@adonisjs/session@8.1.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/runner@5.3.0))': + '@adonisjs/session@8.1.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2)(pg@8.20.0))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/runner@5.3.0))': dependencies: '@adonisjs/core': 7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1) '@poppinss/macroable': 1.1.2 '@poppinss/utils': 7.0.1 optionalDependencies: '@adonisjs/assembler': 8.4.0(typescript@6.0.3) - '@adonisjs/lucid': 22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2) + '@adonisjs/lucid': 22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2)(pg@8.20.0) '@japa/api-client': 3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0) '@japa/plugin-adonisjs': 5.2.0(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/runner@5.3.0) - '@adonisjs/shield@9.0.0(5f877bcd52ddd9fae9bba041f2afb929)': + '@adonisjs/shield@9.0.0(adb93641c3908819f9462459e2e86e5c)': dependencies: '@adonisjs/core': 7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1) - '@adonisjs/session': 8.1.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/runner@5.3.0)) + '@adonisjs/session': 8.1.0(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@adonisjs/lucid@22.4.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@vinejs/vine@4.4.0)(better-sqlite3@12.9.0)(luxon@3.7.2)(pg@8.20.0))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/plugin-adonisjs@5.2.0(@adonisjs/core@7.3.2(@adonisjs/assembler@8.4.0(typescript@6.0.3))(@vinejs/vine@4.4.0)(pino-pretty@13.1.3)(youch@4.1.1))(@japa/api-client@3.2.1(@japa/assert@4.2.0(@japa/runner@5.3.0))(@japa/runner@5.3.0))(@japa/runner@5.3.0)) csrf: 3.1.0 optionalDependencies: '@adonisjs/assembler': 8.4.0(typescript@6.0.3) @@ -6807,6 +6870,12 @@ snapshots: '@types/normalize-package-data@2.4.4': {} + '@types/pg@8.20.0': + dependencies: + '@types/node': 25.6.0 + pg-protocol: 1.13.0 + pg-types: 2.2.0 + '@types/pluralize@0.0.33': {} '@types/react-dom@19.2.3(@types/react@19.2.14)': @@ -8085,10 +8154,10 @@ snapshots: kleur@4.1.5: {} - knex-dynamic-connection@5.0.1(better-sqlite3@12.9.0): + knex-dynamic-connection@5.0.1(better-sqlite3@12.9.0)(pg@8.20.0): dependencies: debug: 4.4.3 - knex: 3.2.7(better-sqlite3@12.9.0) + knex: 3.2.7(better-sqlite3@12.9.0)(pg@8.20.0) transitivePeerDependencies: - better-sqlite3 - mysql @@ -8100,7 +8169,7 @@ snapshots: - supports-color - tedious - knex@3.2.10(better-sqlite3@12.9.0): + knex@3.2.10(better-sqlite3@12.9.0)(pg@8.20.0): dependencies: colorette: 2.0.19 commander: 10.0.1 @@ -8118,10 +8187,11 @@ snapshots: tildify: 2.0.0 optionalDependencies: better-sqlite3: 12.9.0 + pg: 8.20.0 transitivePeerDependencies: - supports-color - knex@3.2.7(better-sqlite3@12.9.0): + knex@3.2.7(better-sqlite3@12.9.0)(pg@8.20.0): dependencies: colorette: 2.0.19 commander: 10.0.1 @@ -8139,6 +8209,7 @@ snapshots: tildify: 2.0.0 optionalDependencies: better-sqlite3: 12.9.0 + pg: 8.20.0 transitivePeerDependencies: - supports-color @@ -8474,8 +8545,43 @@ snapshots: pathval@2.0.1: {} + pg-cloudflare@1.3.0: + optional: true + + pg-connection-string@2.12.0: {} + pg-connection-string@2.6.2: {} + pg-int8@1.0.1: {} + + pg-pool@3.13.0(pg@8.20.0): + dependencies: + pg: 8.20.0 + + pg-protocol@1.13.0: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.1 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg@8.20.0: + dependencies: + pg-connection-string: 2.12.0 + pg-pool: 3.13.0(pg@8.20.0) + pg-protocol: 1.13.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.3.0 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + picocolors@1.1.1: {} picomatch@2.3.2: {} @@ -8532,6 +8638,16 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postgres-array@2.0.0: {} + + postgres-bytea@1.0.1: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + powershell-utils@0.1.0: {} prebuild-install@7.1.3: @@ -9382,6 +9498,8 @@ snapshots: xmlchars@2.2.0: {} + xtend@4.0.2: {} + y18n@5.0.8: {} yallist@3.1.1: {}