From ca0f7cf4b18fc2b1b13247e833122fc5ee975cd9 Mon Sep 17 00:00:00 2001 From: Claude Fable 5 Date: Sat, 4 Jul 2026 19:16:19 +0200 Subject: [PATCH] Add Prisma with PostgreSQL, automatic migrations, and /readyz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit apps/api gains Prisma (instance_settings as the first model) with the initial migration applied automatically at startup via prisma migrate deploy, a lazy-connecting PrismaService, and GET /api/v1/readyz reporting named checks (database reachable, migrations applied) with 200/503. DATABASE_URL joins the validated environment schema; MIGRATE_ON_START=false skips deploys for tests and tooling. An idempotent seed script and a Compose dev overlay with PostgreSQL (host port 5434 — 5433 is taken locally) complete the loop. Closes #3 Co-Authored-By: Claude Fable 5 --- apps/api/package.json | 11 +- .../20260704171456_init/migration.sql | 8 + .../api/prisma/migrations/migration_lock.toml | 3 + apps/api/prisma/schema.prisma | 23 ++ apps/api/prisma/seed.ts | 24 ++ apps/api/src/app.module.ts | 2 + apps/api/src/health/health.controller.ts | 28 +- apps/api/src/health/health.e2e.test.ts | 10 + apps/api/src/health/health.module.ts | 2 + apps/api/src/health/readiness.service.ts | 69 ++++ apps/api/src/main.ts | 20 + apps/api/src/prisma/prisma.module.ts | 11 + apps/api/src/prisma/prisma.service.ts | 14 + deploy/compose/compose.dev.yml | 28 ++ packages/shared/src/env.test.ts | 19 +- packages/shared/src/env.ts | 12 + pnpm-lock.yaml | 365 +++++++++++++++--- pnpm-workspace.yaml | 3 + 18 files changed, 596 insertions(+), 56 deletions(-) create mode 100644 apps/api/prisma/migrations/20260704171456_init/migration.sql create mode 100644 apps/api/prisma/migrations/migration_lock.toml create mode 100644 apps/api/prisma/schema.prisma create mode 100644 apps/api/prisma/seed.ts create mode 100644 apps/api/src/health/readiness.service.ts create mode 100644 apps/api/src/prisma/prisma.module.ts create mode 100644 apps/api/src/prisma/prisma.service.ts create mode 100644 deploy/compose/compose.dev.yml diff --git a/apps/api/package.json b/apps/api/package.json index 28bc37f..3561c09 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -5,14 +5,18 @@ "description": "Dorfteich REST API server", "license": "MIT", "scripts": { - "build": "nest build", + "build": "prisma generate && nest build", "start": "node dist/main.js", - "start:dev": "nest start --watch", + "start:dev": "prisma generate && nest start --watch", "typecheck": "tsc --noEmit", - "test": "vitest run --passWithNoTests" + "test": "vitest run --passWithNoTests", + "db:migrate:dev": "prisma migrate dev", + "db:seed": "tsx prisma/seed.ts" }, "dependencies": { "@dorfteich/shared": "workspace:*", + "@prisma/client": "^6.3.0", + "prisma": "^6.3.0", "@nestjs/common": "^11.0.0", "@nestjs/core": "^11.0.0", "@nestjs/platform-express": "^11.0.0", @@ -30,6 +34,7 @@ "@types/supertest": "^6.0.0", "pino-pretty": "^13.0.0", "supertest": "^7.0.0", + "tsx": "^4.19.0", "unplugin-swc": "^1.5.0", "vitest": "^3.0.0" } diff --git a/apps/api/prisma/migrations/20260704171456_init/migration.sql b/apps/api/prisma/migrations/20260704171456_init/migration.sql new file mode 100644 index 0000000..f74aa23 --- /dev/null +++ b/apps/api/prisma/migrations/20260704171456_init/migration.sql @@ -0,0 +1,8 @@ +-- CreateTable +CREATE TABLE "instance_settings" ( + "key" TEXT NOT NULL, + "value" JSONB NOT NULL, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "instance_settings_pkey" PRIMARY KEY ("key") +); diff --git a/apps/api/prisma/migrations/migration_lock.toml b/apps/api/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..044d57c --- /dev/null +++ b/apps/api/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/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma new file mode 100644 index 0000000..0118d21 --- /dev/null +++ b/apps/api/prisma/schema.prisma @@ -0,0 +1,23 @@ +// Prisma schema — the single source of truth for the database structure. +// The entity documentation lives in docs/architecture/data-model.md; keep +// both in sync when the schema evolves. + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +/// Typed key-value configuration for the instance (registration mode, +/// default quotas, legal pages, …). Values are validated with Zod before +/// writing; see the InstanceSettings service (issue #19). +model InstanceSetting { + key String @id + value Json + updatedAt DateTime @updatedAt + + @@map("instance_settings") +} diff --git a/apps/api/prisma/seed.ts b/apps/api/prisma/seed.ts new file mode 100644 index 0000000..36284c1 --- /dev/null +++ b/apps/api/prisma/seed.ts @@ -0,0 +1,24 @@ +/** + * Development/Test fixture seeding. Idempotent: running it twice must not + * duplicate anything. Real fixtures (users, ponds, pages) arrive with their + * feature stories (#20, #32); until then this only proves the wiring. + */ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +async function main(): Promise { + await prisma.instanceSetting.upsert({ + where: { key: 'seed.marker' }, + create: { key: 'seed.marker', value: { seededAt: new Date().toISOString() } }, + update: { value: { seededAt: new Date().toISOString() } }, + }); + console.log('seed: done (no fixtures defined yet)'); +} + +main() + .catch((error) => { + console.error(error); + process.exitCode = 1; + }) + .finally(() => prisma.$disconnect()); diff --git a/apps/api/src/app.module.ts b/apps/api/src/app.module.ts index 27b8ab5..8709a91 100644 --- a/apps/api/src/app.module.ts +++ b/apps/api/src/app.module.ts @@ -6,10 +6,12 @@ import { ApiExceptionFilter } from './common/api-exception.filter'; import { AppConfig } from './config/app-config.service'; import { ConfigModule } from './config/config.module'; import { HealthModule } from './health/health.module'; +import { PrismaModule } from './prisma/prisma.module'; @Module({ imports: [ ConfigModule, + PrismaModule, LoggerModule.forRootAsync({ inject: [AppConfig], useFactory: (config: AppConfig) => ({ diff --git a/apps/api/src/health/health.controller.ts b/apps/api/src/health/health.controller.ts index 38c8774..2e068e3 100644 --- a/apps/api/src/health/health.controller.ts +++ b/apps/api/src/health/health.controller.ts @@ -1,15 +1,33 @@ -import { Controller, Get } from '@nestjs/common'; +import { Controller, Get, HttpStatus, Res } from '@nestjs/common'; import { HealthResponse, healthResponse } from '@dorfteich/shared'; +import type { Response } from 'express'; import { AppConfig } from '../config/app-config.service'; +import { ReadinessService } from './readiness.service'; -@Controller('healthz') +@Controller() export class HealthController { - constructor(private readonly config: AppConfig) {} + constructor( + private readonly config: AppConfig, + private readonly readiness: ReadinessService, + ) {} - /** Liveness only — readiness (`/readyz`) arrives with the database (issue #3). */ - @Get() + /** Liveness: the process is up. Used by Docker healthchecks. */ + @Get('healthz') healthz(): HealthResponse { return healthResponse('api', this.config.env.APP_VERSION); } + + /** + * Readiness: the api can do real work. Used by uptime monitoring. + * The report body is sent as-is with 200/503 (not through the exception + * filter) so monitors always see which check failed. + */ + @Get('readyz') + async readyz(@Res() res: Response): Promise { + const report = await this.readiness.report(); + res + .status(report.status === 'ok' ? HttpStatus.OK : HttpStatus.SERVICE_UNAVAILABLE) + .json(report); + } } diff --git a/apps/api/src/health/health.e2e.test.ts b/apps/api/src/health/health.e2e.test.ts index 266984a..45a12d9 100644 --- a/apps/api/src/health/health.e2e.test.ts +++ b/apps/api/src/health/health.e2e.test.ts @@ -10,6 +10,9 @@ describe('GET /api/v1/healthz (e2e)', () => { beforeAll(async () => { process.env.NODE_ENV = 'test'; + // Points at a closed port: healthz must work without a database, and + // readyz must report unready instead of crashing. + process.env.DATABASE_URL ??= 'postgresql://nobody:nothing@127.0.0.1:59999/absent'; const moduleRef = await Test.createTestingModule({ imports: [AppModule] }).compile(); app = moduleRef.createNestApplication(); app.setGlobalPrefix('api/v1'); @@ -27,6 +30,13 @@ describe('GET /api/v1/healthz (e2e)', () => { expect(typeof res.body.version).toBe('string'); }); + it('reports unready with 503 while the database is unreachable', async () => { + const res = await request(app.getHttpServer()).get('/api/v1/readyz').expect(503); + expect(res.body.status).toBe('unready'); + const failed = res.body.checks.filter((c: { status: string }) => c.status === 'failed'); + expect(failed.length).toBeGreaterThan(0); + }); + it('returns the uniform error shape for unknown routes', async () => { const res = await request(app.getHttpServer()).get('/api/v1/does-not-exist').expect(404); expect(res.body.code).toBe('not_found'); diff --git a/apps/api/src/health/health.module.ts b/apps/api/src/health/health.module.ts index 90d1fe0..c878991 100644 --- a/apps/api/src/health/health.module.ts +++ b/apps/api/src/health/health.module.ts @@ -1,8 +1,10 @@ import { Module } from '@nestjs/common'; import { HealthController } from './health.controller'; +import { ReadinessService } from './readiness.service'; @Module({ controllers: [HealthController], + providers: [ReadinessService], }) export class HealthModule {} diff --git a/apps/api/src/health/readiness.service.ts b/apps/api/src/health/readiness.service.ts new file mode 100644 index 0000000..3053977 --- /dev/null +++ b/apps/api/src/health/readiness.service.ts @@ -0,0 +1,69 @@ +import { Injectable } from '@nestjs/common'; + +import { PrismaService } from '../prisma/prisma.service'; + +export interface ReadinessCheck { + name: string; + status: 'ok' | 'failed'; + detail?: string; +} + +export interface ReadinessReport { + status: 'ok' | 'unready'; + checks: ReadinessCheck[]; +} + +@Injectable() +export class ReadinessService { + constructor(private readonly prisma: PrismaService) {} + + /** + * Readiness = the api can do real work: database reachable and all + * migrations applied. Further checks (converters, backup freshness) are + * added by later stories (issues #62, #85) — each as one more entry in + * the checks array, never as a separate endpoint. + */ + async report(): Promise { + const checks: ReadinessCheck[] = [ + await this.databaseReachable(), + await this.migrationsApplied(), + ]; + return { + status: checks.every((c) => c.status === 'ok') ? 'ok' : 'unready', + checks, + }; + } + + private async databaseReachable(): Promise { + try { + await this.prisma.$queryRaw`SELECT 1`; + return { name: 'database', status: 'ok' }; + } catch (error) { + return { name: 'database', status: 'failed', detail: shortMessage(error) }; + } + } + + private async migrationsApplied(): Promise { + try { + // `prisma migrate deploy` records every migration here; an entry + // without finished_at is pending or failed. + const rows = await this.prisma.$queryRaw<{ pending: bigint }[]>` + SELECT count(*)::bigint AS pending + FROM _prisma_migrations + WHERE finished_at IS NULL AND rolled_back_at IS NULL + `; + const pending = Number(rows[0]?.pending ?? 0); + return pending === 0 + ? { name: 'migrations', status: 'ok' } + : { name: 'migrations', status: 'failed', detail: `${pending} migration(s) pending` }; + } catch (error) { + return { name: 'migrations', status: 'failed', detail: shortMessage(error) }; + } + } +} + +function shortMessage(error: unknown): string { + const message = error instanceof Error ? error.message : String(error); + // Keep readiness output single-line and free of connection strings. + return message.split('\n').filter(Boolean).slice(-1)[0]?.slice(0, 200) ?? 'unknown error'; +} diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 08e7174..527439d 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -1,10 +1,30 @@ +import { execFileSync } from 'node:child_process'; + import { NestFactory } from '@nestjs/core'; +import { apiEnvSchema, parseEnv } from '@dorfteich/shared'; import { Logger } from 'nestjs-pino'; import { AppModule } from './app.module'; import { AppConfig } from './config/app-config.service'; +/** + * Apply pending migrations before the application accepts traffic, so + * self-hosters update by simply pulling a new image (ADR 0002). Prisma + * serializes concurrent deploys with a database advisory lock. + */ +function runMigrations(): void { + const prismaCli = require.resolve('prisma/build/index.js'); + execFileSync(process.execPath, [prismaCli, 'migrate', 'deploy'], { stdio: 'inherit' }); +} + async function bootstrap(): Promise { + // Validate the environment before doing anything with it; this throws a + // readable list of problems and prevents a half-started process. + const env = parseEnv(apiEnvSchema, process.env); + if (env.MIGRATE_ON_START) { + runMigrations(); + } + // bufferLogs holds early log lines until the pino logger is attached, // so even bootstrap errors come out as structured JSON. const app = await NestFactory.create(AppModule, { bufferLogs: true }); diff --git a/apps/api/src/prisma/prisma.module.ts b/apps/api/src/prisma/prisma.module.ts new file mode 100644 index 0000000..3dadb55 --- /dev/null +++ b/apps/api/src/prisma/prisma.module.ts @@ -0,0 +1,11 @@ +import { Global, Module } from '@nestjs/common'; + +import { PrismaService } from './prisma.service'; + +/** Global: the database client is a cross-cutting dependency like AppConfig. */ +@Global() +@Module({ + providers: [PrismaService], + exports: [PrismaService], +}) +export class PrismaModule {} diff --git a/apps/api/src/prisma/prisma.service.ts b/apps/api/src/prisma/prisma.service.ts new file mode 100644 index 0000000..defa3fc --- /dev/null +++ b/apps/api/src/prisma/prisma.service.ts @@ -0,0 +1,14 @@ +import { Injectable, OnModuleDestroy } from '@nestjs/common'; +import { PrismaClient } from '@prisma/client'; + +/** + * PrismaClient as a Nest provider. Connections are opened lazily on first + * query (Prisma default), so the application can boot — and report an + * unready state via /readyz — while the database is still starting up. + */ +@Injectable() +export class PrismaService extends PrismaClient implements OnModuleDestroy { + async onModuleDestroy(): Promise { + await this.$disconnect(); + } +} diff --git a/deploy/compose/compose.dev.yml b/deploy/compose/compose.dev.yml new file mode 100644 index 0000000..0198ac3 --- /dev/null +++ b/deploy/compose/compose.dev.yml @@ -0,0 +1,28 @@ +# Local development overlay. For now this only provides the database; +# issue #6 extends it with hot-reloading web/api services layered over the +# production docker-compose.yml. +# +# Usage (from the repo root): +# docker compose -f deploy/compose/compose.dev.yml up -d db +# DATABASE_URL=postgresql://dorfteich:dorfteich@localhost:5434/dorfteich pnpm --filter @dorfteich/api start:dev + +services: + db: + image: postgres:17.5-alpine + environment: + POSTGRES_USER: dorfteich + POSTGRES_PASSWORD: dorfteich + POSTGRES_DB: dorfteich + ports: + # 5434 on the host to avoid colliding with other local PostgreSQL instances (5432 system, 5433 wochenplan-staging). + - '5434:5432' + volumes: + - db-data:/var/lib/postgresql/data + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U dorfteich -d dorfteich'] + interval: 5s + timeout: 3s + retries: 10 + +volumes: + db-data: diff --git a/packages/shared/src/env.test.ts b/packages/shared/src/env.test.ts index 2baa854..2b705cf 100644 --- a/packages/shared/src/env.test.ts +++ b/packages/shared/src/env.test.ts @@ -2,16 +2,27 @@ import { describe, expect, it } from 'vitest'; import { apiEnvSchema, parseEnv } from './env'; +const MINIMAL_ENV = { DATABASE_URL: 'postgresql://user:pass@localhost:5432/db' }; + describe('parseEnv', () => { it('applies defaults for a minimal environment', () => { - const env = parseEnv(apiEnvSchema, {}); + const env = parseEnv(apiEnvSchema, MINIMAL_ENV); expect(env.PORT).toBe(3000); expect(env.NODE_ENV).toBe('development'); + expect(env.MIGRATE_ON_START).toBe(true); + }); + + it('requires DATABASE_URL', () => { + expect(() => parseEnv(apiEnvSchema, {})).toThrowError(/DATABASE_URL/); + }); + + it('rejects non-postgres connection strings', () => { + expect(() => parseEnv(apiEnvSchema, { DATABASE_URL: 'mysql://x' })).toThrowError(/postgresql/); }); it('fails with a message naming every invalid variable', () => { - expect(() => parseEnv(apiEnvSchema, { PORT: 'not-a-port', LOG_LEVEL: 'loud' })).toThrowError( - /PORT.*\n.*LOG_LEVEL/s, - ); + expect(() => + parseEnv(apiEnvSchema, { ...MINIMAL_ENV, PORT: 'not-a-port', LOG_LEVEL: 'loud' }), + ).toThrowError(/PORT.*\n.*LOG_LEVEL/s); }); }); diff --git a/packages/shared/src/env.ts b/packages/shared/src/env.ts index 4ce8a1b..0bfce23 100644 --- a/packages/shared/src/env.ts +++ b/packages/shared/src/env.ts @@ -12,6 +12,18 @@ export const apiEnvSchema = z.object({ LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'), /** Version shown in health responses; injected at image build time. */ APP_VERSION: z.string().default('0.0.0-dev'), + /** PostgreSQL connection string — required, there is no sensible default. */ + DATABASE_URL: z + .string() + .min(1) + .refine((url) => url.startsWith('postgresql://') || url.startsWith('postgres://'), { + message: 'must be a postgresql:// connection string', + }), + /** Set to "false" to skip `prisma migrate deploy` at startup (tests, tooling). */ + MIGRATE_ON_START: z + .enum(['true', 'false']) + .default('true') + .transform((value) => value === 'true'), }); export type ApiEnv = z.infer; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 285f331..c25c063 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,10 +13,10 @@ importers: version: 9.39.4 eslint: specifier: ^9.20.0 - version: 9.39.4 + version: 9.39.4(jiti@2.7.0) eslint-config-prettier: specifier: ^10.0.0 - version: 10.1.8(eslint@9.39.4) + version: 10.1.8(eslint@9.39.4(jiti@2.7.0)) prettier: specifier: ^3.5.0 version: 3.9.4 @@ -25,7 +25,7 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.24.0 - version: 8.62.1(eslint@9.39.4)(typescript@5.9.3) + version: 8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) apps/api: dependencies: @@ -41,6 +41,9 @@ importers: '@nestjs/platform-express': specifier: ^11.0.0 version: 11.1.27(@nestjs/common@11.1.27(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.27) + '@prisma/client': + specifier: ^6.3.0 + version: 6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3) nestjs-pino: specifier: ^4.3.0 version: 4.6.1(@nestjs/common@11.1.27(reflect-metadata@0.2.2)(rxjs@7.8.2))(pino-http@10.5.0)(pino@9.14.0)(rxjs@7.8.2) @@ -50,6 +53,9 @@ importers: pino-http: specifier: ^10.4.0 version: 10.5.0 + prisma: + specifier: ^6.3.0 + version: 6.19.3(typescript@5.9.3) reflect-metadata: specifier: ^0.2.2 version: 0.2.2 @@ -78,24 +84,27 @@ importers: supertest: specifier: ^7.0.0 version: 7.2.2 + tsx: + specifier: ^4.19.0 + version: 4.23.0 unplugin-swc: specifier: ^1.5.0 version: 1.5.9(@swc/core@1.15.43)(rollup@4.62.2) vitest: specifier: ^3.0.0 - version: 3.2.6(@types/node@26.1.0)(terser@5.48.0) + version: 3.2.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0) apps/collab: devDependencies: vitest: specifier: ^3.0.0 - version: 3.2.6(@types/node@26.1.0)(terser@5.48.0) + version: 3.2.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0) apps/web: devDependencies: vitest: specifier: ^3.0.0 - version: 3.2.6(@types/node@26.1.0)(terser@5.48.0) + version: 3.2.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0) packages/shared: dependencies: @@ -105,10 +114,10 @@ importers: devDependencies: tsup: specifier: ^8.3.0 - version: 8.5.1(@swc/core@1.15.43)(postcss@8.5.16)(typescript@5.9.3) + version: 8.5.1(@swc/core@1.15.43)(jiti@2.7.0)(postcss@8.5.16)(tsx@4.23.0)(typescript@5.9.3) vitest: specifier: ^3.0.0 - version: 3.2.6(@types/node@26.1.0)(terser@5.48.0) + version: 3.2.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0) packages: @@ -776,6 +785,36 @@ packages: '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + '@prisma/client@6.19.3': + resolution: {integrity: sha512-mKq3jQFhjvko5LTJFHGilsuQs+W+T3Gm451NzuTDGQxwCzwXHYnIu2zGkRoW+Exq3Rob7yp2MfzSrdIiZVhrBg==} + engines: {node: '>=18.18'} + peerDependencies: + prisma: '*' + typescript: '>=5.1.0' + peerDependenciesMeta: + prisma: + optional: true + typescript: + optional: true + + '@prisma/config@6.19.3': + resolution: {integrity: sha512-CBPT44BjlQxEt8kiMEauji2WHTDoVBOKl7UlewXmUgBPnr/oPRZC3psci5chJnYmH0ivEIog2OU9PGWoki3DLQ==} + + '@prisma/debug@6.19.3': + resolution: {integrity: sha512-ljkJ+SgpXNktLG0Q/n4JGYCkKf0f8oYLyjImS2I8e2q2WCfdRRtWER062ZV/ixaNP2M2VKlWXVJiGzZaUgbKZw==} + + '@prisma/engines-version@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': + resolution: {integrity: sha512-03bgb1VD5gvuumNf+7fVGBzfpJPjmqV423l/WxsWk2cNQ42JD0/SsFBPhN6z8iAvdHs07/7ei77SKu7aZfq8bA==} + + '@prisma/engines@6.19.3': + resolution: {integrity: sha512-RSYxtlYFl5pJ8ZePgMv0lZ9IzVCOdTPOegrs2qcbAEFrBI1G33h6wyC9kjQvo0DnYEhEVY0X4LsuFHXLKQk88g==} + + '@prisma/fetch-engine@6.19.3': + resolution: {integrity: sha512-tKtl/qco9Nt7LU5iKhpultD8O4vMCZcU2CHjNTnRrL1QvSUr5W/GcyFPjNL87GtRrwBc7ubXXD9xy4EvLvt8JA==} + + '@prisma/get-platform@6.19.3': + resolution: {integrity: sha512-xFj1VcJ1N3MKooOQAGO0W5tsd0W2QzIvW7DD7c/8H14Zmp4jseeWAITm+w2LLoLrlhoHdPPh0NMZ8mfL6puoHA==} + '@rollup/pluginutils@5.4.0': resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} engines: {node: '>=14.0.0'} @@ -923,6 +962,9 @@ packages: cpu: [x64] os: [win32] + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@swc/core-darwin-arm64@1.15.43': resolution: {integrity: sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==} engines: {node: '>=10'} @@ -1373,6 +1415,14 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + c12@3.1.0: + resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -1415,6 +1465,12 @@ packages: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + citty@0.2.2: + resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} + cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -1473,6 +1529,9 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} @@ -1536,6 +1595,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge-ts@7.1.5: + resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} + engines: {node: '>=16.0.0'} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -1543,6 +1606,9 @@ packages: defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -1551,9 +1617,16 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + dezalgo@1.0.4: resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -1561,12 +1634,19 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + effect@3.21.0: + resolution: {integrity: sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ==} + electron-to-chromium@1.5.385: resolution: {integrity: sha512-78sa/M08MNAYHQfjoWMvOlKQqZ0ElhSm/L5HNUc96VZ3b+KvDVnngFm8sYQy0XrhTRgAhggHr5abA7yTvRdo4Q==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} + encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -1711,6 +1791,13 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} + exsolve@1.1.0: + resolution: {integrity: sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==} + + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + fast-copy@4.0.3: resolution: {integrity: sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==} @@ -1814,6 +1901,10 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} @@ -1926,6 +2017,10 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -2132,10 +2227,18 @@ packages: node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-releases@2.0.50: resolution: {integrity: sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==} engines: {node: '>=18'} + nypm@0.6.8: + resolution: {integrity: sha512-Q9K4Diu6l5u6xJQogeFSs/zKtyMSgFKFtRQV+tHP4kL7KPm2grpBU0dFIwFaXwNxN0MtfKWc43VpCugAa+LPsw==} + engines: {node: '>=18'} + hasBin: true + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2144,6 +2247,9 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} @@ -2213,6 +2319,9 @@ packages: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2251,6 +2360,9 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -2286,6 +2398,16 @@ packages: engines: {node: '>=14'} hasBin: true + prisma@6.19.3: + resolution: {integrity: sha512-++ZJ0ijLrDJF6hNB4t4uxg2br3fC4H9Yc9tcbjr2fcNFP3rh/SBNrAgjhsqBU4Ght8JPrVofG/ZkXfnSfnYsFg==} + engines: {node: '>=18.18'} + hasBin: true + peerDependencies: + typescript: '>=5.1.0' + peerDependenciesMeta: + typescript: + optional: true + process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} @@ -2300,6 +2422,9 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qs@6.15.3: resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} engines: {node: '>=0.6'} @@ -2315,6 +2440,9 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -2595,6 +2723,10 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -2662,6 +2794,11 @@ packages: typescript: optional: true + tsx@4.23.0: + resolution: {integrity: sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==} + engines: {node: '>=18.0.0'} + hasBin: true + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -3098,9 +3235,9 @@ snapshots: '@esbuild/win32-x64@0.28.1': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4)': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': dependencies: - eslint: 9.39.4 + eslint: 9.39.4(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -3430,6 +3567,41 @@ snapshots: '@pinojs/redact@0.4.0': {} + '@prisma/client@6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3)': + optionalDependencies: + prisma: 6.19.3(typescript@5.9.3) + typescript: 5.9.3 + + '@prisma/config@6.19.3': + dependencies: + c12: 3.1.0 + deepmerge-ts: 7.1.5 + effect: 3.21.0 + empathic: 2.0.0 + transitivePeerDependencies: + - magicast + + '@prisma/debug@6.19.3': {} + + '@prisma/engines-version@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': {} + + '@prisma/engines@6.19.3': + dependencies: + '@prisma/debug': 6.19.3 + '@prisma/engines-version': 7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + '@prisma/fetch-engine': 6.19.3 + '@prisma/get-platform': 6.19.3 + + '@prisma/fetch-engine@6.19.3': + dependencies: + '@prisma/debug': 6.19.3 + '@prisma/engines-version': 7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + '@prisma/get-platform': 6.19.3 + + '@prisma/get-platform@6.19.3': + dependencies: + '@prisma/debug': 6.19.3 + '@rollup/pluginutils@5.4.0(rollup@4.62.2)': dependencies: '@types/estree': 1.0.9 @@ -3513,6 +3685,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.62.2': optional: true + '@standard-schema/spec@1.1.0': {} + '@swc/core-darwin-arm64@1.15.43': optional: true @@ -3660,15 +3834,15 @@ snapshots: '@types/methods': 1.1.4 '@types/superagent': 8.1.10 - '@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.62.1(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/parser': 8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.62.1 - '@typescript-eslint/type-utils': 8.62.1(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/utils': 8.62.1(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.62.1 - eslint: 9.39.4 + eslint: 9.39.4(jiti@2.7.0) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -3676,14 +3850,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.62.1(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/parser@8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.62.1 '@typescript-eslint/types': 8.62.1 '@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.62.1 debug: 4.4.3 - eslint: 9.39.4 + eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -3706,13 +3880,13 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.62.1(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.62.1 '@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.62.1(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/utils': 8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.4 + eslint: 9.39.4(jiti@2.7.0) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -3735,13 +3909,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.62.1(eslint@9.39.4)(typescript@5.9.3)': + '@typescript-eslint/utils@8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) '@typescript-eslint/scope-manager': 8.62.1 '@typescript-eslint/types': 8.62.1 '@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3) - eslint: 9.39.4 + eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -3759,13 +3933,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.6(vite@7.3.6(@types/node@26.1.0)(terser@5.48.0))': + '@vitest/mocker@3.2.6(vite@7.3.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0))': dependencies: '@vitest/spy': 3.2.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.6(@types/node@26.1.0)(terser@5.48.0) + vite: 7.3.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0) '@vitest/pretty-format@3.2.6': dependencies: @@ -4015,6 +4189,21 @@ snapshots: bytes@3.1.2: {} + c12@3.1.0: + dependencies: + chokidar: 4.0.3 + confbox: 0.2.4 + defu: 6.1.7 + dotenv: 16.6.1 + exsolve: 1.1.0 + giget: 2.0.0 + jiti: 2.7.0 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 1.0.0 + pkg-types: 2.3.1 + rc9: 2.1.2 + cac@6.7.14: {} call-bind-apply-helpers@1.0.2: @@ -4054,6 +4243,12 @@ snapshots: chrome-trace-event@1.0.4: {} + citty@0.1.6: + dependencies: + consola: 3.4.2 + + citty@0.2.2: {} + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -4104,6 +4299,8 @@ snapshots: confbox@0.1.8: {} + confbox@0.2.4: {} + consola@3.4.2: {} content-disposition@1.1.0: {} @@ -4148,21 +4345,29 @@ snapshots: deep-is@0.1.4: {} + deepmerge-ts@7.1.5: {} + deepmerge@4.3.1: {} defaults@1.0.4: dependencies: clone: 1.0.4 + defu@6.1.7: {} + delayed-stream@1.0.0: {} depd@2.0.0: {} + destr@2.0.5: {} + dezalgo@1.0.4: dependencies: asap: 2.0.6 wrappy: 1.0.2 + dotenv@16.6.1: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -4171,10 +4376,17 @@ snapshots: ee-first@1.1.1: {} + effect@3.21.0: + dependencies: + '@standard-schema/spec': 1.1.0 + fast-check: 3.23.2 + electron-to-chromium@1.5.385: {} emoji-regex@8.0.0: {} + empathic@2.0.0: {} + encodeurl@2.0.0: {} end-of-stream@1.4.5: @@ -4273,9 +4485,9 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@9.39.4): + eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.7.0)): dependencies: - eslint: 9.39.4 + eslint: 9.39.4(jiti@2.7.0) eslint-scope@5.1.1: dependencies: @@ -4293,9 +4505,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@9.39.4: + eslint@9.39.4(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.2 '@eslint/config-helpers': 0.4.2 @@ -4329,6 +4541,8 @@ snapshots: minimatch: 3.1.5 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 transitivePeerDependencies: - supports-color @@ -4399,6 +4613,12 @@ snapshots: transitivePeerDependencies: - supports-color + exsolve@1.1.0: {} + + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + fast-copy@4.0.3: {} fast-deep-equal@3.1.3: {} @@ -4525,6 +4745,15 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.2 + giget@2.0.0: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.7 + node-fetch-native: 1.6.7 + nypm: 0.6.8 + pathe: 2.0.3 + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 @@ -4612,6 +4841,8 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 + jiti@2.7.0: {} + joycon@3.1.1: {} js-tokens@4.0.0: {} @@ -4775,12 +5006,22 @@ snapshots: dependencies: lodash: 4.18.1 + node-fetch-native@1.6.7: {} + node-releases@2.0.50: {} + nypm@0.6.8: + dependencies: + citty: 0.2.2 + pathe: 2.0.3 + tinyexec: 1.2.4 + object-assign@4.1.1: {} object-inspect@1.13.4: {} + ohash@2.0.11: {} + on-exit-leak-free@2.1.2: {} on-finished@2.4.1: @@ -4854,6 +5095,8 @@ snapshots: pathval@2.0.1: {} + perfect-debounce@1.0.0: {} + picocolors@1.1.1: {} picomatch@4.0.4: {} @@ -4915,13 +5158,21 @@ snapshots: mlly: 1.8.2 pathe: 2.0.3 + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.1.0 + pathe: 2.0.3 + pluralize@8.0.0: {} - postcss-load-config@6.0.1(postcss@8.5.16): + postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.16)(tsx@4.23.0): dependencies: lilconfig: 3.1.3 optionalDependencies: + jiti: 2.7.0 postcss: 8.5.16 + tsx: 4.23.0 postcss@8.5.16: dependencies: @@ -4933,6 +5184,15 @@ snapshots: prettier@3.9.4: {} + prisma@6.19.3(typescript@5.9.3): + dependencies: + '@prisma/config': 6.19.3 + '@prisma/engines': 6.19.3 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - magicast + process-warning@5.0.0: {} proxy-addr@2.0.7: @@ -4947,6 +5207,8 @@ snapshots: punycode@2.3.1: {} + pure-rand@6.1.0: {} + qs@6.15.3: dependencies: es-define-property: 1.0.1 @@ -4963,6 +5225,11 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 + rc9@2.1.2: + dependencies: + defu: 6.1.7 + destr: 2.0.5 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -5257,6 +5524,8 @@ snapshots: tinyexec@0.3.2: {} + tinyexec@1.2.4: {} + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.5) @@ -5299,7 +5568,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(@swc/core@1.15.43)(postcss@8.5.16)(typescript@5.9.3): + tsup@8.5.1(@swc/core@1.15.43)(jiti@2.7.0)(postcss@8.5.16)(tsx@4.23.0)(typescript@5.9.3): dependencies: bundle-require: 5.1.0(esbuild@0.27.7) cac: 6.7.14 @@ -5310,7 +5579,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(postcss@8.5.16) + postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.16)(tsx@4.23.0) resolve-from: 5.0.0 rollup: 4.62.2 source-map: 0.7.6 @@ -5328,6 +5597,12 @@ snapshots: - tsx - yaml + tsx@4.23.0: + dependencies: + esbuild: 0.28.1 + optionalDependencies: + fsevents: 2.3.3 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -5345,13 +5620,13 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.62.1(eslint@9.39.4)(typescript@5.9.3): + typescript-eslint@8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.62.1(@typescript-eslint/parser@8.62.1(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/parser': 8.62.1(eslint@9.39.4)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.62.1(@typescript-eslint/parser@8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.62.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.62.1(eslint@9.39.4)(typescript@5.9.3) - eslint: 9.39.4 + '@typescript-eslint/utils': 8.62.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -5402,13 +5677,13 @@ snapshots: vary@1.1.2: {} - vite-node@3.2.4(@types/node@26.1.0)(terser@5.48.0): + vite-node@3.2.4(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.6(@types/node@26.1.0)(terser@5.48.0) + vite: 7.3.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0) transitivePeerDependencies: - '@types/node' - jiti @@ -5423,7 +5698,7 @@ snapshots: - tsx - yaml - vite@7.3.6(@types/node@26.1.0)(terser@5.48.0): + vite@7.3.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0): dependencies: esbuild: 0.28.1 fdir: 6.5.0(picomatch@4.0.5) @@ -5434,13 +5709,15 @@ snapshots: optionalDependencies: '@types/node': 26.1.0 fsevents: 2.3.3 + jiti: 2.7.0 terser: 5.48.0 + tsx: 4.23.0 - vitest@3.2.6(@types/node@26.1.0)(terser@5.48.0): + vitest@3.2.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.6 - '@vitest/mocker': 3.2.6(vite@7.3.6(@types/node@26.1.0)(terser@5.48.0)) + '@vitest/mocker': 3.2.6(vite@7.3.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0)) '@vitest/pretty-format': 3.2.6 '@vitest/runner': 3.2.6 '@vitest/snapshot': 3.2.6 @@ -5458,8 +5735,8 @@ snapshots: tinyglobby: 0.2.17 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.6(@types/node@26.1.0)(terser@5.48.0) - vite-node: 3.2.4(@types/node@26.1.0)(terser@5.48.0) + vite: 7.3.6(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0) + vite-node: 3.2.4(@types/node@26.1.0)(jiti@2.7.0)(terser@5.48.0)(tsx@4.23.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.1.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index db0ce1e..9bbc86c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,5 +3,8 @@ packages: - packages/* # Postinstall scripts are opt-in with pnpm; esbuild needs its binary install. allowBuilds: + '@prisma/client': true + '@prisma/engines': true '@swc/core': true esbuild: true + prisma: true