diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c45662fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +node_modules/ +.pnpm-store/ + +dist/ +build/ +coverage/ +.next/ +.turbo/ +.vite/ + +.env +.env.* +!.env.example + +.idea/ +*.log +.DS_Store diff --git a/apps/api/.env.example b/apps/api/.env.example new file mode 100644 index 00000000..2f7a5567 --- /dev/null +++ b/apps/api/.env.example @@ -0,0 +1,5 @@ +DATABASE_URL=postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public +REDIS_URL=redis://localhost:6379 +QUEUE_ADAPTER=bullmq +S1_STORAGE_ROOT=.local/storage +HARNESS_CLI_TIMEOUT_MS=5000 diff --git a/apps/api/package.json b/apps/api/package.json new file mode 100644 index 00000000..9c93b83e --- /dev/null +++ b/apps/api/package.json @@ -0,0 +1,33 @@ +{ + "name": "@huijing/api", + "private": true, + "type": "module", + "scripts": { + "lint": "eslint .", + "typecheck": "tsc --noEmit", + "test": "vitest run", + "build": "tsc -p tsconfig.json && node -e \"await import('./dist/main.js')\"", + "dev:smoke": "vitest run", + "prisma": "prisma" + }, + "dependencies": { + "@huijing/harness-client": "workspace:*", + "@nestjs/common": "^11.1.24", + "@nestjs/core": "^11.1.24", + "@nestjs/platform-express": "^11.1.24", + "@prisma/adapter-pg": "7.8.0", + "@prisma/client": "7.8.0", + "bullmq": "^5.77.6", + "ioredis": "^5.11.0", + "pg": "^8.21.0", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.2" + }, + "devDependencies": { + "@nestjs/testing": "^11.1.24", + "@types/node": "^25.9.1", + "@types/pg": "^8.20.0", + "prisma": "^7.8.0", + "vitest": "^4.1.7" + } +} diff --git a/apps/api/prisma.config.ts b/apps/api/prisma.config.ts new file mode 100644 index 00000000..4a2bc544 --- /dev/null +++ b/apps/api/prisma.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "prisma/config"; + +export default defineConfig({ + schema: "prisma/schema.prisma", + migrations: { + path: "prisma/migrations" + }, + datasource: { + url: process.env.DATABASE_URL ?? "postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public" + } +}); diff --git a/apps/api/prisma/migrations/20260601040253_s1_app_foundation/migration.sql b/apps/api/prisma/migrations/20260601040253_s1_app_foundation/migration.sql new file mode 100644 index 00000000..678c1e1c --- /dev/null +++ b/apps/api/prisma/migrations/20260601040253_s1_app_foundation/migration.sql @@ -0,0 +1,493 @@ +-- CreateEnum +CREATE TYPE "UserStatus" AS ENUM ('active', 'disabled'); + +-- CreateEnum +CREATE TYPE "UserRoleName" AS ENUM ('admin', 'operator', 'creator', 'player'); + +-- CreateEnum +CREATE TYPE "ProjectStatus" AS ENUM ('active', 'archived'); + +-- CreateEnum +CREATE TYPE "GameVersionStatus" AS ENUM ('draft', 'candidate', 'active', 'archived', 'failed'); + +-- CreateEnum +CREATE TYPE "AssetStatus" AS ENUM ('uploaded', 'deleted'); + +-- CreateEnum +CREATE TYPE "JobStatus" AS ENUM ('queued', 'running', 'succeeded', 'pending_retry', 'failed', 'canceled'); + +-- CreateEnum +CREATE TYPE "JobTargetType" AS ENUM ('project', 'version'); + +-- CreateEnum +CREATE TYPE "MainCreationAgentSessionStatus" AS ENUM ('routing_internal_tasks', 'completed', 'failed', 'canceled'); + +-- CreateEnum +CREATE TYPE "AgentTaskType" AS ENUM ('requirement_clarifier', 'game_design_draft_generator'); + +-- CreateEnum +CREATE TYPE "AgentTaskStatus" AS ENUM ('queued', 'running', 'succeeded', 'failed', 'canceled', 'timed_out'); + +-- CreateEnum +CREATE TYPE "ReviewRecordStatus" AS ENUM ('pending_review', 'approved', 'rejected', 'canceled'); + +-- CreateEnum +CREATE TYPE "ReviewDecision" AS ENUM ('approved', 'rejected'); + +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "email" TEXT, + "displayName" TEXT NOT NULL, + "status" "UserStatus" NOT NULL DEFAULT 'active', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "UserRole" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "role" "UserRoleName" NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "UserRole_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AnonymousIdentity" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "deviceKey" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AnonymousIdentity_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "GameProject" ( + "id" TEXT NOT NULL, + "ownerId" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "title" TEXT NOT NULL, + "status" "ProjectStatus" NOT NULL DEFAULT 'active', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "GameProject_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "GameVersion" ( + "id" TEXT NOT NULL, + "projectId" TEXT NOT NULL, + "versionNumber" INTEGER NOT NULL, + "status" "GameVersionStatus" NOT NULL, + "configJson" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "GameVersion_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Asset" ( + "id" TEXT NOT NULL, + "projectId" TEXT NOT NULL, + "kind" TEXT NOT NULL, + "storageKey" TEXT NOT NULL, + "mimeType" TEXT NOT NULL, + "byteSize" INTEGER NOT NULL, + "sha256" TEXT NOT NULL, + "status" "AssetStatus" NOT NULL DEFAULT 'uploaded', + "metadataJson" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Asset_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Job" ( + "id" TEXT NOT NULL, + "actorId" TEXT NOT NULL, + "projectId" TEXT NOT NULL, + "type" TEXT NOT NULL, + "idempotencyKey" TEXT NOT NULL, + "status" "JobStatus" NOT NULL DEFAULT 'queued', + "attempts" INTEGER NOT NULL DEFAULT 0, + "maxAttempts" INTEGER NOT NULL DEFAULT 3, + "timeoutAt" TIMESTAMP(3), + "nextRetryAt" TIMESTAMP(3), + "errorCode" TEXT, + "targetType" "JobTargetType" NOT NULL, + "targetId" TEXT NOT NULL, + "targetScopeKey" TEXT NOT NULL, + "gameProjectId" TEXT, + "gameVersionId" TEXT, + "payloadJson" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Job_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AuditLog" ( + "id" TEXT NOT NULL, + "actorId" TEXT NOT NULL, + "action" TEXT NOT NULL, + "targetType" TEXT NOT NULL, + "targetId" TEXT NOT NULL, + "eventJson" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "MainCreationAgentSession" ( + "id" TEXT NOT NULL, + "creatorId" TEXT NOT NULL, + "projectId" TEXT NOT NULL, + "versionId" TEXT NOT NULL, + "status" "MainCreationAgentSessionStatus" NOT NULL, + "contextSummary" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "MainCreationAgentSession_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AgentTask" ( + "id" TEXT NOT NULL, + "sessionId" TEXT NOT NULL, + "taskType" "AgentTaskType" NOT NULL, + "subagentId" TEXT NOT NULL, + "inputRef" TEXT NOT NULL, + "outputRef" TEXT, + "status" "AgentTaskStatus" NOT NULL, + "timeoutAt" TIMESTAMP(3) NOT NULL, + "errorCode" TEXT, + "auditLogId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "AgentTask_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ReviewRecord" ( + "id" TEXT NOT NULL, + "gameVersionId" TEXT NOT NULL, + "status" "ReviewRecordStatus" NOT NULL, + "decision" "ReviewDecision", + "reasonCode" TEXT, + "decidedById" TEXT, + "decidedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "ReviewRecord_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "LifecycleEvent" ( + "eventId" TEXT NOT NULL, + "gameVersionId" TEXT, + "event" TEXT NOT NULL, + "from" TEXT NOT NULL, + "to" TEXT NOT NULL, + "actorJson" JSONB NOT NULL, + "requiredRole" TEXT NOT NULL, + "requiredRecordRefsJson" JSONB NOT NULL, + "auditEvent" TEXT NOT NULL, + "reasonCode" TEXT NOT NULL, + "occurredAt" TIMESTAMP(3) NOT NULL, + "approval" TEXT NOT NULL, + "requiredRecordsJson" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "LifecycleEvent_pkey" PRIMARY KEY ("eventId") +); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE INDEX "UserRole_role_idx" ON "UserRole"("role"); + +-- CreateIndex +CREATE UNIQUE INDEX "UserRole_userId_role_key" ON "UserRole"("userId", "role"); + +-- CreateIndex +CREATE INDEX "AnonymousIdentity_userId_idx" ON "AnonymousIdentity"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "AnonymousIdentity_deviceKey_key" ON "AnonymousIdentity"("deviceKey"); + +-- CreateIndex +CREATE UNIQUE INDEX "GameProject_slug_key" ON "GameProject"("slug"); + +-- CreateIndex +CREATE INDEX "GameProject_ownerId_idx" ON "GameProject"("ownerId"); + +-- CreateIndex +CREATE INDEX "GameVersion_projectId_status_idx" ON "GameVersion"("projectId", "status"); + +-- CreateIndex +CREATE UNIQUE INDEX "GameVersion_projectId_versionNumber_key" ON "GameVersion"("projectId", "versionNumber"); + +-- CreateIndex +CREATE UNIQUE INDEX "GameVersion_id_projectId_key" ON "GameVersion"("id", "projectId"); + +-- CreateIndex +CREATE INDEX "Asset_projectId_kind_idx" ON "Asset"("projectId", "kind"); + +-- CreateIndex +CREATE UNIQUE INDEX "Asset_projectId_storageKey_key" ON "Asset"("projectId", "storageKey"); + +-- CreateIndex +CREATE INDEX "Job_projectId_status_idx" ON "Job"("projectId", "status"); + +-- CreateIndex +CREATE INDEX "Job_actorId_status_idx" ON "Job"("actorId", "status"); + +-- CreateIndex +CREATE INDEX "Job_gameProjectId_idx" ON "Job"("gameProjectId"); + +-- CreateIndex +CREATE INDEX "Job_gameVersionId_idx" ON "Job"("gameVersionId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Job_actorId_projectId_type_targetScopeKey_idempotencyKey_key" ON "Job"("actorId", "projectId", "type", "targetScopeKey", "idempotencyKey"); + +-- CreateIndex +CREATE INDEX "AuditLog_actorId_createdAt_idx" ON "AuditLog"("actorId", "createdAt"); + +-- CreateIndex +CREATE INDEX "AuditLog_targetType_targetId_idx" ON "AuditLog"("targetType", "targetId"); + +-- CreateIndex +CREATE INDEX "MainCreationAgentSession_creatorId_idx" ON "MainCreationAgentSession"("creatorId"); + +-- CreateIndex +CREATE INDEX "MainCreationAgentSession_projectId_idx" ON "MainCreationAgentSession"("projectId"); + +-- CreateIndex +CREATE INDEX "MainCreationAgentSession_versionId_idx" ON "MainCreationAgentSession"("versionId"); + +-- CreateIndex +CREATE INDEX "AgentTask_sessionId_idx" ON "AgentTask"("sessionId"); + +-- CreateIndex +CREATE INDEX "AgentTask_status_idx" ON "AgentTask"("status"); + +-- CreateIndex +CREATE INDEX "ReviewRecord_gameVersionId_status_idx" ON "ReviewRecord"("gameVersionId", "status"); + +-- CreateIndex +CREATE INDEX "ReviewRecord_decidedById_idx" ON "ReviewRecord"("decidedById"); + +-- CreateIndex +CREATE INDEX "LifecycleEvent_gameVersionId_idx" ON "LifecycleEvent"("gameVersionId"); + +-- CreateIndex +CREATE INDEX "LifecycleEvent_event_occurredAt_idx" ON "LifecycleEvent"("event", "occurredAt"); + +-- AddForeignKey +ALTER TABLE "UserRole" ADD CONSTRAINT "UserRole_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AnonymousIdentity" ADD CONSTRAINT "AnonymousIdentity_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "GameProject" ADD CONSTRAINT "GameProject_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "GameVersion" ADD CONSTRAINT "GameVersion_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "GameProject"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Asset" ADD CONSTRAINT "Asset_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "GameProject"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Job" ADD CONSTRAINT "Job_actorId_fkey" FOREIGN KEY ("actorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Job" ADD CONSTRAINT "Job_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "GameProject"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Job" ADD CONSTRAINT "Job_gameProjectId_fkey" FOREIGN KEY ("gameProjectId") REFERENCES "GameProject"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Job" ADD CONSTRAINT "Job_gameVersionId_projectId_fkey" FOREIGN KEY ("gameVersionId", "projectId") REFERENCES "GameVersion"("id", "projectId") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_actorId_fkey" FOREIGN KEY ("actorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MainCreationAgentSession" ADD CONSTRAINT "MainCreationAgentSession_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MainCreationAgentSession" ADD CONSTRAINT "MainCreationAgentSession_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "GameProject"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MainCreationAgentSession" ADD CONSTRAINT "MainCreationAgentSession_versionId_fkey" FOREIGN KEY ("versionId") REFERENCES "GameVersion"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AgentTask" ADD CONSTRAINT "AgentTask_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "MainCreationAgentSession"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ReviewRecord" ADD CONSTRAINT "ReviewRecord_gameVersionId_fkey" FOREIGN KEY ("gameVersionId") REFERENCES "GameVersion"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ReviewRecord" ADD CONSTRAINT "ReviewRecord_decidedById_fkey" FOREIGN KEY ("decidedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "LifecycleEvent" ADD CONSTRAINT "LifecycleEvent_gameVersionId_fkey" FOREIGN KEY ("gameVersionId") REFERENCES "GameVersion"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- Task 4 DB invariants: 用命名 CHECK 锁住 Job 的具体目标、幂等作用域和重试计数。 +ALTER TABLE "Job" ADD CONSTRAINT "Job_target_xor_check" CHECK ( + ( + "targetType" = 'project' + AND "gameProjectId" IS NOT NULL + AND "gameVersionId" IS NULL + ) + OR ( + "targetType" = 'version' + AND "gameVersionId" IS NOT NULL + AND "gameProjectId" IS NULL + ) +); + +ALTER TABLE "Job" ADD CONSTRAINT "Job_target_id_matches_check" CHECK ( + ( + "targetType" = 'project' + AND "targetId" = "gameProjectId" + ) + OR ( + "targetType" = 'version' + AND "targetId" = "gameVersionId" + ) +); + +ALTER TABLE "Job" ADD CONSTRAINT "Job_project_scope_matches_check" CHECK ( + "targetType" <> 'project' + OR "projectId" = "gameProjectId" +); + +ALTER TABLE "Job" ADD CONSTRAINT "Job_target_scope_key_check" CHECK ( + ( + "targetType" = 'project' + AND "targetScopeKey" = ('project:' || "gameProjectId") + ) + OR ( + "targetType" = 'version' + AND "targetScopeKey" = ('version:' || "gameVersionId") + ) +); + +ALTER TABLE "Job" ADD CONSTRAINT "Job_non_empty_idempotency_scope_check" CHECK ( + length(btrim("idempotencyKey")) > 0 + AND length(btrim("targetScopeKey")) > 0 +); + +ALTER TABLE "Job" ADD CONSTRAINT "Job_retry_counts_check" CHECK ( + "attempts" >= 0 + AND "maxAttempts" > 0 + AND "attempts" <= "maxAttempts" +); + +-- AgentTask 只能使用 S0 已确认的 taskType/subagentId 组合。 +ALTER TABLE "AgentTask" ADD CONSTRAINT "AgentTask_task_subagent_allowlist_check" CHECK ( + ( + "taskType" = 'requirement_clarifier' + AND "subagentId" = 'subagent-requirement-clarifier-001' + ) + OR ( + "taskType" = 'game_design_draft_generator' + AND "subagentId" = 'subagent-game-draft-001' + ) +); + +-- ReviewRecord 的人工决策事实必须带 reasonCode,并且 status 与 decision 保持一致。 +ALTER TABLE "ReviewRecord" ADD CONSTRAINT "ReviewRecord_decision_reason_check" CHECK ( + "decision" IS NULL + OR ( + "reasonCode" IS NOT NULL + AND "status"::text = "decision"::text + ) +); + +-- 状态边界由后续 state-transition service 在事务内 SET LOCAL;Task 4 只安装 DB guard。 +CREATE OR REPLACE FUNCTION app_require_state_transition_guard() +RETURNS trigger AS $$ +BEGIN + IF current_setting('app.state_transition_guard', true) IS DISTINCT FROM 'on' THEN + RAISE EXCEPTION 'state transition guard is required' USING ERRCODE = '42501'; + END IF; + + IF TG_OP = 'DELETE' THEN + RETURN OLD; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER "GameVersion_a_guard_status_insert" +BEFORE INSERT ON "GameVersion" +FOR EACH ROW +EXECUTE FUNCTION app_require_state_transition_guard(); + +CREATE TRIGGER "GameVersion_a_guard_status_update" +BEFORE UPDATE OF "status" ON "GameVersion" +FOR EACH ROW +WHEN (OLD."status" IS DISTINCT FROM NEW."status") +EXECUTE FUNCTION app_require_state_transition_guard(); + +CREATE TRIGGER "ReviewRecord_a_guard_status_insert" +BEFORE INSERT ON "ReviewRecord" +FOR EACH ROW +EXECUTE FUNCTION app_require_state_transition_guard(); + +CREATE TRIGGER "ReviewRecord_a_guard_status_update" +BEFORE UPDATE OF "status" ON "ReviewRecord" +FOR EACH ROW +WHEN (OLD."status" IS DISTINCT FROM NEW."status") +EXECUTE FUNCTION app_require_state_transition_guard(); + +CREATE TRIGGER "LifecycleEvent_a_guard_insert" +BEFORE INSERT ON "LifecycleEvent" +FOR EACH ROW +EXECUTE FUNCTION app_require_state_transition_guard(); + +CREATE TRIGGER "LifecycleEvent_a_guard_update" +BEFORE UPDATE ON "LifecycleEvent" +FOR EACH ROW +EXECUTE FUNCTION app_require_state_transition_guard(); + +CREATE TRIGGER "LifecycleEvent_a_guard_delete" +BEFORE DELETE ON "LifecycleEvent" +FOR EACH ROW +EXECUTE FUNCTION app_require_state_transition_guard(); + +-- AuditLog 是 append-only 事实表,任何 UPDATE/DELETE 都在 DB 层拒绝。 +CREATE OR REPLACE FUNCTION app_reject_audit_log_mutation() +RETURNS trigger AS $$ +BEGIN + RAISE EXCEPTION 'AuditLog is append-only' USING ERRCODE = '42501'; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER "AuditLog_reject_update" +BEFORE UPDATE ON "AuditLog" +FOR EACH ROW +EXECUTE FUNCTION app_reject_audit_log_mutation(); + +CREATE TRIGGER "AuditLog_reject_delete" +BEFORE DELETE ON "AuditLog" +FOR EACH ROW +EXECUTE FUNCTION app_reject_audit_log_mutation(); diff --git a/apps/api/prisma/migrations/20260601050132_s1_task4_quality_fixes/migration.sql b/apps/api/prisma/migrations/20260601050132_s1_task4_quality_fixes/migration.sql new file mode 100644 index 00000000..9ef8b185 --- /dev/null +++ b/apps/api/prisma/migrations/20260601050132_s1_task4_quality_fixes/migration.sql @@ -0,0 +1,27 @@ +-- DropForeignKey +ALTER TABLE "MainCreationAgentSession" DROP CONSTRAINT "MainCreationAgentSession_versionId_fkey"; + +-- AddForeignKey +ALTER TABLE "MainCreationAgentSession" ADD CONSTRAINT "MainCreationAgentSession_versionId_projectId_fkey" FOREIGN KEY ("versionId", "projectId") REFERENCES "GameVersion"("id", "projectId") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- ReviewRecord 审核事实必须完整:pending/canceled 不能带决策字段,approved/rejected 必须带完整可审计证据。 +ALTER TABLE "ReviewRecord" DROP CONSTRAINT "ReviewRecord_decision_reason_check"; + +ALTER TABLE "ReviewRecord" ADD CONSTRAINT "ReviewRecord_decision_reason_check" CHECK ( + ( + "status" IN ('pending_review', 'canceled') + AND "decision" IS NULL + AND "reasonCode" IS NULL + AND "decidedById" IS NULL + AND "decidedAt" IS NULL + ) + OR ( + "status" IN ('approved', 'rejected') + AND "decision" IS NOT NULL + AND "decision"::text = "status"::text + AND "reasonCode" IS NOT NULL + AND length(btrim("reasonCode")) > 0 + AND "decidedById" IS NOT NULL + AND "decidedAt" IS NOT NULL + ) +); diff --git a/apps/api/prisma/migrations/20260601165239_s1_task7_job_lease_fields/migration.sql b/apps/api/prisma/migrations/20260601165239_s1_task7_job_lease_fields/migration.sql new file mode 100644 index 00000000..19e4b38a --- /dev/null +++ b/apps/api/prisma/migrations/20260601165239_s1_task7_job_lease_fields/migration.sql @@ -0,0 +1,28 @@ +-- Task 7 Job 执行边界:持久化 lease 和乐观版本号,避免 worker 用内存状态伪装并发语义。 +ALTER TABLE "Job" ADD COLUMN "leaseToken" TEXT; +ALTER TABLE "Job" ADD COLUMN "leasedBy" TEXT; +ALTER TABLE "Job" ADD COLUMN "leaseExpiresAt" TIMESTAMP(3); +ALTER TABLE "Job" ADD COLUMN "lockVersion" INTEGER NOT NULL DEFAULT 0; + +CREATE INDEX "Job_status_nextRetryAt_createdAt_idx" ON "Job"("status", "nextRetryAt", "createdAt"); +CREATE INDEX "Job_leaseToken_idx" ON "Job"("leaseToken"); + +-- running 必须带完整 lease;非 running 状态不得保留可完成的 lease,避免 stale worker 误提交。 +ALTER TABLE "Job" ADD CONSTRAINT "Job_lease_consistency_check" CHECK ( + ( + "status" = 'running' + AND "leaseToken" IS NOT NULL + AND length(btrim("leaseToken")) > 0 + AND "leasedBy" IS NOT NULL + AND length(btrim("leasedBy")) > 0 + AND "leaseExpiresAt" IS NOT NULL + ) + OR ( + "status" <> 'running' + AND "leaseToken" IS NULL + AND "leasedBy" IS NULL + AND "leaseExpiresAt" IS NULL + ) +); + +ALTER TABLE "Job" ADD CONSTRAINT "Job_lock_version_check" CHECK ("lockVersion" >= 0); diff --git a/apps/api/prisma/migrations/migration_lock.toml b/apps/api/prisma/migrations/migration_lock.toml new file mode 100644 index 00000000..044d57cd --- /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 00000000..94cdba71 --- /dev/null +++ b/apps/api/prisma/schema.prisma @@ -0,0 +1,306 @@ +generator client { + provider = "prisma-client" + output = "../src/generated/prisma" +} + +datasource db { + provider = "postgresql" +} + +enum UserStatus { + active + disabled +} + +enum UserRoleName { + admin + operator + creator + player +} + +enum ProjectStatus { + active + archived +} + +enum GameVersionStatus { + draft + candidate + active + archived + failed +} + +enum AssetStatus { + uploaded + deleted +} + +enum JobStatus { + queued + running + succeeded + pending_retry + failed + canceled +} + +enum JobTargetType { + project + version +} + +enum MainCreationAgentSessionStatus { + routing_internal_tasks + completed + failed + canceled +} + +enum AgentTaskType { + requirement_clarifier + game_design_draft_generator +} + +enum AgentTaskStatus { + queued + running + succeeded + failed + canceled + timed_out +} + +enum ReviewRecordStatus { + pending_review + approved + rejected + canceled +} + +enum ReviewDecision { + approved + rejected +} + +model User { + id String @id + email String? @unique + displayName String + status UserStatus @default(active) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + roles UserRole[] + anonymousIdentities AnonymousIdentity[] + gameProjects GameProject[] + auditLogs AuditLog[] @relation("AuditActor") + jobs Job[] @relation("JobActor") + mainCreationAgentSessions MainCreationAgentSession[] + reviewDecisions ReviewRecord[] @relation("ReviewDecider") +} + +model UserRole { + id String @id @default(cuid()) + userId String + role UserRoleName + createdAt DateTime @default(now()) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([userId, role]) + @@index([role]) +} + +model AnonymousIdentity { + id String @id + userId String + deviceKey String + createdAt DateTime @default(now()) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([deviceKey]) + @@index([userId]) +} + +model GameProject { + id String @id + ownerId String + slug String @unique + title String + status ProjectStatus @default(active) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + owner User @relation(fields: [ownerId], references: [id], onDelete: Restrict) + versions GameVersion[] + assets Asset[] + jobs Job[] @relation("JobProjectScope") + projectTargetJobs Job[] @relation("JobGameProjectTarget") + mainCreationAgentSessionScopes MainCreationAgentSession[] @relation("MainCreationAgentSessionProjectScope") + + @@index([ownerId]) +} + +model GameVersion { + id String @id + projectId String + versionNumber Int + status GameVersionStatus + configJson Json + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + project GameProject @relation(fields: [projectId], references: [id], onDelete: Cascade) + versionTargetJobs Job[] @relation("JobGameVersionTarget") + mainCreationAgentSessionScopes MainCreationAgentSession[] @relation("MainCreationAgentSessionVersionScope") + reviewRecords ReviewRecord[] + lifecycleEvents LifecycleEvent[] + + @@unique([projectId, versionNumber]) + @@unique([id, projectId]) + @@index([projectId, status]) +} + +model Asset { + id String @id + projectId String + kind String + storageKey String + mimeType String + byteSize Int + sha256 String + status AssetStatus @default(uploaded) + metadataJson Json? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + project GameProject @relation(fields: [projectId], references: [id], onDelete: Cascade) + + @@unique([projectId, storageKey]) + @@index([projectId, kind]) +} + +model Job { + id String @id + actorId String + projectId String + type String + idempotencyKey String + status JobStatus @default(queued) + attempts Int @default(0) + maxAttempts Int @default(3) + timeoutAt DateTime? + nextRetryAt DateTime? + errorCode String? + leaseToken String? + leasedBy String? + leaseExpiresAt DateTime? + lockVersion Int @default(0) + targetType JobTargetType + targetId String + targetScopeKey String + gameProjectId String? + gameVersionId String? + payloadJson Json + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + actor User @relation("JobActor", fields: [actorId], references: [id], onDelete: Restrict) + project GameProject @relation("JobProjectScope", fields: [projectId], references: [id], onDelete: Cascade) + gameProject GameProject? @relation("JobGameProjectTarget", fields: [gameProjectId], references: [id], onDelete: Restrict) + gameVersion GameVersion? @relation("JobGameVersionTarget", fields: [gameVersionId, projectId], references: [id, projectId], onDelete: Restrict) + + @@unique([actorId, projectId, type, targetScopeKey, idempotencyKey]) + @@index([projectId, status]) + @@index([actorId, status]) + @@index([status, nextRetryAt, createdAt]) + @@index([leaseToken]) + @@index([gameProjectId]) + @@index([gameVersionId]) +} + +model AuditLog { + id String @id + actorId String + action String + targetType String + targetId String + eventJson Json + createdAt DateTime @default(now()) + actor User @relation("AuditActor", fields: [actorId], references: [id], onDelete: Restrict) + + @@index([actorId, createdAt]) + @@index([targetType, targetId]) +} + +model MainCreationAgentSession { + id String @id + creatorId String + projectId String + versionId String + status MainCreationAgentSessionStatus + contextSummary String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + creator User @relation(fields: [creatorId], references: [id], onDelete: Restrict) + project GameProject @relation("MainCreationAgentSessionProjectScope", fields: [projectId], references: [id], onDelete: Cascade) + version GameVersion @relation("MainCreationAgentSessionVersionScope", fields: [versionId, projectId], references: [id, projectId], onDelete: Restrict) + tasks AgentTask[] + + @@index([creatorId]) + @@index([projectId]) + @@index([versionId]) +} + +model AgentTask { + id String @id + sessionId String + taskType AgentTaskType + subagentId String + inputRef String + outputRef String? + status AgentTaskStatus + timeoutAt DateTime + errorCode String? + auditLogId String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + session MainCreationAgentSession @relation(fields: [sessionId], references: [id], onDelete: Cascade) + + @@index([sessionId]) + @@index([status]) +} + +model ReviewRecord { + id String @id + gameVersionId String + status ReviewRecordStatus + decision ReviewDecision? + reasonCode String? + decidedById String? + decidedAt DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + gameVersion GameVersion @relation(fields: [gameVersionId], references: [id], onDelete: Cascade) + decidedBy User? @relation("ReviewDecider", fields: [decidedById], references: [id], onDelete: Restrict) + + @@index([gameVersionId, status]) + @@index([decidedById]) +} + +model LifecycleEvent { + eventId String @id + gameVersionId String? + event String + from String + to String + actorJson Json + requiredRole String + requiredRecordRefsJson Json + auditEvent String + reasonCode String + occurredAt DateTime + approval String + requiredRecordsJson Json + createdAt DateTime @default(now()) + gameVersion GameVersion? @relation(fields: [gameVersionId], references: [id], onDelete: SetNull) + + @@index([gameVersionId]) + @@index([event, occurredAt]) +} diff --git a/apps/api/src/app.module.ts b/apps/api/src/app.module.ts new file mode 100644 index 00000000..480a4929 --- /dev/null +++ b/apps/api/src/app.module.ts @@ -0,0 +1,13 @@ +import { Module } from "@nestjs/common"; +import { HealthController } from "./health.controller.js"; +import { AuditModule } from "./modules/audit/index.js"; +import { AssetsModule } from "./modules/assets/index.js"; +import { AuthModule } from "./modules/auth/index.js"; +import { JobsApiModule } from "./modules/jobs/index.js"; +import { ProjectsModule } from "./modules/projects/index.js"; + +@Module({ + imports: [AuthModule, ProjectsModule, AssetsModule, JobsApiModule, AuditModule], + controllers: [HealthController] +}) +export class AppModule {} diff --git a/apps/api/src/generated/prisma/browser.ts b/apps/api/src/generated/prisma/browser.ts new file mode 100644 index 00000000..e4f50006 --- /dev/null +++ b/apps/api/src/generated/prisma/browser.ts @@ -0,0 +1,79 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file should be your main import to use Prisma-related types and utilities in a browser. + * Use it to get access to models, enums, and input types. + * + * This file does not contain a `PrismaClient` class, nor several other helpers that are intended as server-side only. + * See `client.ts` for the standard, server-side entry point. + * + * 🟢 You can import this file directly. + */ + +import * as Prisma from './internal/prismaNamespaceBrowser.js' +export { Prisma } +export * as $Enums from './enums.js' +export * from './enums.js'; +/** + * Model User + * + */ +export type User = Prisma.UserModel +/** + * Model UserRole + * + */ +export type UserRole = Prisma.UserRoleModel +/** + * Model AnonymousIdentity + * + */ +export type AnonymousIdentity = Prisma.AnonymousIdentityModel +/** + * Model GameProject + * + */ +export type GameProject = Prisma.GameProjectModel +/** + * Model GameVersion + * + */ +export type GameVersion = Prisma.GameVersionModel +/** + * Model Asset + * + */ +export type Asset = Prisma.AssetModel +/** + * Model Job + * + */ +export type Job = Prisma.JobModel +/** + * Model AuditLog + * + */ +export type AuditLog = Prisma.AuditLogModel +/** + * Model MainCreationAgentSession + * + */ +export type MainCreationAgentSession = Prisma.MainCreationAgentSessionModel +/** + * Model AgentTask + * + */ +export type AgentTask = Prisma.AgentTaskModel +/** + * Model ReviewRecord + * + */ +export type ReviewRecord = Prisma.ReviewRecordModel +/** + * Model LifecycleEvent + * + */ +export type LifecycleEvent = Prisma.LifecycleEventModel diff --git a/apps/api/src/generated/prisma/client.ts b/apps/api/src/generated/prisma/client.ts new file mode 100644 index 00000000..913b5830 --- /dev/null +++ b/apps/api/src/generated/prisma/client.ts @@ -0,0 +1,103 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file should be your main import to use Prisma. Through it you get access to all the models, enums, and input types. + * If you're looking for something you can import in the client-side of your application, please refer to the `browser.ts` file instead. + * + * 🟢 You can import this file directly. + */ + +import * as process from 'node:process' +import * as path from 'node:path' +import { fileURLToPath } from 'node:url' +globalThis['__dirname'] = path.dirname(fileURLToPath(import.meta.url)) + +import * as runtime from "@prisma/client/runtime/client" +import * as $Enums from "./enums.js" +import * as $Class from "./internal/class.js" +import * as Prisma from "./internal/prismaNamespace.js" + +export * as $Enums from './enums.js' +export * from "./enums.js" +/** + * ## Prisma Client + * + * Type-safe database client for TypeScript + * @example + * ``` + * const prisma = new PrismaClient({ + * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) + * }) + * // Fetch zero or more Users + * const users = await prisma.user.findMany() + * ``` + * + * Read more in our [docs](https://pris.ly/d/client). + */ +export const PrismaClient = $Class.getPrismaClientClass() +export type PrismaClient = $Class.PrismaClient +export { Prisma } + +/** + * Model User + * + */ +export type User = Prisma.UserModel +/** + * Model UserRole + * + */ +export type UserRole = Prisma.UserRoleModel +/** + * Model AnonymousIdentity + * + */ +export type AnonymousIdentity = Prisma.AnonymousIdentityModel +/** + * Model GameProject + * + */ +export type GameProject = Prisma.GameProjectModel +/** + * Model GameVersion + * + */ +export type GameVersion = Prisma.GameVersionModel +/** + * Model Asset + * + */ +export type Asset = Prisma.AssetModel +/** + * Model Job + * + */ +export type Job = Prisma.JobModel +/** + * Model AuditLog + * + */ +export type AuditLog = Prisma.AuditLogModel +/** + * Model MainCreationAgentSession + * + */ +export type MainCreationAgentSession = Prisma.MainCreationAgentSessionModel +/** + * Model AgentTask + * + */ +export type AgentTask = Prisma.AgentTaskModel +/** + * Model ReviewRecord + * + */ +export type ReviewRecord = Prisma.ReviewRecordModel +/** + * Model LifecycleEvent + * + */ +export type LifecycleEvent = Prisma.LifecycleEventModel diff --git a/apps/api/src/generated/prisma/commonInputTypes.ts b/apps/api/src/generated/prisma/commonInputTypes.ts new file mode 100644 index 00000000..9efeeddd --- /dev/null +++ b/apps/api/src/generated/prisma/commonInputTypes.ts @@ -0,0 +1,884 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports various common sort, input & filter types that are not directly linked to a particular model. + * + * 🟢 You can import this file directly. + */ + +import type * as runtime from "@prisma/client/runtime/client" +import * as $Enums from "./enums.js" +import type * as Prisma from "./internal/prismaNamespace.js" + + +export type StringFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + mode?: Prisma.QueryMode + not?: Prisma.NestedStringFilter<$PrismaModel> | string +} + +export type StringNullableFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + mode?: Prisma.QueryMode + not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null +} + +export type EnumUserStatusFilter<$PrismaModel = never> = { + equals?: $Enums.UserStatus | Prisma.EnumUserStatusFieldRefInput<$PrismaModel> + in?: $Enums.UserStatus[] | Prisma.ListEnumUserStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.UserStatus[] | Prisma.ListEnumUserStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumUserStatusFilter<$PrismaModel> | $Enums.UserStatus +} + +export type DateTimeFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeFilter<$PrismaModel> | Date | string +} + +export type SortOrderInput = { + sort: Prisma.SortOrder + nulls?: Prisma.NullsOrder +} + +export type StringWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + mode?: Prisma.QueryMode + not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedStringFilter<$PrismaModel> + _max?: Prisma.NestedStringFilter<$PrismaModel> +} + +export type StringNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + mode?: Prisma.QueryMode + not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedStringNullableFilter<$PrismaModel> + _max?: Prisma.NestedStringNullableFilter<$PrismaModel> +} + +export type EnumUserStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.UserStatus | Prisma.EnumUserStatusFieldRefInput<$PrismaModel> + in?: $Enums.UserStatus[] | Prisma.ListEnumUserStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.UserStatus[] | Prisma.ListEnumUserStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumUserStatusWithAggregatesFilter<$PrismaModel> | $Enums.UserStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumUserStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumUserStatusFilter<$PrismaModel> +} + +export type DateTimeWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedDateTimeFilter<$PrismaModel> + _max?: Prisma.NestedDateTimeFilter<$PrismaModel> +} + +export type EnumUserRoleNameFilter<$PrismaModel = never> = { + equals?: $Enums.UserRoleName | Prisma.EnumUserRoleNameFieldRefInput<$PrismaModel> + in?: $Enums.UserRoleName[] | Prisma.ListEnumUserRoleNameFieldRefInput<$PrismaModel> + notIn?: $Enums.UserRoleName[] | Prisma.ListEnumUserRoleNameFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumUserRoleNameFilter<$PrismaModel> | $Enums.UserRoleName +} + +export type EnumUserRoleNameWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.UserRoleName | Prisma.EnumUserRoleNameFieldRefInput<$PrismaModel> + in?: $Enums.UserRoleName[] | Prisma.ListEnumUserRoleNameFieldRefInput<$PrismaModel> + notIn?: $Enums.UserRoleName[] | Prisma.ListEnumUserRoleNameFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumUserRoleNameWithAggregatesFilter<$PrismaModel> | $Enums.UserRoleName + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumUserRoleNameFilter<$PrismaModel> + _max?: Prisma.NestedEnumUserRoleNameFilter<$PrismaModel> +} + +export type EnumProjectStatusFilter<$PrismaModel = never> = { + equals?: $Enums.ProjectStatus | Prisma.EnumProjectStatusFieldRefInput<$PrismaModel> + in?: $Enums.ProjectStatus[] | Prisma.ListEnumProjectStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.ProjectStatus[] | Prisma.ListEnumProjectStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumProjectStatusFilter<$PrismaModel> | $Enums.ProjectStatus +} + +export type EnumProjectStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.ProjectStatus | Prisma.EnumProjectStatusFieldRefInput<$PrismaModel> + in?: $Enums.ProjectStatus[] | Prisma.ListEnumProjectStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.ProjectStatus[] | Prisma.ListEnumProjectStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumProjectStatusWithAggregatesFilter<$PrismaModel> | $Enums.ProjectStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumProjectStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumProjectStatusFilter<$PrismaModel> +} + +export type IntFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntFilter<$PrismaModel> | number +} + +export type EnumGameVersionStatusFilter<$PrismaModel = never> = { + equals?: $Enums.GameVersionStatus | Prisma.EnumGameVersionStatusFieldRefInput<$PrismaModel> + in?: $Enums.GameVersionStatus[] | Prisma.ListEnumGameVersionStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.GameVersionStatus[] | Prisma.ListEnumGameVersionStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumGameVersionStatusFilter<$PrismaModel> | $Enums.GameVersionStatus +} + +export type JsonFilter<$PrismaModel = never> = +| Prisma.PatchUndefined< + Prisma.Either>, Exclude>, 'path'>>, + Required> + > +| Prisma.OptionalFlat>, 'path'>> + +export type JsonFilterBase<$PrismaModel = never> = { + equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter + path?: string[] + mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel> + string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + lt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + lte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter +} + +export type IntWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntWithAggregatesFilter<$PrismaModel> | number + _count?: Prisma.NestedIntFilter<$PrismaModel> + _avg?: Prisma.NestedFloatFilter<$PrismaModel> + _sum?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedIntFilter<$PrismaModel> + _max?: Prisma.NestedIntFilter<$PrismaModel> +} + +export type EnumGameVersionStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.GameVersionStatus | Prisma.EnumGameVersionStatusFieldRefInput<$PrismaModel> + in?: $Enums.GameVersionStatus[] | Prisma.ListEnumGameVersionStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.GameVersionStatus[] | Prisma.ListEnumGameVersionStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumGameVersionStatusWithAggregatesFilter<$PrismaModel> | $Enums.GameVersionStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumGameVersionStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumGameVersionStatusFilter<$PrismaModel> +} + +export type JsonWithAggregatesFilter<$PrismaModel = never> = +| Prisma.PatchUndefined< + Prisma.Either>, Exclude>, 'path'>>, + Required> + > +| Prisma.OptionalFlat>, 'path'>> + +export type JsonWithAggregatesFilterBase<$PrismaModel = never> = { + equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter + path?: string[] + mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel> + string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + lt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + lte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedJsonFilter<$PrismaModel> + _max?: Prisma.NestedJsonFilter<$PrismaModel> +} + +export type EnumAssetStatusFilter<$PrismaModel = never> = { + equals?: $Enums.AssetStatus | Prisma.EnumAssetStatusFieldRefInput<$PrismaModel> + in?: $Enums.AssetStatus[] | Prisma.ListEnumAssetStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.AssetStatus[] | Prisma.ListEnumAssetStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAssetStatusFilter<$PrismaModel> | $Enums.AssetStatus +} + +export type JsonNullableFilter<$PrismaModel = never> = +| Prisma.PatchUndefined< + Prisma.Either>, Exclude>, 'path'>>, + Required> + > +| Prisma.OptionalFlat>, 'path'>> + +export type JsonNullableFilterBase<$PrismaModel = never> = { + equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter + path?: string[] + mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel> + string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + lt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + lte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter +} + +export type EnumAssetStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.AssetStatus | Prisma.EnumAssetStatusFieldRefInput<$PrismaModel> + in?: $Enums.AssetStatus[] | Prisma.ListEnumAssetStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.AssetStatus[] | Prisma.ListEnumAssetStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAssetStatusWithAggregatesFilter<$PrismaModel> | $Enums.AssetStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumAssetStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumAssetStatusFilter<$PrismaModel> +} + +export type JsonNullableWithAggregatesFilter<$PrismaModel = never> = +| Prisma.PatchUndefined< + Prisma.Either>, Exclude>, 'path'>>, + Required> + > +| Prisma.OptionalFlat>, 'path'>> + +export type JsonNullableWithAggregatesFilterBase<$PrismaModel = never> = { + equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter + path?: string[] + mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel> + string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + lt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + lte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedJsonNullableFilter<$PrismaModel> + _max?: Prisma.NestedJsonNullableFilter<$PrismaModel> +} + +export type EnumJobStatusFilter<$PrismaModel = never> = { + equals?: $Enums.JobStatus | Prisma.EnumJobStatusFieldRefInput<$PrismaModel> + in?: $Enums.JobStatus[] | Prisma.ListEnumJobStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.JobStatus[] | Prisma.ListEnumJobStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumJobStatusFilter<$PrismaModel> | $Enums.JobStatus +} + +export type DateTimeNullableFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null +} + +export type EnumJobTargetTypeFilter<$PrismaModel = never> = { + equals?: $Enums.JobTargetType | Prisma.EnumJobTargetTypeFieldRefInput<$PrismaModel> + in?: $Enums.JobTargetType[] | Prisma.ListEnumJobTargetTypeFieldRefInput<$PrismaModel> + notIn?: $Enums.JobTargetType[] | Prisma.ListEnumJobTargetTypeFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumJobTargetTypeFilter<$PrismaModel> | $Enums.JobTargetType +} + +export type EnumJobStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.JobStatus | Prisma.EnumJobStatusFieldRefInput<$PrismaModel> + in?: $Enums.JobStatus[] | Prisma.ListEnumJobStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.JobStatus[] | Prisma.ListEnumJobStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumJobStatusWithAggregatesFilter<$PrismaModel> | $Enums.JobStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumJobStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumJobStatusFilter<$PrismaModel> +} + +export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> + _max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> +} + +export type EnumJobTargetTypeWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.JobTargetType | Prisma.EnumJobTargetTypeFieldRefInput<$PrismaModel> + in?: $Enums.JobTargetType[] | Prisma.ListEnumJobTargetTypeFieldRefInput<$PrismaModel> + notIn?: $Enums.JobTargetType[] | Prisma.ListEnumJobTargetTypeFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumJobTargetTypeWithAggregatesFilter<$PrismaModel> | $Enums.JobTargetType + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumJobTargetTypeFilter<$PrismaModel> + _max?: Prisma.NestedEnumJobTargetTypeFilter<$PrismaModel> +} + +export type EnumMainCreationAgentSessionStatusFilter<$PrismaModel = never> = { + equals?: $Enums.MainCreationAgentSessionStatus | Prisma.EnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + in?: $Enums.MainCreationAgentSessionStatus[] | Prisma.ListEnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.MainCreationAgentSessionStatus[] | Prisma.ListEnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumMainCreationAgentSessionStatusFilter<$PrismaModel> | $Enums.MainCreationAgentSessionStatus +} + +export type EnumMainCreationAgentSessionStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.MainCreationAgentSessionStatus | Prisma.EnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + in?: $Enums.MainCreationAgentSessionStatus[] | Prisma.ListEnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.MainCreationAgentSessionStatus[] | Prisma.ListEnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumMainCreationAgentSessionStatusWithAggregatesFilter<$PrismaModel> | $Enums.MainCreationAgentSessionStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumMainCreationAgentSessionStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumMainCreationAgentSessionStatusFilter<$PrismaModel> +} + +export type EnumAgentTaskTypeFilter<$PrismaModel = never> = { + equals?: $Enums.AgentTaskType | Prisma.EnumAgentTaskTypeFieldRefInput<$PrismaModel> + in?: $Enums.AgentTaskType[] | Prisma.ListEnumAgentTaskTypeFieldRefInput<$PrismaModel> + notIn?: $Enums.AgentTaskType[] | Prisma.ListEnumAgentTaskTypeFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAgentTaskTypeFilter<$PrismaModel> | $Enums.AgentTaskType +} + +export type EnumAgentTaskStatusFilter<$PrismaModel = never> = { + equals?: $Enums.AgentTaskStatus | Prisma.EnumAgentTaskStatusFieldRefInput<$PrismaModel> + in?: $Enums.AgentTaskStatus[] | Prisma.ListEnumAgentTaskStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.AgentTaskStatus[] | Prisma.ListEnumAgentTaskStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAgentTaskStatusFilter<$PrismaModel> | $Enums.AgentTaskStatus +} + +export type EnumAgentTaskTypeWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.AgentTaskType | Prisma.EnumAgentTaskTypeFieldRefInput<$PrismaModel> + in?: $Enums.AgentTaskType[] | Prisma.ListEnumAgentTaskTypeFieldRefInput<$PrismaModel> + notIn?: $Enums.AgentTaskType[] | Prisma.ListEnumAgentTaskTypeFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAgentTaskTypeWithAggregatesFilter<$PrismaModel> | $Enums.AgentTaskType + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumAgentTaskTypeFilter<$PrismaModel> + _max?: Prisma.NestedEnumAgentTaskTypeFilter<$PrismaModel> +} + +export type EnumAgentTaskStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.AgentTaskStatus | Prisma.EnumAgentTaskStatusFieldRefInput<$PrismaModel> + in?: $Enums.AgentTaskStatus[] | Prisma.ListEnumAgentTaskStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.AgentTaskStatus[] | Prisma.ListEnumAgentTaskStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAgentTaskStatusWithAggregatesFilter<$PrismaModel> | $Enums.AgentTaskStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumAgentTaskStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumAgentTaskStatusFilter<$PrismaModel> +} + +export type EnumReviewRecordStatusFilter<$PrismaModel = never> = { + equals?: $Enums.ReviewRecordStatus | Prisma.EnumReviewRecordStatusFieldRefInput<$PrismaModel> + in?: $Enums.ReviewRecordStatus[] | Prisma.ListEnumReviewRecordStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.ReviewRecordStatus[] | Prisma.ListEnumReviewRecordStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumReviewRecordStatusFilter<$PrismaModel> | $Enums.ReviewRecordStatus +} + +export type EnumReviewDecisionNullableFilter<$PrismaModel = never> = { + equals?: $Enums.ReviewDecision | Prisma.EnumReviewDecisionFieldRefInput<$PrismaModel> | null + in?: $Enums.ReviewDecision[] | Prisma.ListEnumReviewDecisionFieldRefInput<$PrismaModel> | null + notIn?: $Enums.ReviewDecision[] | Prisma.ListEnumReviewDecisionFieldRefInput<$PrismaModel> | null + not?: Prisma.NestedEnumReviewDecisionNullableFilter<$PrismaModel> | $Enums.ReviewDecision | null +} + +export type EnumReviewRecordStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.ReviewRecordStatus | Prisma.EnumReviewRecordStatusFieldRefInput<$PrismaModel> + in?: $Enums.ReviewRecordStatus[] | Prisma.ListEnumReviewRecordStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.ReviewRecordStatus[] | Prisma.ListEnumReviewRecordStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumReviewRecordStatusWithAggregatesFilter<$PrismaModel> | $Enums.ReviewRecordStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumReviewRecordStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumReviewRecordStatusFilter<$PrismaModel> +} + +export type EnumReviewDecisionNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.ReviewDecision | Prisma.EnumReviewDecisionFieldRefInput<$PrismaModel> | null + in?: $Enums.ReviewDecision[] | Prisma.ListEnumReviewDecisionFieldRefInput<$PrismaModel> | null + notIn?: $Enums.ReviewDecision[] | Prisma.ListEnumReviewDecisionFieldRefInput<$PrismaModel> | null + not?: Prisma.NestedEnumReviewDecisionNullableWithAggregatesFilter<$PrismaModel> | $Enums.ReviewDecision | null + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedEnumReviewDecisionNullableFilter<$PrismaModel> + _max?: Prisma.NestedEnumReviewDecisionNullableFilter<$PrismaModel> +} + +export type NestedStringFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + not?: Prisma.NestedStringFilter<$PrismaModel> | string +} + +export type NestedStringNullableFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null +} + +export type NestedEnumUserStatusFilter<$PrismaModel = never> = { + equals?: $Enums.UserStatus | Prisma.EnumUserStatusFieldRefInput<$PrismaModel> + in?: $Enums.UserStatus[] | Prisma.ListEnumUserStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.UserStatus[] | Prisma.ListEnumUserStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumUserStatusFilter<$PrismaModel> | $Enums.UserStatus +} + +export type NestedDateTimeFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeFilter<$PrismaModel> | Date | string +} + +export type NestedStringWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedStringFilter<$PrismaModel> + _max?: Prisma.NestedStringFilter<$PrismaModel> +} + +export type NestedIntFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntFilter<$PrismaModel> | number +} + +export type NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedStringNullableFilter<$PrismaModel> + _max?: Prisma.NestedStringNullableFilter<$PrismaModel> +} + +export type NestedIntNullableFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null +} + +export type NestedEnumUserStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.UserStatus | Prisma.EnumUserStatusFieldRefInput<$PrismaModel> + in?: $Enums.UserStatus[] | Prisma.ListEnumUserStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.UserStatus[] | Prisma.ListEnumUserStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumUserStatusWithAggregatesFilter<$PrismaModel> | $Enums.UserStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumUserStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumUserStatusFilter<$PrismaModel> +} + +export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedDateTimeFilter<$PrismaModel> + _max?: Prisma.NestedDateTimeFilter<$PrismaModel> +} + +export type NestedEnumUserRoleNameFilter<$PrismaModel = never> = { + equals?: $Enums.UserRoleName | Prisma.EnumUserRoleNameFieldRefInput<$PrismaModel> + in?: $Enums.UserRoleName[] | Prisma.ListEnumUserRoleNameFieldRefInput<$PrismaModel> + notIn?: $Enums.UserRoleName[] | Prisma.ListEnumUserRoleNameFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumUserRoleNameFilter<$PrismaModel> | $Enums.UserRoleName +} + +export type NestedEnumUserRoleNameWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.UserRoleName | Prisma.EnumUserRoleNameFieldRefInput<$PrismaModel> + in?: $Enums.UserRoleName[] | Prisma.ListEnumUserRoleNameFieldRefInput<$PrismaModel> + notIn?: $Enums.UserRoleName[] | Prisma.ListEnumUserRoleNameFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumUserRoleNameWithAggregatesFilter<$PrismaModel> | $Enums.UserRoleName + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumUserRoleNameFilter<$PrismaModel> + _max?: Prisma.NestedEnumUserRoleNameFilter<$PrismaModel> +} + +export type NestedEnumProjectStatusFilter<$PrismaModel = never> = { + equals?: $Enums.ProjectStatus | Prisma.EnumProjectStatusFieldRefInput<$PrismaModel> + in?: $Enums.ProjectStatus[] | Prisma.ListEnumProjectStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.ProjectStatus[] | Prisma.ListEnumProjectStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumProjectStatusFilter<$PrismaModel> | $Enums.ProjectStatus +} + +export type NestedEnumProjectStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.ProjectStatus | Prisma.EnumProjectStatusFieldRefInput<$PrismaModel> + in?: $Enums.ProjectStatus[] | Prisma.ListEnumProjectStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.ProjectStatus[] | Prisma.ListEnumProjectStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumProjectStatusWithAggregatesFilter<$PrismaModel> | $Enums.ProjectStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumProjectStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumProjectStatusFilter<$PrismaModel> +} + +export type NestedEnumGameVersionStatusFilter<$PrismaModel = never> = { + equals?: $Enums.GameVersionStatus | Prisma.EnumGameVersionStatusFieldRefInput<$PrismaModel> + in?: $Enums.GameVersionStatus[] | Prisma.ListEnumGameVersionStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.GameVersionStatus[] | Prisma.ListEnumGameVersionStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumGameVersionStatusFilter<$PrismaModel> | $Enums.GameVersionStatus +} + +export type NestedIntWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntWithAggregatesFilter<$PrismaModel> | number + _count?: Prisma.NestedIntFilter<$PrismaModel> + _avg?: Prisma.NestedFloatFilter<$PrismaModel> + _sum?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedIntFilter<$PrismaModel> + _max?: Prisma.NestedIntFilter<$PrismaModel> +} + +export type NestedFloatFilter<$PrismaModel = never> = { + equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> + lt?: number | Prisma.FloatFieldRefInput<$PrismaModel> + lte?: number | Prisma.FloatFieldRefInput<$PrismaModel> + gt?: number | Prisma.FloatFieldRefInput<$PrismaModel> + gte?: number | Prisma.FloatFieldRefInput<$PrismaModel> + not?: Prisma.NestedFloatFilter<$PrismaModel> | number +} + +export type NestedEnumGameVersionStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.GameVersionStatus | Prisma.EnumGameVersionStatusFieldRefInput<$PrismaModel> + in?: $Enums.GameVersionStatus[] | Prisma.ListEnumGameVersionStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.GameVersionStatus[] | Prisma.ListEnumGameVersionStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumGameVersionStatusWithAggregatesFilter<$PrismaModel> | $Enums.GameVersionStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumGameVersionStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumGameVersionStatusFilter<$PrismaModel> +} + +export type NestedJsonFilter<$PrismaModel = never> = +| Prisma.PatchUndefined< + Prisma.Either>, Exclude>, 'path'>>, + Required> + > +| Prisma.OptionalFlat>, 'path'>> + +export type NestedJsonFilterBase<$PrismaModel = never> = { + equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter + path?: string[] + mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel> + string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + lt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + lte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter +} + +export type NestedEnumAssetStatusFilter<$PrismaModel = never> = { + equals?: $Enums.AssetStatus | Prisma.EnumAssetStatusFieldRefInput<$PrismaModel> + in?: $Enums.AssetStatus[] | Prisma.ListEnumAssetStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.AssetStatus[] | Prisma.ListEnumAssetStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAssetStatusFilter<$PrismaModel> | $Enums.AssetStatus +} + +export type NestedEnumAssetStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.AssetStatus | Prisma.EnumAssetStatusFieldRefInput<$PrismaModel> + in?: $Enums.AssetStatus[] | Prisma.ListEnumAssetStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.AssetStatus[] | Prisma.ListEnumAssetStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAssetStatusWithAggregatesFilter<$PrismaModel> | $Enums.AssetStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumAssetStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumAssetStatusFilter<$PrismaModel> +} + +export type NestedJsonNullableFilter<$PrismaModel = never> = +| Prisma.PatchUndefined< + Prisma.Either>, Exclude>, 'path'>>, + Required> + > +| Prisma.OptionalFlat>, 'path'>> + +export type NestedJsonNullableFilterBase<$PrismaModel = never> = { + equals?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter + path?: string[] + mode?: Prisma.QueryMode | Prisma.EnumQueryModeFieldRefInput<$PrismaModel> + string_contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_starts_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + string_ends_with?: string | Prisma.StringFieldRefInput<$PrismaModel> + array_starts_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_ends_with?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + array_contains?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | null + lt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + lte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gt?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + gte?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> + not?: runtime.InputJsonValue | Prisma.JsonFieldRefInput<$PrismaModel> | Prisma.JsonNullValueFilter +} + +export type NestedEnumJobStatusFilter<$PrismaModel = never> = { + equals?: $Enums.JobStatus | Prisma.EnumJobStatusFieldRefInput<$PrismaModel> + in?: $Enums.JobStatus[] | Prisma.ListEnumJobStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.JobStatus[] | Prisma.ListEnumJobStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumJobStatusFilter<$PrismaModel> | $Enums.JobStatus +} + +export type NestedDateTimeNullableFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null +} + +export type NestedEnumJobTargetTypeFilter<$PrismaModel = never> = { + equals?: $Enums.JobTargetType | Prisma.EnumJobTargetTypeFieldRefInput<$PrismaModel> + in?: $Enums.JobTargetType[] | Prisma.ListEnumJobTargetTypeFieldRefInput<$PrismaModel> + notIn?: $Enums.JobTargetType[] | Prisma.ListEnumJobTargetTypeFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumJobTargetTypeFilter<$PrismaModel> | $Enums.JobTargetType +} + +export type NestedEnumJobStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.JobStatus | Prisma.EnumJobStatusFieldRefInput<$PrismaModel> + in?: $Enums.JobStatus[] | Prisma.ListEnumJobStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.JobStatus[] | Prisma.ListEnumJobStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumJobStatusWithAggregatesFilter<$PrismaModel> | $Enums.JobStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumJobStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumJobStatusFilter<$PrismaModel> +} + +export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> + _max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> +} + +export type NestedEnumJobTargetTypeWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.JobTargetType | Prisma.EnumJobTargetTypeFieldRefInput<$PrismaModel> + in?: $Enums.JobTargetType[] | Prisma.ListEnumJobTargetTypeFieldRefInput<$PrismaModel> + notIn?: $Enums.JobTargetType[] | Prisma.ListEnumJobTargetTypeFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumJobTargetTypeWithAggregatesFilter<$PrismaModel> | $Enums.JobTargetType + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumJobTargetTypeFilter<$PrismaModel> + _max?: Prisma.NestedEnumJobTargetTypeFilter<$PrismaModel> +} + +export type NestedEnumMainCreationAgentSessionStatusFilter<$PrismaModel = never> = { + equals?: $Enums.MainCreationAgentSessionStatus | Prisma.EnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + in?: $Enums.MainCreationAgentSessionStatus[] | Prisma.ListEnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.MainCreationAgentSessionStatus[] | Prisma.ListEnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumMainCreationAgentSessionStatusFilter<$PrismaModel> | $Enums.MainCreationAgentSessionStatus +} + +export type NestedEnumMainCreationAgentSessionStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.MainCreationAgentSessionStatus | Prisma.EnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + in?: $Enums.MainCreationAgentSessionStatus[] | Prisma.ListEnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.MainCreationAgentSessionStatus[] | Prisma.ListEnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumMainCreationAgentSessionStatusWithAggregatesFilter<$PrismaModel> | $Enums.MainCreationAgentSessionStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumMainCreationAgentSessionStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumMainCreationAgentSessionStatusFilter<$PrismaModel> +} + +export type NestedEnumAgentTaskTypeFilter<$PrismaModel = never> = { + equals?: $Enums.AgentTaskType | Prisma.EnumAgentTaskTypeFieldRefInput<$PrismaModel> + in?: $Enums.AgentTaskType[] | Prisma.ListEnumAgentTaskTypeFieldRefInput<$PrismaModel> + notIn?: $Enums.AgentTaskType[] | Prisma.ListEnumAgentTaskTypeFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAgentTaskTypeFilter<$PrismaModel> | $Enums.AgentTaskType +} + +export type NestedEnumAgentTaskStatusFilter<$PrismaModel = never> = { + equals?: $Enums.AgentTaskStatus | Prisma.EnumAgentTaskStatusFieldRefInput<$PrismaModel> + in?: $Enums.AgentTaskStatus[] | Prisma.ListEnumAgentTaskStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.AgentTaskStatus[] | Prisma.ListEnumAgentTaskStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAgentTaskStatusFilter<$PrismaModel> | $Enums.AgentTaskStatus +} + +export type NestedEnumAgentTaskTypeWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.AgentTaskType | Prisma.EnumAgentTaskTypeFieldRefInput<$PrismaModel> + in?: $Enums.AgentTaskType[] | Prisma.ListEnumAgentTaskTypeFieldRefInput<$PrismaModel> + notIn?: $Enums.AgentTaskType[] | Prisma.ListEnumAgentTaskTypeFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAgentTaskTypeWithAggregatesFilter<$PrismaModel> | $Enums.AgentTaskType + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumAgentTaskTypeFilter<$PrismaModel> + _max?: Prisma.NestedEnumAgentTaskTypeFilter<$PrismaModel> +} + +export type NestedEnumAgentTaskStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.AgentTaskStatus | Prisma.EnumAgentTaskStatusFieldRefInput<$PrismaModel> + in?: $Enums.AgentTaskStatus[] | Prisma.ListEnumAgentTaskStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.AgentTaskStatus[] | Prisma.ListEnumAgentTaskStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumAgentTaskStatusWithAggregatesFilter<$PrismaModel> | $Enums.AgentTaskStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumAgentTaskStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumAgentTaskStatusFilter<$PrismaModel> +} + +export type NestedEnumReviewRecordStatusFilter<$PrismaModel = never> = { + equals?: $Enums.ReviewRecordStatus | Prisma.EnumReviewRecordStatusFieldRefInput<$PrismaModel> + in?: $Enums.ReviewRecordStatus[] | Prisma.ListEnumReviewRecordStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.ReviewRecordStatus[] | Prisma.ListEnumReviewRecordStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumReviewRecordStatusFilter<$PrismaModel> | $Enums.ReviewRecordStatus +} + +export type NestedEnumReviewDecisionNullableFilter<$PrismaModel = never> = { + equals?: $Enums.ReviewDecision | Prisma.EnumReviewDecisionFieldRefInput<$PrismaModel> | null + in?: $Enums.ReviewDecision[] | Prisma.ListEnumReviewDecisionFieldRefInput<$PrismaModel> | null + notIn?: $Enums.ReviewDecision[] | Prisma.ListEnumReviewDecisionFieldRefInput<$PrismaModel> | null + not?: Prisma.NestedEnumReviewDecisionNullableFilter<$PrismaModel> | $Enums.ReviewDecision | null +} + +export type NestedEnumReviewRecordStatusWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.ReviewRecordStatus | Prisma.EnumReviewRecordStatusFieldRefInput<$PrismaModel> + in?: $Enums.ReviewRecordStatus[] | Prisma.ListEnumReviewRecordStatusFieldRefInput<$PrismaModel> + notIn?: $Enums.ReviewRecordStatus[] | Prisma.ListEnumReviewRecordStatusFieldRefInput<$PrismaModel> + not?: Prisma.NestedEnumReviewRecordStatusWithAggregatesFilter<$PrismaModel> | $Enums.ReviewRecordStatus + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedEnumReviewRecordStatusFilter<$PrismaModel> + _max?: Prisma.NestedEnumReviewRecordStatusFilter<$PrismaModel> +} + +export type NestedEnumReviewDecisionNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: $Enums.ReviewDecision | Prisma.EnumReviewDecisionFieldRefInput<$PrismaModel> | null + in?: $Enums.ReviewDecision[] | Prisma.ListEnumReviewDecisionFieldRefInput<$PrismaModel> | null + notIn?: $Enums.ReviewDecision[] | Prisma.ListEnumReviewDecisionFieldRefInput<$PrismaModel> | null + not?: Prisma.NestedEnumReviewDecisionNullableWithAggregatesFilter<$PrismaModel> | $Enums.ReviewDecision | null + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedEnumReviewDecisionNullableFilter<$PrismaModel> + _max?: Prisma.NestedEnumReviewDecisionNullableFilter<$PrismaModel> +} + + diff --git a/apps/api/src/generated/prisma/enums.ts b/apps/api/src/generated/prisma/enums.ts new file mode 100644 index 00000000..c2ab892a --- /dev/null +++ b/apps/api/src/generated/prisma/enums.ts @@ -0,0 +1,122 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* +* This file exports all enum related types from the schema. +* +* 🟢 You can import this file directly. +*/ + +export const UserStatus = { + active: 'active', + disabled: 'disabled' +} as const + +export type UserStatus = (typeof UserStatus)[keyof typeof UserStatus] + + +export const UserRoleName = { + admin: 'admin', + operator: 'operator', + creator: 'creator', + player: 'player' +} as const + +export type UserRoleName = (typeof UserRoleName)[keyof typeof UserRoleName] + + +export const ProjectStatus = { + active: 'active', + archived: 'archived' +} as const + +export type ProjectStatus = (typeof ProjectStatus)[keyof typeof ProjectStatus] + + +export const GameVersionStatus = { + draft: 'draft', + candidate: 'candidate', + active: 'active', + archived: 'archived', + failed: 'failed' +} as const + +export type GameVersionStatus = (typeof GameVersionStatus)[keyof typeof GameVersionStatus] + + +export const AssetStatus = { + uploaded: 'uploaded', + deleted: 'deleted' +} as const + +export type AssetStatus = (typeof AssetStatus)[keyof typeof AssetStatus] + + +export const JobStatus = { + queued: 'queued', + running: 'running', + succeeded: 'succeeded', + pending_retry: 'pending_retry', + failed: 'failed', + canceled: 'canceled' +} as const + +export type JobStatus = (typeof JobStatus)[keyof typeof JobStatus] + + +export const JobTargetType = { + project: 'project', + version: 'version' +} as const + +export type JobTargetType = (typeof JobTargetType)[keyof typeof JobTargetType] + + +export const MainCreationAgentSessionStatus = { + routing_internal_tasks: 'routing_internal_tasks', + completed: 'completed', + failed: 'failed', + canceled: 'canceled' +} as const + +export type MainCreationAgentSessionStatus = (typeof MainCreationAgentSessionStatus)[keyof typeof MainCreationAgentSessionStatus] + + +export const AgentTaskType = { + requirement_clarifier: 'requirement_clarifier', + game_design_draft_generator: 'game_design_draft_generator' +} as const + +export type AgentTaskType = (typeof AgentTaskType)[keyof typeof AgentTaskType] + + +export const AgentTaskStatus = { + queued: 'queued', + running: 'running', + succeeded: 'succeeded', + failed: 'failed', + canceled: 'canceled', + timed_out: 'timed_out' +} as const + +export type AgentTaskStatus = (typeof AgentTaskStatus)[keyof typeof AgentTaskStatus] + + +export const ReviewRecordStatus = { + pending_review: 'pending_review', + approved: 'approved', + rejected: 'rejected', + canceled: 'canceled' +} as const + +export type ReviewRecordStatus = (typeof ReviewRecordStatus)[keyof typeof ReviewRecordStatus] + + +export const ReviewDecision = { + approved: 'approved', + rejected: 'rejected' +} as const + +export type ReviewDecision = (typeof ReviewDecision)[keyof typeof ReviewDecision] diff --git a/apps/api/src/generated/prisma/internal/class.ts b/apps/api/src/generated/prisma/internal/class.ts new file mode 100644 index 00000000..84011b7a --- /dev/null +++ b/apps/api/src/generated/prisma/internal/class.ts @@ -0,0 +1,314 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * WARNING: This is an internal file that is subject to change! + * + * 🛑 Under no circumstances should you import this file directly! 🛑 + * + * Please import the `PrismaClient` class from the `client.ts` file instead. + */ + +import * as runtime from "@prisma/client/runtime/client" +import type * as Prisma from "./prismaNamespace.js" + + +const config: runtime.GetPrismaClientConfig = { + "previewFeatures": [], + "clientVersion": "7.8.0", + "engineVersion": "3c6e192761c0362d496ed980de936e2f3cebcd3a", + "activeProvider": "postgresql", + "inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"../src/generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nenum UserStatus {\n active\n disabled\n}\n\nenum UserRoleName {\n admin\n operator\n creator\n player\n}\n\nenum ProjectStatus {\n active\n archived\n}\n\nenum GameVersionStatus {\n draft\n candidate\n active\n archived\n failed\n}\n\nenum AssetStatus {\n uploaded\n deleted\n}\n\nenum JobStatus {\n queued\n running\n succeeded\n pending_retry\n failed\n canceled\n}\n\nenum JobTargetType {\n project\n version\n}\n\nenum MainCreationAgentSessionStatus {\n routing_internal_tasks\n completed\n failed\n canceled\n}\n\nenum AgentTaskType {\n requirement_clarifier\n game_design_draft_generator\n}\n\nenum AgentTaskStatus {\n queued\n running\n succeeded\n failed\n canceled\n timed_out\n}\n\nenum ReviewRecordStatus {\n pending_review\n approved\n rejected\n canceled\n}\n\nenum ReviewDecision {\n approved\n rejected\n}\n\nmodel User {\n id String @id\n email String? @unique\n displayName String\n status UserStatus @default(active)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n roles UserRole[]\n anonymousIdentities AnonymousIdentity[]\n gameProjects GameProject[]\n auditLogs AuditLog[] @relation(\"AuditActor\")\n jobs Job[] @relation(\"JobActor\")\n mainCreationAgentSessions MainCreationAgentSession[]\n reviewDecisions ReviewRecord[] @relation(\"ReviewDecider\")\n}\n\nmodel UserRole {\n id String @id @default(cuid())\n userId String\n role UserRoleName\n createdAt DateTime @default(now())\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, role])\n @@index([role])\n}\n\nmodel AnonymousIdentity {\n id String @id\n userId String\n deviceKey String\n createdAt DateTime @default(now())\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([deviceKey])\n @@index([userId])\n}\n\nmodel GameProject {\n id String @id\n ownerId String\n slug String @unique\n title String\n status ProjectStatus @default(active)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n owner User @relation(fields: [ownerId], references: [id], onDelete: Restrict)\n versions GameVersion[]\n assets Asset[]\n jobs Job[] @relation(\"JobProjectScope\")\n projectTargetJobs Job[] @relation(\"JobGameProjectTarget\")\n mainCreationAgentSessionScopes MainCreationAgentSession[] @relation(\"MainCreationAgentSessionProjectScope\")\n\n @@index([ownerId])\n}\n\nmodel GameVersion {\n id String @id\n projectId String\n versionNumber Int\n status GameVersionStatus\n configJson Json\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n project GameProject @relation(fields: [projectId], references: [id], onDelete: Cascade)\n versionTargetJobs Job[] @relation(\"JobGameVersionTarget\")\n mainCreationAgentSessionScopes MainCreationAgentSession[] @relation(\"MainCreationAgentSessionVersionScope\")\n reviewRecords ReviewRecord[]\n lifecycleEvents LifecycleEvent[]\n\n @@unique([projectId, versionNumber])\n @@unique([id, projectId])\n @@index([projectId, status])\n}\n\nmodel Asset {\n id String @id\n projectId String\n kind String\n storageKey String\n mimeType String\n byteSize Int\n sha256 String\n status AssetStatus @default(uploaded)\n metadataJson Json?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n project GameProject @relation(fields: [projectId], references: [id], onDelete: Cascade)\n\n @@unique([projectId, storageKey])\n @@index([projectId, kind])\n}\n\nmodel Job {\n id String @id\n actorId String\n projectId String\n type String\n idempotencyKey String\n status JobStatus @default(queued)\n attempts Int @default(0)\n maxAttempts Int @default(3)\n timeoutAt DateTime?\n nextRetryAt DateTime?\n errorCode String?\n leaseToken String?\n leasedBy String?\n leaseExpiresAt DateTime?\n lockVersion Int @default(0)\n targetType JobTargetType\n targetId String\n targetScopeKey String\n gameProjectId String?\n gameVersionId String?\n payloadJson Json\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n actor User @relation(\"JobActor\", fields: [actorId], references: [id], onDelete: Restrict)\n project GameProject @relation(\"JobProjectScope\", fields: [projectId], references: [id], onDelete: Cascade)\n gameProject GameProject? @relation(\"JobGameProjectTarget\", fields: [gameProjectId], references: [id], onDelete: Restrict)\n gameVersion GameVersion? @relation(\"JobGameVersionTarget\", fields: [gameVersionId, projectId], references: [id, projectId], onDelete: Restrict)\n\n @@unique([actorId, projectId, type, targetScopeKey, idempotencyKey])\n @@index([projectId, status])\n @@index([actorId, status])\n @@index([status, nextRetryAt, createdAt])\n @@index([leaseToken])\n @@index([gameProjectId])\n @@index([gameVersionId])\n}\n\nmodel AuditLog {\n id String @id\n actorId String\n action String\n targetType String\n targetId String\n eventJson Json\n createdAt DateTime @default(now())\n actor User @relation(\"AuditActor\", fields: [actorId], references: [id], onDelete: Restrict)\n\n @@index([actorId, createdAt])\n @@index([targetType, targetId])\n}\n\nmodel MainCreationAgentSession {\n id String @id\n creatorId String\n projectId String\n versionId String\n status MainCreationAgentSessionStatus\n contextSummary String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n creator User @relation(fields: [creatorId], references: [id], onDelete: Restrict)\n project GameProject @relation(\"MainCreationAgentSessionProjectScope\", fields: [projectId], references: [id], onDelete: Cascade)\n version GameVersion @relation(\"MainCreationAgentSessionVersionScope\", fields: [versionId, projectId], references: [id, projectId], onDelete: Restrict)\n tasks AgentTask[]\n\n @@index([creatorId])\n @@index([projectId])\n @@index([versionId])\n}\n\nmodel AgentTask {\n id String @id\n sessionId String\n taskType AgentTaskType\n subagentId String\n inputRef String\n outputRef String?\n status AgentTaskStatus\n timeoutAt DateTime\n errorCode String?\n auditLogId String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n session MainCreationAgentSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)\n\n @@index([sessionId])\n @@index([status])\n}\n\nmodel ReviewRecord {\n id String @id\n gameVersionId String\n status ReviewRecordStatus\n decision ReviewDecision?\n reasonCode String?\n decidedById String?\n decidedAt DateTime?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n gameVersion GameVersion @relation(fields: [gameVersionId], references: [id], onDelete: Cascade)\n decidedBy User? @relation(\"ReviewDecider\", fields: [decidedById], references: [id], onDelete: Restrict)\n\n @@index([gameVersionId, status])\n @@index([decidedById])\n}\n\nmodel LifecycleEvent {\n eventId String @id\n gameVersionId String?\n event String\n from String\n to String\n actorJson Json\n requiredRole String\n requiredRecordRefsJson Json\n auditEvent String\n reasonCode String\n occurredAt DateTime\n approval String\n requiredRecordsJson Json\n createdAt DateTime @default(now())\n gameVersion GameVersion? @relation(fields: [gameVersionId], references: [id], onDelete: SetNull)\n\n @@index([gameVersionId])\n @@index([event, occurredAt])\n}\n", + "runtimeDataModel": { + "models": {}, + "enums": {}, + "types": {} + }, + "parameterizationSchema": { + "strings": [], + "graph": "" + } +} + +config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"displayName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"UserStatus\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"roles\",\"kind\":\"object\",\"type\":\"UserRole\",\"relationName\":\"UserToUserRole\"},{\"name\":\"anonymousIdentities\",\"kind\":\"object\",\"type\":\"AnonymousIdentity\",\"relationName\":\"AnonymousIdentityToUser\"},{\"name\":\"gameProjects\",\"kind\":\"object\",\"type\":\"GameProject\",\"relationName\":\"GameProjectToUser\"},{\"name\":\"auditLogs\",\"kind\":\"object\",\"type\":\"AuditLog\",\"relationName\":\"AuditActor\"},{\"name\":\"jobs\",\"kind\":\"object\",\"type\":\"Job\",\"relationName\":\"JobActor\"},{\"name\":\"mainCreationAgentSessions\",\"kind\":\"object\",\"type\":\"MainCreationAgentSession\",\"relationName\":\"MainCreationAgentSessionToUser\"},{\"name\":\"reviewDecisions\",\"kind\":\"object\",\"type\":\"ReviewRecord\",\"relationName\":\"ReviewDecider\"}],\"dbName\":null},\"UserRole\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"UserRoleName\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToUserRole\"}],\"dbName\":null},\"AnonymousIdentity\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"deviceKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"AnonymousIdentityToUser\"}],\"dbName\":null},\"GameProject\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"ownerId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"slug\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"ProjectStatus\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"owner\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"GameProjectToUser\"},{\"name\":\"versions\",\"kind\":\"object\",\"type\":\"GameVersion\",\"relationName\":\"GameProjectToGameVersion\"},{\"name\":\"assets\",\"kind\":\"object\",\"type\":\"Asset\",\"relationName\":\"AssetToGameProject\"},{\"name\":\"jobs\",\"kind\":\"object\",\"type\":\"Job\",\"relationName\":\"JobProjectScope\"},{\"name\":\"projectTargetJobs\",\"kind\":\"object\",\"type\":\"Job\",\"relationName\":\"JobGameProjectTarget\"},{\"name\":\"mainCreationAgentSessionScopes\",\"kind\":\"object\",\"type\":\"MainCreationAgentSession\",\"relationName\":\"MainCreationAgentSessionProjectScope\"}],\"dbName\":null},\"GameVersion\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"projectId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"versionNumber\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"GameVersionStatus\"},{\"name\":\"configJson\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"project\",\"kind\":\"object\",\"type\":\"GameProject\",\"relationName\":\"GameProjectToGameVersion\"},{\"name\":\"versionTargetJobs\",\"kind\":\"object\",\"type\":\"Job\",\"relationName\":\"JobGameVersionTarget\"},{\"name\":\"mainCreationAgentSessionScopes\",\"kind\":\"object\",\"type\":\"MainCreationAgentSession\",\"relationName\":\"MainCreationAgentSessionVersionScope\"},{\"name\":\"reviewRecords\",\"kind\":\"object\",\"type\":\"ReviewRecord\",\"relationName\":\"GameVersionToReviewRecord\"},{\"name\":\"lifecycleEvents\",\"kind\":\"object\",\"type\":\"LifecycleEvent\",\"relationName\":\"GameVersionToLifecycleEvent\"}],\"dbName\":null},\"Asset\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"projectId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"kind\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"storageKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"mimeType\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"byteSize\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"sha256\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"AssetStatus\"},{\"name\":\"metadataJson\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"project\",\"kind\":\"object\",\"type\":\"GameProject\",\"relationName\":\"AssetToGameProject\"}],\"dbName\":null},\"Job\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"actorId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"projectId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"type\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"idempotencyKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"JobStatus\"},{\"name\":\"attempts\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"maxAttempts\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"timeoutAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"nextRetryAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"errorCode\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"leaseToken\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"leasedBy\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"leaseExpiresAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"lockVersion\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"targetType\",\"kind\":\"enum\",\"type\":\"JobTargetType\"},{\"name\":\"targetId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"targetScopeKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"gameProjectId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"gameVersionId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"payloadJson\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"actor\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"JobActor\"},{\"name\":\"project\",\"kind\":\"object\",\"type\":\"GameProject\",\"relationName\":\"JobProjectScope\"},{\"name\":\"gameProject\",\"kind\":\"object\",\"type\":\"GameProject\",\"relationName\":\"JobGameProjectTarget\"},{\"name\":\"gameVersion\",\"kind\":\"object\",\"type\":\"GameVersion\",\"relationName\":\"JobGameVersionTarget\"}],\"dbName\":null},\"AuditLog\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"actorId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"action\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"targetType\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"targetId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"eventJson\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"actor\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"AuditActor\"}],\"dbName\":null},\"MainCreationAgentSession\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"creatorId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"projectId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"versionId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"MainCreationAgentSessionStatus\"},{\"name\":\"contextSummary\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"creator\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"MainCreationAgentSessionToUser\"},{\"name\":\"project\",\"kind\":\"object\",\"type\":\"GameProject\",\"relationName\":\"MainCreationAgentSessionProjectScope\"},{\"name\":\"version\",\"kind\":\"object\",\"type\":\"GameVersion\",\"relationName\":\"MainCreationAgentSessionVersionScope\"},{\"name\":\"tasks\",\"kind\":\"object\",\"type\":\"AgentTask\",\"relationName\":\"AgentTaskToMainCreationAgentSession\"}],\"dbName\":null},\"AgentTask\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessionId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"taskType\",\"kind\":\"enum\",\"type\":\"AgentTaskType\"},{\"name\":\"subagentId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"inputRef\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"outputRef\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"AgentTaskStatus\"},{\"name\":\"timeoutAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"errorCode\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"auditLogId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"session\",\"kind\":\"object\",\"type\":\"MainCreationAgentSession\",\"relationName\":\"AgentTaskToMainCreationAgentSession\"}],\"dbName\":null},\"ReviewRecord\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"gameVersionId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"ReviewRecordStatus\"},{\"name\":\"decision\",\"kind\":\"enum\",\"type\":\"ReviewDecision\"},{\"name\":\"reasonCode\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"decidedById\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"decidedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"gameVersion\",\"kind\":\"object\",\"type\":\"GameVersion\",\"relationName\":\"GameVersionToReviewRecord\"},{\"name\":\"decidedBy\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"ReviewDecider\"}],\"dbName\":null},\"LifecycleEvent\":{\"fields\":[{\"name\":\"eventId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"gameVersionId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"event\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"from\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"to\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"actorJson\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"requiredRole\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"requiredRecordRefsJson\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"auditEvent\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"reasonCode\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"occurredAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"approval\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"requiredRecordsJson\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"gameVersion\",\"kind\":\"object\",\"type\":\"GameVersion\",\"relationName\":\"GameVersionToLifecycleEvent\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") +config.parameterizationSchema = { + strings: JSON.parse("[\"where\",\"orderBy\",\"cursor\",\"user\",\"roles\",\"anonymousIdentities\",\"owner\",\"project\",\"actor\",\"gameProject\",\"gameVersion\",\"versionTargetJobs\",\"creator\",\"version\",\"session\",\"tasks\",\"_count\",\"mainCreationAgentSessionScopes\",\"decidedBy\",\"reviewRecords\",\"lifecycleEvents\",\"versions\",\"assets\",\"jobs\",\"projectTargetJobs\",\"gameProjects\",\"auditLogs\",\"mainCreationAgentSessions\",\"reviewDecisions\",\"User.findUnique\",\"User.findUniqueOrThrow\",\"User.findFirst\",\"User.findFirstOrThrow\",\"User.findMany\",\"data\",\"User.createOne\",\"User.createMany\",\"User.createManyAndReturn\",\"User.updateOne\",\"User.updateMany\",\"User.updateManyAndReturn\",\"create\",\"update\",\"User.upsertOne\",\"User.deleteOne\",\"User.deleteMany\",\"having\",\"_min\",\"_max\",\"User.groupBy\",\"User.aggregate\",\"UserRole.findUnique\",\"UserRole.findUniqueOrThrow\",\"UserRole.findFirst\",\"UserRole.findFirstOrThrow\",\"UserRole.findMany\",\"UserRole.createOne\",\"UserRole.createMany\",\"UserRole.createManyAndReturn\",\"UserRole.updateOne\",\"UserRole.updateMany\",\"UserRole.updateManyAndReturn\",\"UserRole.upsertOne\",\"UserRole.deleteOne\",\"UserRole.deleteMany\",\"UserRole.groupBy\",\"UserRole.aggregate\",\"AnonymousIdentity.findUnique\",\"AnonymousIdentity.findUniqueOrThrow\",\"AnonymousIdentity.findFirst\",\"AnonymousIdentity.findFirstOrThrow\",\"AnonymousIdentity.findMany\",\"AnonymousIdentity.createOne\",\"AnonymousIdentity.createMany\",\"AnonymousIdentity.createManyAndReturn\",\"AnonymousIdentity.updateOne\",\"AnonymousIdentity.updateMany\",\"AnonymousIdentity.updateManyAndReturn\",\"AnonymousIdentity.upsertOne\",\"AnonymousIdentity.deleteOne\",\"AnonymousIdentity.deleteMany\",\"AnonymousIdentity.groupBy\",\"AnonymousIdentity.aggregate\",\"GameProject.findUnique\",\"GameProject.findUniqueOrThrow\",\"GameProject.findFirst\",\"GameProject.findFirstOrThrow\",\"GameProject.findMany\",\"GameProject.createOne\",\"GameProject.createMany\",\"GameProject.createManyAndReturn\",\"GameProject.updateOne\",\"GameProject.updateMany\",\"GameProject.updateManyAndReturn\",\"GameProject.upsertOne\",\"GameProject.deleteOne\",\"GameProject.deleteMany\",\"GameProject.groupBy\",\"GameProject.aggregate\",\"GameVersion.findUnique\",\"GameVersion.findUniqueOrThrow\",\"GameVersion.findFirst\",\"GameVersion.findFirstOrThrow\",\"GameVersion.findMany\",\"GameVersion.createOne\",\"GameVersion.createMany\",\"GameVersion.createManyAndReturn\",\"GameVersion.updateOne\",\"GameVersion.updateMany\",\"GameVersion.updateManyAndReturn\",\"GameVersion.upsertOne\",\"GameVersion.deleteOne\",\"GameVersion.deleteMany\",\"_avg\",\"_sum\",\"GameVersion.groupBy\",\"GameVersion.aggregate\",\"Asset.findUnique\",\"Asset.findUniqueOrThrow\",\"Asset.findFirst\",\"Asset.findFirstOrThrow\",\"Asset.findMany\",\"Asset.createOne\",\"Asset.createMany\",\"Asset.createManyAndReturn\",\"Asset.updateOne\",\"Asset.updateMany\",\"Asset.updateManyAndReturn\",\"Asset.upsertOne\",\"Asset.deleteOne\",\"Asset.deleteMany\",\"Asset.groupBy\",\"Asset.aggregate\",\"Job.findUnique\",\"Job.findUniqueOrThrow\",\"Job.findFirst\",\"Job.findFirstOrThrow\",\"Job.findMany\",\"Job.createOne\",\"Job.createMany\",\"Job.createManyAndReturn\",\"Job.updateOne\",\"Job.updateMany\",\"Job.updateManyAndReturn\",\"Job.upsertOne\",\"Job.deleteOne\",\"Job.deleteMany\",\"Job.groupBy\",\"Job.aggregate\",\"AuditLog.findUnique\",\"AuditLog.findUniqueOrThrow\",\"AuditLog.findFirst\",\"AuditLog.findFirstOrThrow\",\"AuditLog.findMany\",\"AuditLog.createOne\",\"AuditLog.createMany\",\"AuditLog.createManyAndReturn\",\"AuditLog.updateOne\",\"AuditLog.updateMany\",\"AuditLog.updateManyAndReturn\",\"AuditLog.upsertOne\",\"AuditLog.deleteOne\",\"AuditLog.deleteMany\",\"AuditLog.groupBy\",\"AuditLog.aggregate\",\"MainCreationAgentSession.findUnique\",\"MainCreationAgentSession.findUniqueOrThrow\",\"MainCreationAgentSession.findFirst\",\"MainCreationAgentSession.findFirstOrThrow\",\"MainCreationAgentSession.findMany\",\"MainCreationAgentSession.createOne\",\"MainCreationAgentSession.createMany\",\"MainCreationAgentSession.createManyAndReturn\",\"MainCreationAgentSession.updateOne\",\"MainCreationAgentSession.updateMany\",\"MainCreationAgentSession.updateManyAndReturn\",\"MainCreationAgentSession.upsertOne\",\"MainCreationAgentSession.deleteOne\",\"MainCreationAgentSession.deleteMany\",\"MainCreationAgentSession.groupBy\",\"MainCreationAgentSession.aggregate\",\"AgentTask.findUnique\",\"AgentTask.findUniqueOrThrow\",\"AgentTask.findFirst\",\"AgentTask.findFirstOrThrow\",\"AgentTask.findMany\",\"AgentTask.createOne\",\"AgentTask.createMany\",\"AgentTask.createManyAndReturn\",\"AgentTask.updateOne\",\"AgentTask.updateMany\",\"AgentTask.updateManyAndReturn\",\"AgentTask.upsertOne\",\"AgentTask.deleteOne\",\"AgentTask.deleteMany\",\"AgentTask.groupBy\",\"AgentTask.aggregate\",\"ReviewRecord.findUnique\",\"ReviewRecord.findUniqueOrThrow\",\"ReviewRecord.findFirst\",\"ReviewRecord.findFirstOrThrow\",\"ReviewRecord.findMany\",\"ReviewRecord.createOne\",\"ReviewRecord.createMany\",\"ReviewRecord.createManyAndReturn\",\"ReviewRecord.updateOne\",\"ReviewRecord.updateMany\",\"ReviewRecord.updateManyAndReturn\",\"ReviewRecord.upsertOne\",\"ReviewRecord.deleteOne\",\"ReviewRecord.deleteMany\",\"ReviewRecord.groupBy\",\"ReviewRecord.aggregate\",\"LifecycleEvent.findUnique\",\"LifecycleEvent.findUniqueOrThrow\",\"LifecycleEvent.findFirst\",\"LifecycleEvent.findFirstOrThrow\",\"LifecycleEvent.findMany\",\"LifecycleEvent.createOne\",\"LifecycleEvent.createMany\",\"LifecycleEvent.createManyAndReturn\",\"LifecycleEvent.updateOne\",\"LifecycleEvent.updateMany\",\"LifecycleEvent.updateManyAndReturn\",\"LifecycleEvent.upsertOne\",\"LifecycleEvent.deleteOne\",\"LifecycleEvent.deleteMany\",\"LifecycleEvent.groupBy\",\"LifecycleEvent.aggregate\",\"AND\",\"OR\",\"NOT\",\"eventId\",\"gameVersionId\",\"event\",\"from\",\"to\",\"actorJson\",\"requiredRole\",\"requiredRecordRefsJson\",\"auditEvent\",\"reasonCode\",\"occurredAt\",\"approval\",\"requiredRecordsJson\",\"createdAt\",\"equals\",\"in\",\"notIn\",\"lt\",\"lte\",\"gt\",\"gte\",\"not\",\"string_contains\",\"string_starts_with\",\"string_ends_with\",\"array_starts_with\",\"array_ends_with\",\"array_contains\",\"contains\",\"startsWith\",\"endsWith\",\"id\",\"ReviewRecordStatus\",\"status\",\"ReviewDecision\",\"decision\",\"decidedById\",\"decidedAt\",\"updatedAt\",\"sessionId\",\"AgentTaskType\",\"taskType\",\"subagentId\",\"inputRef\",\"outputRef\",\"AgentTaskStatus\",\"timeoutAt\",\"errorCode\",\"auditLogId\",\"creatorId\",\"projectId\",\"versionId\",\"MainCreationAgentSessionStatus\",\"contextSummary\",\"actorId\",\"action\",\"targetType\",\"targetId\",\"eventJson\",\"type\",\"idempotencyKey\",\"JobStatus\",\"attempts\",\"maxAttempts\",\"nextRetryAt\",\"leaseToken\",\"leasedBy\",\"leaseExpiresAt\",\"lockVersion\",\"JobTargetType\",\"targetScopeKey\",\"gameProjectId\",\"payloadJson\",\"kind\",\"storageKey\",\"mimeType\",\"byteSize\",\"sha256\",\"AssetStatus\",\"metadataJson\",\"versionNumber\",\"GameVersionStatus\",\"configJson\",\"ownerId\",\"slug\",\"title\",\"ProjectStatus\",\"userId\",\"deviceKey\",\"UserRoleName\",\"role\",\"email\",\"displayName\",\"UserStatus\",\"projectId_storageKey\",\"every\",\"some\",\"none\",\"actorId_projectId_type_targetScopeKey_idempotencyKey\",\"projectId_versionNumber\",\"id_projectId\",\"userId_role\",\"is\",\"isNot\",\"connectOrCreate\",\"upsert\",\"createMany\",\"set\",\"disconnect\",\"delete\",\"connect\",\"updateMany\",\"deleteMany\",\"increment\",\"decrement\",\"multiply\",\"divide\"]"), + graph: "hAdrwAEQBAAAsAMAIAUAALEDACAXAAC0AwAgGQAAsgMAIBoAALMDACAbAAC1AwAgHAAAtgMAIOUBAACuAwAw5gEAACYAEOcBAACuAwAw9QFAAKMDACGHAgEAAAABiQIAAK8DxgIijgJAAKMDACHDAgEAAAABxAIBAKEDACEBAAAAAQAgCAMAAKQDACDlAQAA1AMAMOYBAAADABDnAQAA1AMAMPUBQACjAwAhhwIBAKEDACG_AgEAoQMAIcICAADVA8ICIgEDAACXBgAgCQMAAKQDACDlAQAA1AMAMOYBAAADABDnAQAA1AMAMPUBQACjAwAhhwIBAAAAAb8CAQChAwAhwgIAANUDwgIizQIAANMDACADAAAAAwAgAQAABAAwAgAABQAgCAMAAKQDACDlAQAA0gMAMOYBAAAHABDnAQAA0gMAMPUBQACjAwAhhwIBAKEDACG_AgEAoQMAIcACAQChAwAhAQMAAJcGACAIAwAApAMAIOUBAADSAwAw5gEAAAcAEOcBAADSAwAw9QFAAKMDACGHAgEAAAABvwIBAKEDACHAAgEAAAABAwAAAAcAIAEAAAgAMAIAAAkAIBAGAACkAwAgEQAAtQMAIBUAANADACAWAADRAwAgFwAAtAMAIBgAALQDACDlAQAAzgMAMOYBAAALABDnAQAAzgMAMPUBQACjAwAhhwIBAKEDACGJAgAAzwO_AiKOAkAAowMAIbsCAQChAwAhvAIBAKEDACG9AgEAoQMAIQYGAACXBgAgEQAAlQYAIBUAAJ0GACAWAACeBgAgFwAAlAYAIBgAAJQGACAQBgAApAMAIBEAALUDACAVAADQAwAgFgAA0QMAIBcAALQDACAYAAC0AwAg5QEAAM4DADDmAQAACwAQ5wEAAM4DADD1AUAAowMAIYcCAQAAAAGJAgAAzwO_AiKOAkAAowMAIbsCAQChAwAhvAIBAAAAAb0CAQChAwAhAwAAAAsAIAEAAAwAMAIAAA0AIA8HAACqAwAgCwAAtAMAIBEAALUDACATAAC2AwAgFAAAzQMAIOUBAADLAwAw5gEAAA8AEOcBAADLAwAw9QFAAKMDACGHAgEAoQMAIYkCAADMA7oCIo4CQACjAwAhmgIBAKEDACG4AgIApwMAIboCAACiAwAgBQcAAJgGACALAACUBgAgEQAAlQYAIBMAAJYGACAUAACcBgAgEQcAAKoDACALAAC0AwAgEQAAtQMAIBMAALYDACAUAADNAwAg5QEAAMsDADDmAQAADwAQ5wEAAMsDADD1AUAAowMAIYcCAQAAAAGJAgAAzAO6AiKOAkAAowMAIZoCAQChAwAhuAICAKcDACG6AgAAogMAIMsCAADJAwAgzAIAAMoDACADAAAADwAgAQAAEAAwAgAAEQAgHgcAAKoDACAIAACkAwAgCQAAyAMAIAoAAK0DACDlAQAAxQMAMOYBAAATABDnAQAAxQMAMOkBAQCsAwAh9QFAAKMDACGHAgEAoQMAIYkCAADGA6YCIo4CQACjAwAhlgJAALoDACGXAgEArAMAIZoCAQChAwAhngIBAKEDACGgAgAAxwOuAiKhAgEAoQMAIaMCAQChAwAhpAIBAKEDACGmAgIApwMAIacCAgCnAwAhqAJAALoDACGpAgEArAMAIaoCAQCsAwAhqwJAALoDACGsAgIApwMAIa4CAQChAwAhrwIBAKwDACGwAgAAogMAIAwHAACYBgAgCAAAlwYAIAkAAJgGACAKAACZBgAg6QEAANYDACCWAgAA1gMAIJcCAADWAwAgqAIAANYDACCpAgAA1gMAIKoCAADWAwAgqwIAANYDACCvAgAA1gMAIB8HAACqAwAgCAAApAMAIAkAAMgDACAKAACtAwAg5QEAAMUDADDmAQAAEwAQ5wEAAMUDADDpAQEArAMAIfUBQACjAwAhhwIBAAAAAYkCAADGA6YCIo4CQACjAwAhlgJAALoDACGXAgEArAMAIZoCAQChAwAhngIBAKEDACGgAgAAxwOuAiKhAgEAoQMAIaMCAQChAwAhpAIBAKEDACGmAgIApwMAIacCAgCnAwAhqAJAALoDACGpAgEArAMAIaoCAQCsAwAhqwJAALoDACGsAgIApwMAIa4CAQChAwAhrwIBAKwDACGwAgAAogMAIMoCAADEAwAgAwAAABMAIAEAABQAMAIAABUAIAEAAAALACABAAAADwAgDwcAAKoDACAMAACkAwAgDQAAuwMAIA8AAMMDACDlAQAAwQMAMOYBAAAZABDnAQAAwQMAMPUBQACjAwAhhwIBAKEDACGJAgAAwgOdAiKOAkAAowMAIZkCAQChAwAhmgIBAKEDACGbAgEAoQMAIZ0CAQChAwAhBAcAAJgGACAMAACXBgAgDQAAmQYAIA8AAJsGACAPBwAAqgMAIAwAAKQDACANAAC7AwAgDwAAwwMAIOUBAADBAwAw5gEAABkAEOcBAADBAwAw9QFAAKMDACGHAgEAAAABiQIAAMIDnQIijgJAAKMDACGZAgEAoQMAIZoCAQChAwAhmwIBAKEDACGdAgEAoQMAIQMAAAAZACABAAAaADACAAAbACAQDgAAwAMAIOUBAAC9AwAw5gEAAB0AEOcBAAC9AwAw9QFAAKMDACGHAgEAoQMAIYkCAAC_A5YCIo4CQACjAwAhjwIBAKEDACGRAgAAvgORAiKSAgEAoQMAIZMCAQChAwAhlAIBAKwDACGWAkAAowMAIZcCAQCsAwAhmAIBAKEDACEDDgAAmgYAIJQCAADWAwAglwIAANYDACAQDgAAwAMAIOUBAAC9AwAw5gEAAB0AEOcBAAC9AwAw9QFAAKMDACGHAgEAAAABiQIAAL8DlgIijgJAAKMDACGPAgEAoQMAIZECAAC-A5ECIpICAQChAwAhkwIBAKEDACGUAgEArAMAIZYCQACjAwAhlwIBAKwDACGYAgEAoQMAIQMAAAAdACABAAAeADACAAAfACABAAAAHQAgDgoAALsDACASAAC8AwAg5QEAALcDADDmAQAAIgAQ5wEAALcDADDpAQEAoQMAIfEBAQCsAwAh9QFAAKMDACGHAgEAoQMAIYkCAAC4A4kCIosCAAC5A4sCI4wCAQCsAwAhjQJAALoDACGOAkAAowMAIQYKAACZBgAgEgAAlwYAIPEBAADWAwAgiwIAANYDACCMAgAA1gMAII0CAADWAwAgDgoAALsDACASAAC8AwAg5QEAALcDADDmAQAAIgAQ5wEAALcDADDpAQEAoQMAIfEBAQCsAwAh9QFAAKMDACGHAgEAAAABiQIAALgDiQIiiwIAALkDiwIjjAIBAKwDACGNAkAAugMAIY4CQACjAwAhAwAAACIAIAEAACMAMAIAACQAIBAEAACwAwAgBQAAsQMAIBcAALQDACAZAACyAwAgGgAAswMAIBsAALUDACAcAAC2AwAg5QEAAK4DADDmAQAAJgAQ5wEAAK4DADD1AUAAowMAIYcCAQChAwAhiQIAAK8DxgIijgJAAKMDACHDAgEArAMAIcQCAQChAwAhAQAAACYAIBIKAACtAwAg5QEAAKsDADDmAQAAKAAQ5wEAAKsDADDoAQEAoQMAIekBAQCsAwAh6gEBAKEDACHrAQEAoQMAIewBAQChAwAh7QEAAKIDACDuAQEAoQMAIe8BAACiAwAg8AEBAKEDACHxAQEAoQMAIfIBQACjAwAh8wEBAKEDACH0AQAAogMAIPUBQACjAwAhAgoAAJkGACDpAQAA1gMAIBIKAACtAwAg5QEAAKsDADDmAQAAKAAQ5wEAAKsDADDoAQEAAAAB6QEBAKwDACHqAQEAoQMAIesBAQChAwAh7AEBAKEDACHtAQAAogMAIO4BAQChAwAh7wEAAKIDACDwAQEAoQMAIfEBAQChAwAh8gFAAKMDACHzAQEAoQMAIfQBAACiAwAg9QFAAKMDACEDAAAAKAAgAQAAKQAwAgAAKgAgAQAAAA8AIAEAAAATACABAAAAGQAgAQAAACIAIAEAAAAoACAPBwAAqgMAIOUBAACmAwAw5gEAADEAEOcBAACmAwAw9QFAAKMDACGHAgEAoQMAIYkCAACoA7cCIo4CQACjAwAhmgIBAKEDACGxAgEAoQMAIbICAQChAwAhswIBAKEDACG0AgIApwMAIbUCAQChAwAhtwIAAKkDACACBwAAmAYAILcCAADWAwAgEAcAAKoDACDlAQAApgMAMOYBAAAxABDnAQAApgMAMPUBQACjAwAhhwIBAAAAAYkCAACoA7cCIo4CQACjAwAhmgIBAKEDACGxAgEAoQMAIbICAQChAwAhswIBAKEDACG0AgIApwMAIbUCAQChAwAhtwIAAKkDACDGAgAApQMAIAMAAAAxACABAAAyADACAAAzACADAAAAEwAgAQAAFAAwAgAAFQAgAwAAABMAIAEAABQAMAIAABUAIAMAAAAZACABAAAaADACAAAbACABAAAADwAgAQAAADEAIAEAAAATACABAAAAEwAgAQAAABkAIAsIAACkAwAg5QEAAKADADDmAQAAPQAQ5wEAAKADADD1AUAAowMAIYcCAQChAwAhngIBAKEDACGfAgEAoQMAIaACAQChAwAhoQIBAKEDACGiAgAAogMAIAEIAACXBgAgCwgAAKQDACDlAQAAoAMAMOYBAAA9ABDnAQAAoAMAMPUBQACjAwAhhwIBAAAAAZ4CAQChAwAhnwIBAKEDACGgAgEAoQMAIaECAQChAwAhogIAAKIDACADAAAAPQAgAQAAPgAwAgAAPwAgAwAAABMAIAEAABQAMAIAABUAIAMAAAAZACABAAAaADACAAAbACADAAAAIgAgAQAAIwAwAgAAJAAgAQAAAAMAIAEAAAAHACABAAAACwAgAQAAAD0AIAEAAAATACABAAAAGQAgAQAAACIAIAEAAAABACAIBAAAkAYAIAUAAJEGACAXAACUBgAgGQAAkgYAIBoAAJMGACAbAACVBgAgHAAAlgYAIMMCAADWAwAgAwAAACYAIAEAAEwAMAIAAAEAIAMAAAAmACABAABMADACAAABACADAAAAJgAgAQAATAAwAgAAAQAgDQQAAIkGACAFAACKBgAgFwAAjQYAIBkAAIsGACAaAACMBgAgGwAAjgYAIBwAAI8GACD1AUAAAAABhwIBAAAAAYkCAAAAxgICjgJAAAAAAcMCAQAAAAHEAgEAAAABASIAAFAAIAb1AUAAAAABhwIBAAAAAYkCAAAAxgICjgJAAAAAAcMCAQAAAAHEAgEAAAABASIAAFIAMAEiAABSADANBAAAtwUAIAUAALgFACAXAAC7BQAgGQAAuQUAIBoAALoFACAbAAC8BQAgHAAAvQUAIPUBQADbAwAhhwIBANoDACGJAgAAtgXGAiKOAkAA2wMAIcMCAQDcAwAhxAIBANoDACECAAAAAQAgIgAAVQAgBvUBQADbAwAhhwIBANoDACGJAgAAtgXGAiKOAkAA2wMAIcMCAQDcAwAhxAIBANoDACECAAAAJgAgIgAAVwAgAgAAACYAICIAAFcAIAMAAAABACApAABQACAqAABVACABAAAAAQAgAQAAACYAIAQQAACzBQAgLwAAtQUAIDAAALQFACDDAgAA1gMAIAnlAQAAnAMAMOYBAABeABDnAQAAnAMAMPUBQADfAgAhhwIBANwCACGJAgAAnQPGAiKOAkAA3wIAIcMCAQDdAgAhxAIBANwCACEDAAAAJgAgAQAAXQAwLgAAXgAgAwAAACYAIAEAAEwAMAIAAAEAIAEAAAAFACABAAAABQAgAwAAAAMAIAEAAAQAMAIAAAUAIAMAAAADACABAAAEADACAAAFACADAAAAAwAgAQAABAAwAgAABQAgBQMAALIFACD1AUAAAAABhwIBAAAAAb8CAQAAAAHCAgAAAMICAgEiAABmACAE9QFAAAAAAYcCAQAAAAG_AgEAAAABwgIAAADCAgIBIgAAaAAwASIAAGgAMAUDAACxBQAg9QFAANsDACGHAgEA2gMAIb8CAQDaAwAhwgIAALAFwgIiAgAAAAUAICIAAGsAIAT1AUAA2wMAIYcCAQDaAwAhvwIBANoDACHCAgAAsAXCAiICAAAAAwAgIgAAbQAgAgAAAAMAICIAAG0AIAMAAAAFACApAABmACAqAABrACABAAAABQAgAQAAAAMAIAMQAACtBQAgLwAArwUAIDAAAK4FACAH5QEAAJgDADDmAQAAdAAQ5wEAAJgDADD1AUAA3wIAIYcCAQDcAgAhvwIBANwCACHCAgAAmQPCAiIDAAAAAwAgAQAAcwAwLgAAdAAgAwAAAAMAIAEAAAQAMAIAAAUAIAEAAAAJACABAAAACQAgAwAAAAcAIAEAAAgAMAIAAAkAIAMAAAAHACABAAAIADACAAAJACADAAAABwAgAQAACAAwAgAACQAgBQMAAKwFACD1AUAAAAABhwIBAAAAAb8CAQAAAAHAAgEAAAABASIAAHwAIAT1AUAAAAABhwIBAAAAAb8CAQAAAAHAAgEAAAABASIAAH4AMAEiAAB-ADAFAwAAqwUAIPUBQADbAwAhhwIBANoDACG_AgEA2gMAIcACAQDaAwAhAgAAAAkAICIAAIEBACAE9QFAANsDACGHAgEA2gMAIb8CAQDaAwAhwAIBANoDACECAAAABwAgIgAAgwEAIAIAAAAHACAiAACDAQAgAwAAAAkAICkAAHwAICoAAIEBACABAAAACQAgAQAAAAcAIAMQAACoBQAgLwAAqgUAIDAAAKkFACAH5QEAAJcDADDmAQAAigEAEOcBAACXAwAw9QFAAN8CACGHAgEA3AIAIb8CAQDcAgAhwAIBANwCACEDAAAABwAgAQAAiQEAMC4AAIoBACADAAAABwAgAQAACAAwAgAACQAgAQAAAA0AIAEAAAANACADAAAACwAgAQAADAAwAgAADQAgAwAAAAsAIAEAAAwAMAIAAA0AIAMAAAALACABAAAMADACAAANACANBgAAogUAIBEAAKcFACAVAACjBQAgFgAApAUAIBcAAKUFACAYAACmBQAg9QFAAAAAAYcCAQAAAAGJAgAAAL8CAo4CQAAAAAG7AgEAAAABvAIBAAAAAb0CAQAAAAEBIgAAkgEAIAf1AUAAAAABhwIBAAAAAYkCAAAAvwICjgJAAAAAAbsCAQAAAAG8AgEAAAABvQIBAAAAAQEiAACUAQAwASIAAJQBADANBgAA6QQAIBEAAO4EACAVAADqBAAgFgAA6wQAIBcAAOwEACAYAADtBAAg9QFAANsDACGHAgEA2gMAIYkCAADoBL8CIo4CQADbAwAhuwIBANoDACG8AgEA2gMAIb0CAQDaAwAhAgAAAA0AICIAAJcBACAH9QFAANsDACGHAgEA2gMAIYkCAADoBL8CIo4CQADbAwAhuwIBANoDACG8AgEA2gMAIb0CAQDaAwAhAgAAAAsAICIAAJkBACACAAAACwAgIgAAmQEAIAMAAAANACApAACSAQAgKgAAlwEAIAEAAAANACABAAAACwAgAxAAAOUEACAvAADnBAAgMAAA5gQAIArlAQAAkwMAMOYBAACgAQAQ5wEAAJMDADD1AUAA3wIAIYcCAQDcAgAhiQIAAJQDvwIijgJAAN8CACG7AgEA3AIAIbwCAQDcAgAhvQIBANwCACEDAAAACwAgAQAAnwEAMC4AAKABACADAAAACwAgAQAADAAwAgAADQAgAQAAABEAIAEAAAARACADAAAADwAgAQAAEAAwAgAAEQAgAwAAAA8AIAEAABAAMAIAABEAIAMAAAAPACABAAAQADACAAARACAMBwAA4AQAIAsAAOEEACARAADiBAAgEwAA4wQAIBQAAOQEACD1AUAAAAABhwIBAAAAAYkCAAAAugICjgJAAAAAAZoCAQAAAAG4AgIAAAABugKAAAAAAQEiAACoAQAgB_UBQAAAAAGHAgEAAAABiQIAAAC6AgKOAkAAAAABmgIBAAAAAbgCAgAAAAG6AoAAAAABASIAAKoBADABIgAAqgEAMAwHAACrBAAgCwAArAQAIBEAAK0EACATAACuBAAgFAAArwQAIPUBQADbAwAhhwIBANoDACGJAgAAqgS6AiKOAkAA2wMAIZoCAQDaAwAhuAICAJMEACG6AoAAAAABAgAAABEAICIAAK0BACAH9QFAANsDACGHAgEA2gMAIYkCAACqBLoCIo4CQADbAwAhmgIBANoDACG4AgIAkwQAIboCgAAAAAECAAAADwAgIgAArwEAIAIAAAAPACAiAACvAQAgAwAAABEAICkAAKgBACAqAACtAQAgAQAAABEAIAEAAAAPACAFEAAApQQAIC8AAKgEACAwAACnBAAgcQAApgQAIHIAAKkEACAK5QEAAI8DADDmAQAAtgEAEOcBAACPAwAw9QFAAN8CACGHAgEA3AIAIYkCAACQA7oCIo4CQADfAgAhmgIBANwCACG4AgIAgQMAIboCAADeAgAgAwAAAA8AIAEAALUBADAuAAC2AQAgAwAAAA8AIAEAABAAMAIAABEAIAEAAAAzACABAAAAMwAgAwAAADEAIAEAADIAMAIAADMAIAMAAAAxACABAAAyADACAAAzACADAAAAMQAgAQAAMgAwAgAAMwAgDAcAAKQEACD1AUAAAAABhwIBAAAAAYkCAAAAtwICjgJAAAAAAZoCAQAAAAGxAgEAAAABsgIBAAAAAbMCAQAAAAG0AgIAAAABtQIBAAAAAbcCgAAAAAEBIgAAvgEAIAv1AUAAAAABhwIBAAAAAYkCAAAAtwICjgJAAAAAAZoCAQAAAAGxAgEAAAABsgIBAAAAAbMCAQAAAAG0AgIAAAABtQIBAAAAAbcCgAAAAAEBIgAAwAEAMAEiAADAAQAwDAcAAKMEACD1AUAA2wMAIYcCAQDaAwAhiQIAAKIEtwIijgJAANsDACGaAgEA2gMAIbECAQDaAwAhsgIBANoDACGzAgEA2gMAIbQCAgCTBAAhtQIBANoDACG3AoAAAAABAgAAADMAICIAAMMBACAL9QFAANsDACGHAgEA2gMAIYkCAACiBLcCIo4CQADbAwAhmgIBANoDACGxAgEA2gMAIbICAQDaAwAhswIBANoDACG0AgIAkwQAIbUCAQDaAwAhtwKAAAAAAQIAAAAxACAiAADFAQAgAgAAADEAICIAAMUBACADAAAAMwAgKQAAvgEAICoAAMMBACABAAAAMwAgAQAAADEAIAYQAACdBAAgLwAAoAQAIDAAAJ8EACBxAACeBAAgcgAAoQQAILcCAADWAwAgDuUBAACJAwAw5gEAAMwBABDnAQAAiQMAMPUBQADfAgAhhwIBANwCACGJAgAAigO3AiKOAkAA3wIAIZoCAQDcAgAhsQIBANwCACGyAgEA3AIAIbMCAQDcAgAhtAICAIEDACG1AgEA3AIAIbcCAACLAwAgAwAAADEAIAEAAMsBADAuAADMAQAgAwAAADEAIAEAADIAMAIAADMAIAEAAAAVACABAAAAFQAgAwAAABMAIAEAABQAMAIAABUAIAMAAAATACABAAAUADACAAAVACADAAAAEwAgAQAAFAAwAgAAFQAgGwcAAJoEACAIAACZBAAgCQAAmwQAIAoAAJwEACDpAQEAAAAB9QFAAAAAAYcCAQAAAAGJAgAAAKYCAo4CQAAAAAGWAkAAAAABlwIBAAAAAZoCAQAAAAGeAgEAAAABoAIAAACuAgKhAgEAAAABowIBAAAAAaQCAQAAAAGmAgIAAAABpwICAAAAAagCQAAAAAGpAgEAAAABqgIBAAAAAasCQAAAAAGsAgIAAAABrgIBAAAAAa8CAQAAAAGwAoAAAAABASIAANQBACAX6QEBAAAAAfUBQAAAAAGHAgEAAAABiQIAAACmAgKOAkAAAAABlgJAAAAAAZcCAQAAAAGaAgEAAAABngIBAAAAAaACAAAArgICoQIBAAAAAaMCAQAAAAGkAgEAAAABpgICAAAAAacCAgAAAAGoAkAAAAABqQIBAAAAAaoCAQAAAAGrAkAAAAABrAICAAAAAa4CAQAAAAGvAgEAAAABsAKAAAAAAQEiAADWAQAwASIAANYBADABAAAACwAgAQAAAA8AIBsHAACWBAAgCAAAlQQAIAkAAJcEACAKAACYBAAg6QEBANwDACH1AUAA2wMAIYcCAQDaAwAhiQIAAJIEpgIijgJAANsDACGWAkAA5AMAIZcCAQDcAwAhmgIBANoDACGeAgEA2gMAIaACAACUBK4CIqECAQDaAwAhowIBANoDACGkAgEA2gMAIaYCAgCTBAAhpwICAJMEACGoAkAA5AMAIakCAQDcAwAhqgIBANwDACGrAkAA5AMAIawCAgCTBAAhrgIBANoDACGvAgEA3AMAIbACgAAAAAECAAAAFQAgIgAA2wEAIBfpAQEA3AMAIfUBQADbAwAhhwIBANoDACGJAgAAkgSmAiKOAkAA2wMAIZYCQADkAwAhlwIBANwDACGaAgEA2gMAIZ4CAQDaAwAhoAIAAJQErgIioQIBANoDACGjAgEA2gMAIaQCAQDaAwAhpgICAJMEACGnAgIAkwQAIagCQADkAwAhqQIBANwDACGqAgEA3AMAIasCQADkAwAhrAICAJMEACGuAgEA2gMAIa8CAQDcAwAhsAKAAAAAAQIAAAATACAiAADdAQAgAgAAABMAICIAAN0BACABAAAACwAgAQAAAA8AIAMAAAAVACApAADUAQAgKgAA2wEAIAEAAAAVACABAAAAEwAgDRAAAI0EACAvAACQBAAgMAAAjwQAIHEAAI4EACByAACRBAAg6QEAANYDACCWAgAA1gMAIJcCAADWAwAgqAIAANYDACCpAgAA1gMAIKoCAADWAwAgqwIAANYDACCvAgAA1gMAIBrlAQAA_wIAMOYBAADmAQAQ5wEAAP8CADDpAQEA3QIAIfUBQADfAgAhhwIBANwCACGJAgAAgAOmAiKOAkAA3wIAIZYCQADsAgAhlwIBAN0CACGaAgEA3AIAIZ4CAQDcAgAhoAIAAIIDrgIioQIBANwCACGjAgEA3AIAIaQCAQDcAgAhpgICAIEDACGnAgIAgQMAIagCQADsAgAhqQIBAN0CACGqAgEA3QIAIasCQADsAgAhrAICAIEDACGuAgEA3AIAIa8CAQDdAgAhsAIAAN4CACADAAAAEwAgAQAA5QEAMC4AAOYBACADAAAAEwAgAQAAFAAwAgAAFQAgAQAAAD8AIAEAAAA_ACADAAAAPQAgAQAAPgAwAgAAPwAgAwAAAD0AIAEAAD4AMAIAAD8AIAMAAAA9ACABAAA-ADACAAA_ACAICAAAjAQAIPUBQAAAAAGHAgEAAAABngIBAAAAAZ8CAQAAAAGgAgEAAAABoQIBAAAAAaICgAAAAAEBIgAA7gEAIAf1AUAAAAABhwIBAAAAAZ4CAQAAAAGfAgEAAAABoAIBAAAAAaECAQAAAAGiAoAAAAABASIAAPABADABIgAA8AEAMAgIAACLBAAg9QFAANsDACGHAgEA2gMAIZ4CAQDaAwAhnwIBANoDACGgAgEA2gMAIaECAQDaAwAhogKAAAAAAQIAAAA_ACAiAADzAQAgB_UBQADbAwAhhwIBANoDACGeAgEA2gMAIZ8CAQDaAwAhoAIBANoDACGhAgEA2gMAIaICgAAAAAECAAAAPQAgIgAA9QEAIAIAAAA9ACAiAAD1AQAgAwAAAD8AICkAAO4BACAqAADzAQAgAQAAAD8AIAEAAAA9ACADEAAAiAQAIC8AAIoEACAwAACJBAAgCuUBAAD-AgAw5gEAAPwBABDnAQAA_gIAMPUBQADfAgAhhwIBANwCACGeAgEA3AIAIZ8CAQDcAgAhoAIBANwCACGhAgEA3AIAIaICAADeAgAgAwAAAD0AIAEAAPsBADAuAAD8AQAgAwAAAD0AIAEAAD4AMAIAAD8AIAEAAAAbACABAAAAGwAgAwAAABkAIAEAABoAMAIAABsAIAMAAAAZACABAAAaADACAAAbACADAAAAGQAgAQAAGgAwAgAAGwAgDAcAAIUEACAMAACEBAAgDQAAhgQAIA8AAIcEACD1AUAAAAABhwIBAAAAAYkCAAAAnQICjgJAAAAAAZkCAQAAAAGaAgEAAAABmwIBAAAAAZ0CAQAAAAEBIgAAhAIAIAj1AUAAAAABhwIBAAAAAYkCAAAAnQICjgJAAAAAAZkCAQAAAAGaAgEAAAABmwIBAAAAAZ0CAQAAAAEBIgAAhgIAMAEiAACGAgAwDAcAAPUDACAMAAD0AwAgDQAA9gMAIA8AAPcDACD1AUAA2wMAIYcCAQDaAwAhiQIAAPMDnQIijgJAANsDACGZAgEA2gMAIZoCAQDaAwAhmwIBANoDACGdAgEA2gMAIQIAAAAbACAiAACJAgAgCPUBQADbAwAhhwIBANoDACGJAgAA8wOdAiKOAkAA2wMAIZkCAQDaAwAhmgIBANoDACGbAgEA2gMAIZ0CAQDaAwAhAgAAABkAICIAAIsCACACAAAAGQAgIgAAiwIAIAMAAAAbACApAACEAgAgKgAAiQIAIAEAAAAbACABAAAAGQAgAxAAAPADACAvAADyAwAgMAAA8QMAIAvlAQAA-gIAMOYBAACSAgAQ5wEAAPoCADD1AUAA3wIAIYcCAQDcAgAhiQIAAPsCnQIijgJAAN8CACGZAgEA3AIAIZoCAQDcAgAhmwIBANwCACGdAgEA3AIAIQMAAAAZACABAACRAgAwLgAAkgIAIAMAAAAZACABAAAaADACAAAbACABAAAAHwAgAQAAAB8AIAMAAAAdACABAAAeADACAAAfACADAAAAHQAgAQAAHgAwAgAAHwAgAwAAAB0AIAEAAB4AMAIAAB8AIA0OAADvAwAg9QFAAAAAAYcCAQAAAAGJAgAAAJYCAo4CQAAAAAGPAgEAAAABkQIAAACRAgKSAgEAAAABkwIBAAAAAZQCAQAAAAGWAkAAAAABlwIBAAAAAZgCAQAAAAEBIgAAmgIAIAz1AUAAAAABhwIBAAAAAYkCAAAAlgICjgJAAAAAAY8CAQAAAAGRAgAAAJECApICAQAAAAGTAgEAAAABlAIBAAAAAZYCQAAAAAGXAgEAAAABmAIBAAAAAQEiAACcAgAwASIAAJwCADANDgAA7gMAIPUBQADbAwAhhwIBANoDACGJAgAA7QOWAiKOAkAA2wMAIY8CAQDaAwAhkQIAAOwDkQIikgIBANoDACGTAgEA2gMAIZQCAQDcAwAhlgJAANsDACGXAgEA3AMAIZgCAQDaAwAhAgAAAB8AICIAAJ8CACAM9QFAANsDACGHAgEA2gMAIYkCAADtA5YCIo4CQADbAwAhjwIBANoDACGRAgAA7AORAiKSAgEA2gMAIZMCAQDaAwAhlAIBANwDACGWAkAA2wMAIZcCAQDcAwAhmAIBANoDACECAAAAHQAgIgAAoQIAIAIAAAAdACAiAAChAgAgAwAAAB8AICkAAJoCACAqAACfAgAgAQAAAB8AIAEAAAAdACAFEAAA6QMAIC8AAOsDACAwAADqAwAglAIAANYDACCXAgAA1gMAIA_lAQAA8wIAMOYBAACoAgAQ5wEAAPMCADD1AUAA3wIAIYcCAQDcAgAhiQIAAPUClgIijgJAAN8CACGPAgEA3AIAIZECAAD0ApECIpICAQDcAgAhkwIBANwCACGUAgEA3QIAIZYCQADfAgAhlwIBAN0CACGYAgEA3AIAIQMAAAAdACABAACnAgAwLgAAqAIAIAMAAAAdACABAAAeADACAAAfACABAAAAJAAgAQAAACQAIAMAAAAiACABAAAjADACAAAkACADAAAAIgAgAQAAIwAwAgAAJAAgAwAAACIAIAEAACMAMAIAACQAIAsKAADnAwAgEgAA6AMAIOkBAQAAAAHxAQEAAAAB9QFAAAAAAYcCAQAAAAGJAgAAAIkCAosCAAAAiwIDjAIBAAAAAY0CQAAAAAGOAkAAAAABASIAALACACAJ6QEBAAAAAfEBAQAAAAH1AUAAAAABhwIBAAAAAYkCAAAAiQICiwIAAACLAgOMAgEAAAABjQJAAAAAAY4CQAAAAAEBIgAAsgIAMAEiAACyAgAwAQAAACYAIAsKAADlAwAgEgAA5gMAIOkBAQDaAwAh8QEBANwDACH1AUAA2wMAIYcCAQDaAwAhiQIAAOIDiQIiiwIAAOMDiwIjjAIBANwDACGNAkAA5AMAIY4CQADbAwAhAgAAACQAICIAALYCACAJ6QEBANoDACHxAQEA3AMAIfUBQADbAwAhhwIBANoDACGJAgAA4gOJAiKLAgAA4wOLAiOMAgEA3AMAIY0CQADkAwAhjgJAANsDACECAAAAIgAgIgAAuAIAIAIAAAAiACAiAAC4AgAgAQAAACYAIAMAAAAkACApAACwAgAgKgAAtgIAIAEAAAAkACABAAAAIgAgBxAAAN8DACAvAADhAwAgMAAA4AMAIPEBAADWAwAgiwIAANYDACCMAgAA1gMAII0CAADWAwAgDOUBAADpAgAw5gEAAMACABDnAQAA6QIAMOkBAQDcAgAh8QEBAN0CACH1AUAA3wIAIYcCAQDcAgAhiQIAAOoCiQIiiwIAAOsCiwIjjAIBAN0CACGNAkAA7AIAIY4CQADfAgAhAwAAACIAIAEAAL8CADAuAADAAgAgAwAAACIAIAEAACMAMAIAACQAIAEAAAAqACABAAAAKgAgAwAAACgAIAEAACkAMAIAACoAIAMAAAAoACABAAApADACAAAqACADAAAAKAAgAQAAKQAwAgAAKgAgDwoAAN4DACDoAQEAAAAB6QEBAAAAAeoBAQAAAAHrAQEAAAAB7AEBAAAAAe0BgAAAAAHuAQEAAAAB7wGAAAAAAfABAQAAAAHxAQEAAAAB8gFAAAAAAfMBAQAAAAH0AYAAAAAB9QFAAAAAAQEiAADIAgAgDugBAQAAAAHpAQEAAAAB6gEBAAAAAesBAQAAAAHsAQEAAAAB7QGAAAAAAe4BAQAAAAHvAYAAAAAB8AEBAAAAAfEBAQAAAAHyAUAAAAAB8wEBAAAAAfQBgAAAAAH1AUAAAAABASIAAMoCADABIgAAygIAMAEAAAAPACAPCgAA3QMAIOgBAQDaAwAh6QEBANwDACHqAQEA2gMAIesBAQDaAwAh7AEBANoDACHtAYAAAAAB7gEBANoDACHvAYAAAAAB8AEBANoDACHxAQEA2gMAIfIBQADbAwAh8wEBANoDACH0AYAAAAAB9QFAANsDACECAAAAKgAgIgAAzgIAIA7oAQEA2gMAIekBAQDcAwAh6gEBANoDACHrAQEA2gMAIewBAQDaAwAh7QGAAAAAAe4BAQDaAwAh7wGAAAAAAfABAQDaAwAh8QEBANoDACHyAUAA2wMAIfMBAQDaAwAh9AGAAAAAAfUBQADbAwAhAgAAACgAICIAANACACACAAAAKAAgIgAA0AIAIAEAAAAPACADAAAAKgAgKQAAyAIAICoAAM4CACABAAAAKgAgAQAAACgAIAQQAADXAwAgLwAA2QMAIDAAANgDACDpAQAA1gMAIBHlAQAA2wIAMOYBAADYAgAQ5wEAANsCADDoAQEA3AIAIekBAQDdAgAh6gEBANwCACHrAQEA3AIAIewBAQDcAgAh7QEAAN4CACDuAQEA3AIAIe8BAADeAgAg8AEBANwCACHxAQEA3AIAIfIBQADfAgAh8wEBANwCACH0AQAA3gIAIPUBQADfAgAhAwAAACgAIAEAANcCADAuAADYAgAgAwAAACgAIAEAACkAMAIAACoAIBHlAQAA2wIAMOYBAADYAgAQ5wEAANsCADDoAQEA3AIAIekBAQDdAgAh6gEBANwCACHrAQEA3AIAIewBAQDcAgAh7QEAAN4CACDuAQEA3AIAIe8BAADeAgAg8AEBANwCACHxAQEA3AIAIfIBQADfAgAh8wEBANwCACH0AQAA3gIAIPUBQADfAgAhDhAAAOECACAvAADoAgAgMAAA6AIAIPYBAQAAAAH3AQEAAAAE-AEBAAAABPkBAQAAAAH6AQEAAAAB-wEBAAAAAfwBAQAAAAH9AQEA5wIAIYQCAQAAAAGFAgEAAAABhgIBAAAAAQ4QAADlAgAgLwAA5gIAIDAAAOYCACD2AQEAAAAB9wEBAAAABfgBAQAAAAX5AQEAAAAB-gEBAAAAAfsBAQAAAAH8AQEAAAAB_QEBAOQCACGEAgEAAAABhQIBAAAAAYYCAQAAAAEPEAAA4QIAIC8AAOMCACAwAADjAgAg9gGAAAAAAfkBgAAAAAH6AYAAAAAB-wGAAAAAAfwBgAAAAAH9AYAAAAAB_gEBAAAAAf8BAQAAAAGAAgEAAAABgQKAAAAAAYICgAAAAAGDAoAAAAABCxAAAOECACAvAADiAgAgMAAA4gIAIPYBQAAAAAH3AUAAAAAE-AFAAAAABPkBQAAAAAH6AUAAAAAB-wFAAAAAAfwBQAAAAAH9AUAA4AIAIQsQAADhAgAgLwAA4gIAIDAAAOICACD2AUAAAAAB9wFAAAAABPgBQAAAAAT5AUAAAAAB-gFAAAAAAfsBQAAAAAH8AUAAAAAB_QFAAOACACEI9gECAAAAAfcBAgAAAAT4AQIAAAAE-QECAAAAAfoBAgAAAAH7AQIAAAAB_AECAAAAAf0BAgDhAgAhCPYBQAAAAAH3AUAAAAAE-AFAAAAABPkBQAAAAAH6AUAAAAAB-wFAAAAAAfwBQAAAAAH9AUAA4gIAIQz2AYAAAAAB-QGAAAAAAfoBgAAAAAH7AYAAAAAB_AGAAAAAAf0BgAAAAAH-AQEAAAAB_wEBAAAAAYACAQAAAAGBAoAAAAABggKAAAAAAYMCgAAAAAEOEAAA5QIAIC8AAOYCACAwAADmAgAg9gEBAAAAAfcBAQAAAAX4AQEAAAAF-QEBAAAAAfoBAQAAAAH7AQEAAAAB_AEBAAAAAf0BAQDkAgAhhAIBAAAAAYUCAQAAAAGGAgEAAAABCPYBAgAAAAH3AQIAAAAF-AECAAAABfkBAgAAAAH6AQIAAAAB-wECAAAAAfwBAgAAAAH9AQIA5QIAIQv2AQEAAAAB9wEBAAAABfgBAQAAAAX5AQEAAAAB-gEBAAAAAfsBAQAAAAH8AQEAAAAB_QEBAOYCACGEAgEAAAABhQIBAAAAAYYCAQAAAAEOEAAA4QIAIC8AAOgCACAwAADoAgAg9gEBAAAAAfcBAQAAAAT4AQEAAAAE-QEBAAAAAfoBAQAAAAH7AQEAAAAB_AEBAAAAAf0BAQDnAgAhhAIBAAAAAYUCAQAAAAGGAgEAAAABC_YBAQAAAAH3AQEAAAAE-AEBAAAABPkBAQAAAAH6AQEAAAAB-wEBAAAAAfwBAQAAAAH9AQEA6AIAIYQCAQAAAAGFAgEAAAABhgIBAAAAAQzlAQAA6QIAMOYBAADAAgAQ5wEAAOkCADDpAQEA3AIAIfEBAQDdAgAh9QFAAN8CACGHAgEA3AIAIYkCAADqAokCIosCAADrAosCI4wCAQDdAgAhjQJAAOwCACGOAkAA3wIAIQcQAADhAgAgLwAA8gIAIDAAAPICACD2AQAAAIkCAvcBAAAAiQII-AEAAACJAgj9AQAA8QKJAiIHEAAA5QIAIC8AAPACACAwAADwAgAg9gEAAACLAgP3AQAAAIsCCfgBAAAAiwIJ_QEAAO8CiwIjCxAAAOUCACAvAADuAgAgMAAA7gIAIPYBQAAAAAH3AUAAAAAF-AFAAAAABfkBQAAAAAH6AUAAAAAB-wFAAAAAAfwBQAAAAAH9AUAA7QIAIQsQAADlAgAgLwAA7gIAIDAAAO4CACD2AUAAAAAB9wFAAAAABfgBQAAAAAX5AUAAAAAB-gFAAAAAAfsBQAAAAAH8AUAAAAAB_QFAAO0CACEI9gFAAAAAAfcBQAAAAAX4AUAAAAAF-QFAAAAAAfoBQAAAAAH7AUAAAAAB_AFAAAAAAf0BQADuAgAhBxAAAOUCACAvAADwAgAgMAAA8AIAIPYBAAAAiwID9wEAAACLAgn4AQAAAIsCCf0BAADvAosCIwT2AQAAAIsCA_cBAAAAiwIJ-AEAAACLAgn9AQAA8AKLAiMHEAAA4QIAIC8AAPICACAwAADyAgAg9gEAAACJAgL3AQAAAIkCCPgBAAAAiQII_QEAAPECiQIiBPYBAAAAiQIC9wEAAACJAgj4AQAAAIkCCP0BAADyAokCIg_lAQAA8wIAMOYBAACoAgAQ5wEAAPMCADD1AUAA3wIAIYcCAQDcAgAhiQIAAPUClgIijgJAAN8CACGPAgEA3AIAIZECAAD0ApECIpICAQDcAgAhkwIBANwCACGUAgEA3QIAIZYCQADfAgAhlwIBAN0CACGYAgEA3AIAIQcQAADhAgAgLwAA-QIAIDAAAPkCACD2AQAAAJECAvcBAAAAkQII-AEAAACRAgj9AQAA-AKRAiIHEAAA4QIAIC8AAPcCACAwAAD3AgAg9gEAAACWAgL3AQAAAJYCCPgBAAAAlgII_QEAAPYClgIiBxAAAOECACAvAAD3AgAgMAAA9wIAIPYBAAAAlgIC9wEAAACWAgj4AQAAAJYCCP0BAAD2ApYCIgT2AQAAAJYCAvcBAAAAlgII-AEAAACWAgj9AQAA9wKWAiIHEAAA4QIAIC8AAPkCACAwAAD5AgAg9gEAAACRAgL3AQAAAJECCPgBAAAAkQII_QEAAPgCkQIiBPYBAAAAkQIC9wEAAACRAgj4AQAAAJECCP0BAAD5ApECIgvlAQAA-gIAMOYBAACSAgAQ5wEAAPoCADD1AUAA3wIAIYcCAQDcAgAhiQIAAPsCnQIijgJAAN8CACGZAgEA3AIAIZoCAQDcAgAhmwIBANwCACGdAgEA3AIAIQcQAADhAgAgLwAA_QIAIDAAAP0CACD2AQAAAJ0CAvcBAAAAnQII-AEAAACdAgj9AQAA_AKdAiIHEAAA4QIAIC8AAP0CACAwAAD9AgAg9gEAAACdAgL3AQAAAJ0CCPgBAAAAnQII_QEAAPwCnQIiBPYBAAAAnQIC9wEAAACdAgj4AQAAAJ0CCP0BAAD9Ap0CIgrlAQAA_gIAMOYBAAD8AQAQ5wEAAP4CADD1AUAA3wIAIYcCAQDcAgAhngIBANwCACGfAgEA3AIAIaACAQDcAgAhoQIBANwCACGiAgAA3gIAIBrlAQAA_wIAMOYBAADmAQAQ5wEAAP8CADDpAQEA3QIAIfUBQADfAgAhhwIBANwCACGJAgAAgAOmAiKOAkAA3wIAIZYCQADsAgAhlwIBAN0CACGaAgEA3AIAIZ4CAQDcAgAhoAIAAIIDrgIioQIBANwCACGjAgEA3AIAIaQCAQDcAgAhpgICAIEDACGnAgIAgQMAIagCQADsAgAhqQIBAN0CACGqAgEA3QIAIasCQADsAgAhrAICAIEDACGuAgEA3AIAIa8CAQDdAgAhsAIAAN4CACAHEAAA4QIAIC8AAIgDACAwAACIAwAg9gEAAACmAgL3AQAAAKYCCPgBAAAApgII_QEAAIcDpgIiDRAAAOECACAvAADhAgAgMAAA4QIAIHEAAIYDACByAADhAgAg9gECAAAAAfcBAgAAAAT4AQIAAAAE-QECAAAAAfoBAgAAAAH7AQIAAAAB_AECAAAAAf0BAgCFAwAhBxAAAOECACAvAACEAwAgMAAAhAMAIPYBAAAArgIC9wEAAACuAgj4AQAAAK4CCP0BAACDA64CIgcQAADhAgAgLwAAhAMAIDAAAIQDACD2AQAAAK4CAvcBAAAArgII-AEAAACuAgj9AQAAgwOuAiIE9gEAAACuAgL3AQAAAK4CCPgBAAAArgII_QEAAIQDrgIiDRAAAOECACAvAADhAgAgMAAA4QIAIHEAAIYDACByAADhAgAg9gECAAAAAfcBAgAAAAT4AQIAAAAE-QECAAAAAfoBAgAAAAH7AQIAAAAB_AECAAAAAf0BAgCFAwAhCPYBCAAAAAH3AQgAAAAE-AEIAAAABPkBCAAAAAH6AQgAAAAB-wEIAAAAAfwBCAAAAAH9AQgAhgMAIQcQAADhAgAgLwAAiAMAIDAAAIgDACD2AQAAAKYCAvcBAAAApgII-AEAAACmAgj9AQAAhwOmAiIE9gEAAACmAgL3AQAAAKYCCPgBAAAApgII_QEAAIgDpgIiDuUBAACJAwAw5gEAAMwBABDnAQAAiQMAMPUBQADfAgAhhwIBANwCACGJAgAAigO3AiKOAkAA3wIAIZoCAQDcAgAhsQIBANwCACGyAgEA3AIAIbMCAQDcAgAhtAICAIEDACG1AgEA3AIAIbcCAACLAwAgBxAAAOECACAvAACOAwAgMAAAjgMAIPYBAAAAtwIC9wEAAAC3Agj4AQAAALcCCP0BAACNA7cCIg8QAADlAgAgLwAAjAMAIDAAAIwDACD2AYAAAAAB-QGAAAAAAfoBgAAAAAH7AYAAAAAB_AGAAAAAAf0BgAAAAAH-AQEAAAAB_wEBAAAAAYACAQAAAAGBAoAAAAABggKAAAAAAYMCgAAAAAEM9gGAAAAAAfkBgAAAAAH6AYAAAAAB-wGAAAAAAfwBgAAAAAH9AYAAAAAB_gEBAAAAAf8BAQAAAAGAAgEAAAABgQKAAAAAAYICgAAAAAGDAoAAAAABBxAAAOECACAvAACOAwAgMAAAjgMAIPYBAAAAtwIC9wEAAAC3Agj4AQAAALcCCP0BAACNA7cCIgT2AQAAALcCAvcBAAAAtwII-AEAAAC3Agj9AQAAjgO3AiIK5QEAAI8DADDmAQAAtgEAEOcBAACPAwAw9QFAAN8CACGHAgEA3AIAIYkCAACQA7oCIo4CQADfAgAhmgIBANwCACG4AgIAgQMAIboCAADeAgAgBxAAAOECACAvAACSAwAgMAAAkgMAIPYBAAAAugIC9wEAAAC6Agj4AQAAALoCCP0BAACRA7oCIgcQAADhAgAgLwAAkgMAIDAAAJIDACD2AQAAALoCAvcBAAAAugII-AEAAAC6Agj9AQAAkQO6AiIE9gEAAAC6AgL3AQAAALoCCPgBAAAAugII_QEAAJIDugIiCuUBAACTAwAw5gEAAKABABDnAQAAkwMAMPUBQADfAgAhhwIBANwCACGJAgAAlAO_AiKOAkAA3wIAIbsCAQDcAgAhvAIBANwCACG9AgEA3AIAIQcQAADhAgAgLwAAlgMAIDAAAJYDACD2AQAAAL8CAvcBAAAAvwII-AEAAAC_Agj9AQAAlQO_AiIHEAAA4QIAIC8AAJYDACAwAACWAwAg9gEAAAC_AgL3AQAAAL8CCPgBAAAAvwII_QEAAJUDvwIiBPYBAAAAvwIC9wEAAAC_Agj4AQAAAL8CCP0BAACWA78CIgflAQAAlwMAMOYBAACKAQAQ5wEAAJcDADD1AUAA3wIAIYcCAQDcAgAhvwIBANwCACHAAgEA3AIAIQflAQAAmAMAMOYBAAB0ABDnAQAAmAMAMPUBQADfAgAhhwIBANwCACG_AgEA3AIAIcICAACZA8ICIgcQAADhAgAgLwAAmwMAIDAAAJsDACD2AQAAAMICAvcBAAAAwgII-AEAAADCAgj9AQAAmgPCAiIHEAAA4QIAIC8AAJsDACAwAACbAwAg9gEAAADCAgL3AQAAAMICCPgBAAAAwgII_QEAAJoDwgIiBPYBAAAAwgIC9wEAAADCAgj4AQAAAMICCP0BAACbA8ICIgnlAQAAnAMAMOYBAABeABDnAQAAnAMAMPUBQADfAgAhhwIBANwCACGJAgAAnQPGAiKOAkAA3wIAIcMCAQDdAgAhxAIBANwCACEHEAAA4QIAIC8AAJ8DACAwAACfAwAg9gEAAADGAgL3AQAAAMYCCPgBAAAAxgII_QEAAJ4DxgIiBxAAAOECACAvAACfAwAgMAAAnwMAIPYBAAAAxgIC9wEAAADGAgj4AQAAAMYCCP0BAACeA8YCIgT2AQAAAMYCAvcBAAAAxgII-AEAAADGAgj9AQAAnwPGAiILCAAApAMAIOUBAACgAwAw5gEAAD0AEOcBAACgAwAw9QFAAKMDACGHAgEAoQMAIZ4CAQChAwAhnwIBAKEDACGgAgEAoQMAIaECAQChAwAhogIAAKIDACAL9gEBAAAAAfcBAQAAAAT4AQEAAAAE-QEBAAAAAfoBAQAAAAH7AQEAAAAB_AEBAAAAAf0BAQDoAgAhhAIBAAAAAYUCAQAAAAGGAgEAAAABDPYBgAAAAAH5AYAAAAAB-gGAAAAAAfsBgAAAAAH8AYAAAAAB_QGAAAAAAf4BAQAAAAH_AQEAAAABgAIBAAAAAYECgAAAAAGCAoAAAAABgwKAAAAAAQj2AUAAAAAB9wFAAAAABPgBQAAAAAT5AUAAAAAB-gFAAAAAAfsBQAAAAAH8AUAAAAAB_QFAAOICACESBAAAsAMAIAUAALEDACAXAAC0AwAgGQAAsgMAIBoAALMDACAbAAC1AwAgHAAAtgMAIOUBAACuAwAw5gEAACYAEOcBAACuAwAw9QFAAKMDACGHAgEAoQMAIYkCAACvA8YCIo4CQACjAwAhwwIBAKwDACHEAgEAoQMAIc4CAAAmACDPAgAAJgAgApoCAQAAAAGyAgEAAAABDwcAAKoDACDlAQAApgMAMOYBAAAxABDnAQAApgMAMPUBQACjAwAhhwIBAKEDACGJAgAAqAO3AiKOAkAAowMAIZoCAQChAwAhsQIBAKEDACGyAgEAoQMAIbMCAQChAwAhtAICAKcDACG1AgEAoQMAIbcCAACpAwAgCPYBAgAAAAH3AQIAAAAE-AECAAAABPkBAgAAAAH6AQIAAAAB-wECAAAAAfwBAgAAAAH9AQIA4QIAIQT2AQAAALcCAvcBAAAAtwII-AEAAAC3Agj9AQAAjgO3AiIM9gGAAAAAAfkBgAAAAAH6AYAAAAAB-wGAAAAAAfwBgAAAAAH9AYAAAAAB_gEBAAAAAf8BAQAAAAGAAgEAAAABgQKAAAAAAYICgAAAAAGDAoAAAAABEgYAAKQDACARAAC1AwAgFQAA0AMAIBYAANEDACAXAAC0AwAgGAAAtAMAIOUBAADOAwAw5gEAAAsAEOcBAADOAwAw9QFAAKMDACGHAgEAoQMAIYkCAADPA78CIo4CQACjAwAhuwIBAKEDACG8AgEAoQMAIb0CAQChAwAhzgIAAAsAIM8CAAALACASCgAArQMAIOUBAACrAwAw5gEAACgAEOcBAACrAwAw6AEBAKEDACHpAQEArAMAIeoBAQChAwAh6wEBAKEDACHsAQEAoQMAIe0BAACiAwAg7gEBAKEDACHvAQAAogMAIPABAQChAwAh8QEBAKEDACHyAUAAowMAIfMBAQChAwAh9AEAAKIDACD1AUAAowMAIQv2AQEAAAAB9wEBAAAABfgBAQAAAAX5AQEAAAAB-gEBAAAAAfsBAQAAAAH8AQEAAAAB_QEBAOYCACGEAgEAAAABhQIBAAAAAYYCAQAAAAERBwAAqgMAIAsAALQDACARAAC1AwAgEwAAtgMAIBQAAM0DACDlAQAAywMAMOYBAAAPABDnAQAAywMAMPUBQACjAwAhhwIBAKEDACGJAgAAzAO6AiKOAkAAowMAIZoCAQChAwAhuAICAKcDACG6AgAAogMAIM4CAAAPACDPAgAADwAgEAQAALADACAFAACxAwAgFwAAtAMAIBkAALIDACAaAACzAwAgGwAAtQMAIBwAALYDACDlAQAArgMAMOYBAAAmABDnAQAArgMAMPUBQACjAwAhhwIBAKEDACGJAgAArwPGAiKOAkAAowMAIcMCAQCsAwAhxAIBAKEDACEE9gEAAADGAgL3AQAAAMYCCPgBAAAAxgII_QEAAJ8DxgIiA8cCAAADACDIAgAAAwAgyQIAAAMAIAPHAgAABwAgyAIAAAcAIMkCAAAHACADxwIAAAsAIMgCAAALACDJAgAACwAgA8cCAAA9ACDIAgAAPQAgyQIAAD0AIAPHAgAAEwAgyAIAABMAIMkCAAATACADxwIAABkAIMgCAAAZACDJAgAAGQAgA8cCAAAiACDIAgAAIgAgyQIAACIAIA4KAAC7AwAgEgAAvAMAIOUBAAC3AwAw5gEAACIAEOcBAAC3AwAw6QEBAKEDACHxAQEArAMAIfUBQACjAwAhhwIBAKEDACGJAgAAuAOJAiKLAgAAuQOLAiOMAgEArAMAIY0CQAC6AwAhjgJAAKMDACEE9gEAAACJAgL3AQAAAIkCCPgBAAAAiQII_QEAAPICiQIiBPYBAAAAiwID9wEAAACLAgn4AQAAAIsCCf0BAADwAosCIwj2AUAAAAAB9wFAAAAABfgBQAAAAAX5AUAAAAAB-gFAAAAAAfsBQAAAAAH8AUAAAAAB_QFAAO4CACERBwAAqgMAIAsAALQDACARAAC1AwAgEwAAtgMAIBQAAM0DACDlAQAAywMAMOYBAAAPABDnAQAAywMAMPUBQACjAwAhhwIBAKEDACGJAgAAzAO6AiKOAkAAowMAIZoCAQChAwAhuAICAKcDACG6AgAAogMAIM4CAAAPACDPAgAADwAgEgQAALADACAFAACxAwAgFwAAtAMAIBkAALIDACAaAACzAwAgGwAAtQMAIBwAALYDACDlAQAArgMAMOYBAAAmABDnAQAArgMAMPUBQACjAwAhhwIBAKEDACGJAgAArwPGAiKOAkAAowMAIcMCAQCsAwAhxAIBAKEDACHOAgAAJgAgzwIAACYAIBAOAADAAwAg5QEAAL0DADDmAQAAHQAQ5wEAAL0DADD1AUAAowMAIYcCAQChAwAhiQIAAL8DlgIijgJAAKMDACGPAgEAoQMAIZECAAC-A5ECIpICAQChAwAhkwIBAKEDACGUAgEArAMAIZYCQACjAwAhlwIBAKwDACGYAgEAoQMAIQT2AQAAAJECAvcBAAAAkQII-AEAAACRAgj9AQAA-QKRAiIE9gEAAACWAgL3AQAAAJYCCPgBAAAAlgII_QEAAPcClgIiEQcAAKoDACAMAACkAwAgDQAAuwMAIA8AAMMDACDlAQAAwQMAMOYBAAAZABDnAQAAwQMAMPUBQACjAwAhhwIBAKEDACGJAgAAwgOdAiKOAkAAowMAIZkCAQChAwAhmgIBAKEDACGbAgEAoQMAIZ0CAQChAwAhzgIAABkAIM8CAAAZACAPBwAAqgMAIAwAAKQDACANAAC7AwAgDwAAwwMAIOUBAADBAwAw5gEAABkAEOcBAADBAwAw9QFAAKMDACGHAgEAoQMAIYkCAADCA50CIo4CQACjAwAhmQIBAKEDACGaAgEAoQMAIZsCAQChAwAhnQIBAKEDACEE9gEAAACdAgL3AQAAAJ0CCPgBAAAAnQII_QEAAP0CnQIiA8cCAAAdACDIAgAAHQAgyQIAAB0AIAWaAgEAAAABngIBAAAAAaMCAQAAAAGkAgEAAAABrgIBAAAAAR4HAACqAwAgCAAApAMAIAkAAMgDACAKAACtAwAg5QEAAMUDADDmAQAAEwAQ5wEAAMUDADDpAQEArAMAIfUBQACjAwAhhwIBAKEDACGJAgAAxgOmAiKOAkAAowMAIZYCQAC6AwAhlwIBAKwDACGaAgEAoQMAIZ4CAQChAwAhoAIAAMcDrgIioQIBAKEDACGjAgEAoQMAIaQCAQChAwAhpgICAKcDACGnAgIApwMAIagCQAC6AwAhqQIBAKwDACGqAgEArAMAIasCQAC6AwAhrAICAKcDACGuAgEAoQMAIa8CAQCsAwAhsAIAAKIDACAE9gEAAACmAgL3AQAAAKYCCPgBAAAApgII_QEAAIgDpgIiBPYBAAAArgIC9wEAAACuAgj4AQAAAK4CCP0BAACEA64CIhIGAACkAwAgEQAAtQMAIBUAANADACAWAADRAwAgFwAAtAMAIBgAALQDACDlAQAAzgMAMOYBAAALABDnAQAAzgMAMPUBQACjAwAhhwIBAKEDACGJAgAAzwO_AiKOAkAAowMAIbsCAQChAwAhvAIBAKEDACG9AgEAoQMAIc4CAAALACDPAgAACwAgApoCAQAAAAG4AgIAAAABAocCAQAAAAGaAgEAAAABDwcAAKoDACALAAC0AwAgEQAAtQMAIBMAALYDACAUAADNAwAg5QEAAMsDADDmAQAADwAQ5wEAAMsDADD1AUAAowMAIYcCAQChAwAhiQIAAMwDugIijgJAAKMDACGaAgEAoQMAIbgCAgCnAwAhugIAAKIDACAE9gEAAAC6AgL3AQAAALoCCPgBAAAAugII_QEAAJIDugIiA8cCAAAoACDIAgAAKAAgyQIAACgAIBAGAACkAwAgEQAAtQMAIBUAANADACAWAADRAwAgFwAAtAMAIBgAALQDACDlAQAAzgMAMOYBAAALABDnAQAAzgMAMPUBQACjAwAhhwIBAKEDACGJAgAAzwO_AiKOAkAAowMAIbsCAQChAwAhvAIBAKEDACG9AgEAoQMAIQT2AQAAAL8CAvcBAAAAvwII-AEAAAC_Agj9AQAAlgO_AiIDxwIAAA8AIMgCAAAPACDJAgAADwAgA8cCAAAxACDIAgAAMQAgyQIAADEAIAgDAACkAwAg5QEAANIDADDmAQAABwAQ5wEAANIDADD1AUAAowMAIYcCAQChAwAhvwIBAKEDACHAAgEAoQMAIQK_AgEAAAABwgIAAADCAgIIAwAApAMAIOUBAADUAwAw5gEAAAMAEOcBAADUAwAw9QFAAKMDACGHAgEAoQMAIb8CAQChAwAhwgIAANUDwgIiBPYBAAAAwgIC9wEAAADCAgj4AQAAAMICCP0BAACbA8ICIgAAAAAB0wIBAAAAAQHTAkAAAAABAdMCAQAAAAEHKQAAgAcAICoAAIMHACDQAgAAgQcAINECAACCBwAg1AIAAA8AINUCAAAPACDWAgAAEQAgAykAAIAHACDQAgAAgQcAINYCAAARACAAAAAB0wIAAACJAgIB0wIAAACLAgMB0wJAAAAAAQUpAAD4BgAgKgAA_gYAINACAAD5BgAg0QIAAP0GACDWAgAAEQAgBykAAPYGACAqAAD7BgAg0AIAAPcGACDRAgAA-gYAINQCAAAmACDVAgAAJgAg1gIAAAEAIAMpAAD4BgAg0AIAAPkGACDWAgAAEQAgAykAAPYGACDQAgAA9wYAINYCAAABACAAAAAB0wIAAACRAgIB0wIAAACWAgIFKQAA8QYAICoAAPQGACDQAgAA8gYAINECAADzBgAg1gIAABsAIAMpAADxBgAg0AIAAPIGACDWAgAAGwAgAAAAAdMCAAAAnQICBSkAAOUGACAqAADvBgAg0AIAAOYGACDRAgAA7gYAINYCAAABACAFKQAA4wYAICoAAOwGACDQAgAA5AYAINECAADrBgAg1gIAAA0AIAUpAADhBgAgKgAA6QYAINACAADiBgAg0QIAAOgGACDWAgAAEQAgCykAAPgDADAqAAD9AwAw0AIAAPkDADDRAgAA-gMAMNICAAD7AwAg0wIAAPwDADDUAgAA_AMAMNUCAAD8AwAw1gIAAPwDADDXAgAA_gMAMNgCAAD_AwAwC_UBQAAAAAGHAgEAAAABiQIAAACWAgKOAkAAAAABkQIAAACRAgKSAgEAAAABkwIBAAAAAZQCAQAAAAGWAkAAAAABlwIBAAAAAZgCAQAAAAECAAAAHwAgKQAAgwQAIAMAAAAfACApAACDBAAgKgAAggQAIAEiAADnBgAwEA4AAMADACDlAQAAvQMAMOYBAAAdABDnAQAAvQMAMPUBQACjAwAhhwIBAAAAAYkCAAC_A5YCIo4CQACjAwAhjwIBAKEDACGRAgAAvgORAiKSAgEAoQMAIZMCAQChAwAhlAIBAKwDACGWAkAAowMAIZcCAQCsAwAhmAIBAKEDACECAAAAHwAgIgAAggQAIAIAAACABAAgIgAAgQQAIA_lAQAA_wMAMOYBAACABAAQ5wEAAP8DADD1AUAAowMAIYcCAQChAwAhiQIAAL8DlgIijgJAAKMDACGPAgEAoQMAIZECAAC-A5ECIpICAQChAwAhkwIBAKEDACGUAgEArAMAIZYCQACjAwAhlwIBAKwDACGYAgEAoQMAIQ_lAQAA_wMAMOYBAACABAAQ5wEAAP8DADD1AUAAowMAIYcCAQChAwAhiQIAAL8DlgIijgJAAKMDACGPAgEAoQMAIZECAAC-A5ECIpICAQChAwAhkwIBAKEDACGUAgEArAMAIZYCQACjAwAhlwIBAKwDACGYAgEAoQMAIQv1AUAA2wMAIYcCAQDaAwAhiQIAAO0DlgIijgJAANsDACGRAgAA7AORAiKSAgEA2gMAIZMCAQDaAwAhlAIBANwDACGWAkAA2wMAIZcCAQDcAwAhmAIBANoDACEL9QFAANsDACGHAgEA2gMAIYkCAADtA5YCIo4CQADbAwAhkQIAAOwDkQIikgIBANoDACGTAgEA2gMAIZQCAQDcAwAhlgJAANsDACGXAgEA3AMAIZgCAQDaAwAhC_UBQAAAAAGHAgEAAAABiQIAAACWAgKOAkAAAAABkQIAAACRAgKSAgEAAAABkwIBAAAAAZQCAQAAAAGWAkAAAAABlwIBAAAAAZgCAQAAAAEDKQAA5QYAINACAADmBgAg1gIAAAEAIAMpAADjBgAg0AIAAOQGACDWAgAADQAgAykAAOEGACDQAgAA4gYAINYCAAARACAEKQAA-AMAMNACAAD5AwAw0gIAAPsDACDWAgAA_AMAMAAAAAUpAADcBgAgKgAA3wYAINACAADdBgAg0QIAAN4GACDWAgAAAQAgAykAANwGACDQAgAA3QYAINYCAAABACAAAAAAAAHTAgAAAKYCAgXTAgIAAAAB2QICAAAAAdoCAgAAAAHbAgIAAAAB3AICAAAAAQHTAgAAAK4CAgUpAADOBgAgKgAA2gYAINACAADPBgAg0QIAANkGACDWAgAAAQAgBSkAAMwGACAqAADXBgAg0AIAAM0GACDRAgAA1gYAINYCAAANACAHKQAAygYAICoAANQGACDQAgAAywYAINECAADTBgAg1AIAAAsAINUCAAALACDWAgAADQAgBykAAMgGACAqAADRBgAg0AIAAMkGACDRAgAA0AYAINQCAAAPACDVAgAADwAg1gIAABEAIAMpAADOBgAg0AIAAM8GACDWAgAAAQAgAykAAMwGACDQAgAAzQYAINYCAAANACADKQAAygYAINACAADLBgAg1gIAAA0AIAMpAADIBgAg0AIAAMkGACDWAgAAEQAgAAAAAAAB0wIAAAC3AgIFKQAAwwYAICoAAMYGACDQAgAAxAYAINECAADFBgAg1gIAAA0AIAMpAADDBgAg0AIAAMQGACDWAgAADQAgAAAAAAAB0wIAAAC6AgIFKQAAugYAICoAAMEGACDQAgAAuwYAINECAADABgAg1gIAAA0AIAspAADUBAAwKgAA2QQAMNACAADVBAAw0QIAANYEADDSAgAA1wQAINMCAADYBAAw1AIAANgEADDVAgAA2AQAMNYCAADYBAAw1wIAANoEADDYAgAA2wQAMAspAADIBAAwKgAAzQQAMNACAADJBAAw0QIAAMoEADDSAgAAywQAINMCAADMBAAw1AIAAMwEADDVAgAAzAQAMNYCAADMBAAw1wIAAM4EADDYAgAAzwQAMAspAAC8BAAwKgAAwQQAMNACAAC9BAAw0QIAAL4EADDSAgAAvwQAINMCAADABAAw1AIAAMAEADDVAgAAwAQAMNYCAADABAAw1wIAAMIEADDYAgAAwwQAMAspAACwBAAwKgAAtQQAMNACAACxBAAw0QIAALIEADDSAgAAswQAINMCAAC0BAAw1AIAALQEADDVAgAAtAQAMNYCAAC0BAAw1wIAALYEADDYAgAAtwQAMA3oAQEAAAAB6gEBAAAAAesBAQAAAAHsAQEAAAAB7QGAAAAAAe4BAQAAAAHvAYAAAAAB8AEBAAAAAfEBAQAAAAHyAUAAAAAB8wEBAAAAAfQBgAAAAAH1AUAAAAABAgAAACoAICkAALsEACADAAAAKgAgKQAAuwQAICoAALoEACABIgAAvwYAMBIKAACtAwAg5QEAAKsDADDmAQAAKAAQ5wEAAKsDADDoAQEAAAAB6QEBAKwDACHqAQEAoQMAIesBAQChAwAh7AEBAKEDACHtAQAAogMAIO4BAQChAwAh7wEAAKIDACDwAQEAoQMAIfEBAQChAwAh8gFAAKMDACHzAQEAoQMAIfQBAACiAwAg9QFAAKMDACECAAAAKgAgIgAAugQAIAIAAAC4BAAgIgAAuQQAIBHlAQAAtwQAMOYBAAC4BAAQ5wEAALcEADDoAQEAoQMAIekBAQCsAwAh6gEBAKEDACHrAQEAoQMAIewBAQChAwAh7QEAAKIDACDuAQEAoQMAIe8BAACiAwAg8AEBAKEDACHxAQEAoQMAIfIBQACjAwAh8wEBAKEDACH0AQAAogMAIPUBQACjAwAhEeUBAAC3BAAw5gEAALgEABDnAQAAtwQAMOgBAQChAwAh6QEBAKwDACHqAQEAoQMAIesBAQChAwAh7AEBAKEDACHtAQAAogMAIO4BAQChAwAh7wEAAKIDACDwAQEAoQMAIfEBAQChAwAh8gFAAKMDACHzAQEAoQMAIfQBAACiAwAg9QFAAKMDACEN6AEBANoDACHqAQEA2gMAIesBAQDaAwAh7AEBANoDACHtAYAAAAAB7gEBANoDACHvAYAAAAAB8AEBANoDACHxAQEA2gMAIfIBQADbAwAh8wEBANoDACH0AYAAAAAB9QFAANsDACEN6AEBANoDACHqAQEA2gMAIesBAQDaAwAh7AEBANoDACHtAYAAAAAB7gEBANoDACHvAYAAAAAB8AEBANoDACHxAQEA2gMAIfIBQADbAwAh8wEBANoDACH0AYAAAAAB9QFAANsDACEN6AEBAAAAAeoBAQAAAAHrAQEAAAAB7AEBAAAAAe0BgAAAAAHuAQEAAAAB7wGAAAAAAfABAQAAAAHxAQEAAAAB8gFAAAAAAfMBAQAAAAH0AYAAAAAB9QFAAAAAAQkSAADoAwAg8QEBAAAAAfUBQAAAAAGHAgEAAAABiQIAAACJAgKLAgAAAIsCA4wCAQAAAAGNAkAAAAABjgJAAAAAAQIAAAAkACApAADHBAAgAwAAACQAICkAAMcEACAqAADGBAAgASIAAL4GADAOCgAAuwMAIBIAALwDACDlAQAAtwMAMOYBAAAiABDnAQAAtwMAMOkBAQChAwAh8QEBAKwDACH1AUAAowMAIYcCAQAAAAGJAgAAuAOJAiKLAgAAuQOLAiOMAgEArAMAIY0CQAC6AwAhjgJAAKMDACECAAAAJAAgIgAAxgQAIAIAAADEBAAgIgAAxQQAIAzlAQAAwwQAMOYBAADEBAAQ5wEAAMMEADDpAQEAoQMAIfEBAQCsAwAh9QFAAKMDACGHAgEAoQMAIYkCAAC4A4kCIosCAAC5A4sCI4wCAQCsAwAhjQJAALoDACGOAkAAowMAIQzlAQAAwwQAMOYBAADEBAAQ5wEAAMMEADDpAQEAoQMAIfEBAQCsAwAh9QFAAKMDACGHAgEAoQMAIYkCAAC4A4kCIosCAAC5A4sCI4wCAQCsAwAhjQJAALoDACGOAkAAowMAIQjxAQEA3AMAIfUBQADbAwAhhwIBANoDACGJAgAA4gOJAiKLAgAA4wOLAiOMAgEA3AMAIY0CQADkAwAhjgJAANsDACEJEgAA5gMAIPEBAQDcAwAh9QFAANsDACGHAgEA2gMAIYkCAADiA4kCIosCAADjA4sCI4wCAQDcAwAhjQJAAOQDACGOAkAA2wMAIQkSAADoAwAg8QEBAAAAAfUBQAAAAAGHAgEAAAABiQIAAACJAgKLAgAAAIsCA4wCAQAAAAGNAkAAAAABjgJAAAAAAQkHAACFBAAgDAAAhAQAIA8AAIcEACD1AUAAAAABhwIBAAAAAYkCAAAAnQICjgJAAAAAAZkCAQAAAAGdAgEAAAABAgAAABsAICkAANMEACADAAAAGwAgKQAA0wQAICoAANIEACABIgAAvQYAMA8HAACqAwAgDAAApAMAIA0AALsDACAPAADDAwAg5QEAAMEDADDmAQAAGQAQ5wEAAMEDADD1AUAAowMAIYcCAQAAAAGJAgAAwgOdAiKOAkAAowMAIZkCAQChAwAhmgIBAKEDACGbAgEAoQMAIZ0CAQChAwAhAgAAABsAICIAANIEACACAAAA0AQAICIAANEEACAL5QEAAM8EADDmAQAA0AQAEOcBAADPBAAw9QFAAKMDACGHAgEAoQMAIYkCAADCA50CIo4CQACjAwAhmQIBAKEDACGaAgEAoQMAIZsCAQChAwAhnQIBAKEDACEL5QEAAM8EADDmAQAA0AQAEOcBAADPBAAw9QFAAKMDACGHAgEAoQMAIYkCAADCA50CIo4CQACjAwAhmQIBAKEDACGaAgEAoQMAIZsCAQChAwAhnQIBAKEDACEG9QFAANsDACGHAgEA2gMAIYkCAADzA50CIo4CQADbAwAhmQIBANoDACGdAgEA2gMAIQkHAAD1AwAgDAAA9AMAIA8AAPcDACD1AUAA2wMAIYcCAQDaAwAhiQIAAPMDnQIijgJAANsDACGZAgEA2gMAIZ0CAQDaAwAhCQcAAIUEACAMAACEBAAgDwAAhwQAIPUBQAAAAAGHAgEAAAABiQIAAACdAgKOAkAAAAABmQIBAAAAAZ0CAQAAAAEYBwAAmgQAIAgAAJkEACAJAACbBAAg9QFAAAAAAYcCAQAAAAGJAgAAAKYCAo4CQAAAAAGWAkAAAAABlwIBAAAAAZ4CAQAAAAGgAgAAAK4CAqECAQAAAAGjAgEAAAABpAIBAAAAAaYCAgAAAAGnAgIAAAABqAJAAAAAAakCAQAAAAGqAgEAAAABqwJAAAAAAawCAgAAAAGuAgEAAAABrwIBAAAAAbACgAAAAAECAAAAFQAgKQAA3wQAIAMAAAAVACApAADfBAAgKgAA3gQAIAEiAAC8BgAwHwcAAKoDACAIAACkAwAgCQAAyAMAIAoAAK0DACDlAQAAxQMAMOYBAAATABDnAQAAxQMAMOkBAQCsAwAh9QFAAKMDACGHAgEAAAABiQIAAMYDpgIijgJAAKMDACGWAkAAugMAIZcCAQCsAwAhmgIBAKEDACGeAgEAoQMAIaACAADHA64CIqECAQChAwAhowIBAKEDACGkAgEAoQMAIaYCAgCnAwAhpwICAKcDACGoAkAAugMAIakCAQCsAwAhqgIBAKwDACGrAkAAugMAIawCAgCnAwAhrgIBAKEDACGvAgEArAMAIbACAACiAwAgygIAAMQDACACAAAAFQAgIgAA3gQAIAIAAADcBAAgIgAA3QQAIBrlAQAA2wQAMOYBAADcBAAQ5wEAANsEADDpAQEArAMAIfUBQACjAwAhhwIBAKEDACGJAgAAxgOmAiKOAkAAowMAIZYCQAC6AwAhlwIBAKwDACGaAgEAoQMAIZ4CAQChAwAhoAIAAMcDrgIioQIBAKEDACGjAgEAoQMAIaQCAQChAwAhpgICAKcDACGnAgIApwMAIagCQAC6AwAhqQIBAKwDACGqAgEArAMAIasCQAC6AwAhrAICAKcDACGuAgEAoQMAIa8CAQCsAwAhsAIAAKIDACAa5QEAANsEADDmAQAA3AQAEOcBAADbBAAw6QEBAKwDACH1AUAAowMAIYcCAQChAwAhiQIAAMYDpgIijgJAAKMDACGWAkAAugMAIZcCAQCsAwAhmgIBAKEDACGeAgEAoQMAIaACAADHA64CIqECAQChAwAhowIBAKEDACGkAgEAoQMAIaYCAgCnAwAhpwICAKcDACGoAkAAugMAIakCAQCsAwAhqgIBAKwDACGrAkAAugMAIawCAgCnAwAhrgIBAKEDACGvAgEArAMAIbACAACiAwAgFfUBQADbAwAhhwIBANoDACGJAgAAkgSmAiKOAkAA2wMAIZYCQADkAwAhlwIBANwDACGeAgEA2gMAIaACAACUBK4CIqECAQDaAwAhowIBANoDACGkAgEA2gMAIaYCAgCTBAAhpwICAJMEACGoAkAA5AMAIakCAQDcAwAhqgIBANwDACGrAkAA5AMAIawCAgCTBAAhrgIBANoDACGvAgEA3AMAIbACgAAAAAEYBwAAlgQAIAgAAJUEACAJAACXBAAg9QFAANsDACGHAgEA2gMAIYkCAACSBKYCIo4CQADbAwAhlgJAAOQDACGXAgEA3AMAIZ4CAQDaAwAhoAIAAJQErgIioQIBANoDACGjAgEA2gMAIaQCAQDaAwAhpgICAJMEACGnAgIAkwQAIagCQADkAwAhqQIBANwDACGqAgEA3AMAIasCQADkAwAhrAICAJMEACGuAgEA2gMAIa8CAQDcAwAhsAKAAAAAARgHAACaBAAgCAAAmQQAIAkAAJsEACD1AUAAAAABhwIBAAAAAYkCAAAApgICjgJAAAAAAZYCQAAAAAGXAgEAAAABngIBAAAAAaACAAAArgICoQIBAAAAAaMCAQAAAAGkAgEAAAABpgICAAAAAacCAgAAAAGoAkAAAAABqQIBAAAAAaoCAQAAAAGrAkAAAAABrAICAAAAAa4CAQAAAAGvAgEAAAABsAKAAAAAAQMpAAC6BgAg0AIAALsGACDWAgAADQAgBCkAANQEADDQAgAA1QQAMNICAADXBAAg1gIAANgEADAEKQAAyAQAMNACAADJBAAw0gIAAMsEACDWAgAAzAQAMAQpAAC8BAAw0AIAAL0EADDSAgAAvwQAINYCAADABAAwBCkAALAEADDQAgAAsQQAMNICAACzBAAg1gIAALQEADAAAAAB0wIAAAC_AgIFKQAAsAYAICoAALgGACDQAgAAsQYAINECAAC3BgAg1gIAAAEAIAspAACWBQAwKgAAmwUAMNACAACXBQAw0QIAAJgFADDSAgAAmQUAINMCAACaBQAw1AIAAJoFADDVAgAAmgUAMNYCAACaBQAw1wIAAJwFADDYAgAAnQUAMAspAACKBQAwKgAAjwUAMNACAACLBQAw0QIAAIwFADDSAgAAjQUAINMCAACOBQAw1AIAAI4FADDVAgAAjgUAMNYCAACOBQAw1wIAAJAFADDYAgAAkQUAMAspAACBBQAwKgAAhQUAMNACAACCBQAw0QIAAIMFADDSAgAAhAUAINMCAADYBAAw1AIAANgEADDVAgAA2AQAMNYCAADYBAAw1wIAAIYFADDYAgAA2wQAMAspAAD4BAAwKgAA_AQAMNACAAD5BAAw0QIAAPoEADDSAgAA-wQAINMCAADYBAAw1AIAANgEADDVAgAA2AQAMNYCAADYBAAw1wIAAP0EADDYAgAA2wQAMAspAADvBAAwKgAA8wQAMNACAADwBAAw0QIAAPEEADDSAgAA8gQAINMCAADMBAAw1AIAAMwEADDVAgAAzAQAMNYCAADMBAAw1wIAAPQEADDYAgAAzwQAMAoMAACEBAAgDQAAhgQAIA8AAIcEACD1AUAAAAABhwIBAAAAAYkCAAAAnQICjgJAAAAAAZkCAQAAAAGbAgEAAAABnQIBAAAAAQIAAAAbACApAAD3BAAgAwAAABsAICkAAPcEACAqAAD2BAAgASIAALYGADACAAAAGwAgIgAA9gQAIAIAAADQBAAgIgAA9QQAIAf1AUAA2wMAIYcCAQDaAwAhiQIAAPMDnQIijgJAANsDACGZAgEA2gMAIZsCAQDaAwAhnQIBANoDACEKDAAA9AMAIA0AAPYDACAPAAD3AwAg9QFAANsDACGHAgEA2gMAIYkCAADzA50CIo4CQADbAwAhmQIBANoDACGbAgEA2gMAIZ0CAQDaAwAhCgwAAIQEACANAACGBAAgDwAAhwQAIPUBQAAAAAGHAgEAAAABiQIAAACdAgKOAkAAAAABmQIBAAAAAZsCAQAAAAGdAgEAAAABGQcAAJoEACAIAACZBAAgCgAAnAQAIOkBAQAAAAH1AUAAAAABhwIBAAAAAYkCAAAApgICjgJAAAAAAZYCQAAAAAGXAgEAAAABmgIBAAAAAZ4CAQAAAAGgAgAAAK4CAqECAQAAAAGjAgEAAAABpAIBAAAAAaYCAgAAAAGnAgIAAAABqAJAAAAAAakCAQAAAAGqAgEAAAABqwJAAAAAAawCAgAAAAGuAgEAAAABsAKAAAAAAQIAAAAVACApAACABQAgAwAAABUAICkAAIAFACAqAAD_BAAgASIAALUGADACAAAAFQAgIgAA_wQAIAIAAADcBAAgIgAA_gQAIBbpAQEA3AMAIfUBQADbAwAhhwIBANoDACGJAgAAkgSmAiKOAkAA2wMAIZYCQADkAwAhlwIBANwDACGaAgEA2gMAIZ4CAQDaAwAhoAIAAJQErgIioQIBANoDACGjAgEA2gMAIaQCAQDaAwAhpgICAJMEACGnAgIAkwQAIagCQADkAwAhqQIBANwDACGqAgEA3AMAIasCQADkAwAhrAICAJMEACGuAgEA2gMAIbACgAAAAAEZBwAAlgQAIAgAAJUEACAKAACYBAAg6QEBANwDACH1AUAA2wMAIYcCAQDaAwAhiQIAAJIEpgIijgJAANsDACGWAkAA5AMAIZcCAQDcAwAhmgIBANoDACGeAgEA2gMAIaACAACUBK4CIqECAQDaAwAhowIBANoDACGkAgEA2gMAIaYCAgCTBAAhpwICAJMEACGoAkAA5AMAIakCAQDcAwAhqgIBANwDACGrAkAA5AMAIawCAgCTBAAhrgIBANoDACGwAoAAAAABGQcAAJoEACAIAACZBAAgCgAAnAQAIOkBAQAAAAH1AUAAAAABhwIBAAAAAYkCAAAApgICjgJAAAAAAZYCQAAAAAGXAgEAAAABmgIBAAAAAZ4CAQAAAAGgAgAAAK4CAqECAQAAAAGjAgEAAAABpAIBAAAAAaYCAgAAAAGnAgIAAAABqAJAAAAAAakCAQAAAAGqAgEAAAABqwJAAAAAAawCAgAAAAGuAgEAAAABsAKAAAAAARkIAACZBAAgCQAAmwQAIAoAAJwEACDpAQEAAAAB9QFAAAAAAYcCAQAAAAGJAgAAAKYCAo4CQAAAAAGWAkAAAAABlwIBAAAAAZ4CAQAAAAGgAgAAAK4CAqECAQAAAAGjAgEAAAABpAIBAAAAAaYCAgAAAAGnAgIAAAABqAJAAAAAAakCAQAAAAGqAgEAAAABqwJAAAAAAawCAgAAAAGuAgEAAAABrwIBAAAAAbACgAAAAAECAAAAFQAgKQAAiQUAIAMAAAAVACApAACJBQAgKgAAiAUAIAEiAAC0BgAwAgAAABUAICIAAIgFACACAAAA3AQAICIAAIcFACAW6QEBANwDACH1AUAA2wMAIYcCAQDaAwAhiQIAAJIEpgIijgJAANsDACGWAkAA5AMAIZcCAQDcAwAhngIBANoDACGgAgAAlASuAiKhAgEA2gMAIaMCAQDaAwAhpAIBANoDACGmAgIAkwQAIacCAgCTBAAhqAJAAOQDACGpAgEA3AMAIaoCAQDcAwAhqwJAAOQDACGsAgIAkwQAIa4CAQDaAwAhrwIBANwDACGwAoAAAAABGQgAAJUEACAJAACXBAAgCgAAmAQAIOkBAQDcAwAh9QFAANsDACGHAgEA2gMAIYkCAACSBKYCIo4CQADbAwAhlgJAAOQDACGXAgEA3AMAIZ4CAQDaAwAhoAIAAJQErgIioQIBANoDACGjAgEA2gMAIaQCAQDaAwAhpgICAJMEACGnAgIAkwQAIagCQADkAwAhqQIBANwDACGqAgEA3AMAIasCQADkAwAhrAICAJMEACGuAgEA2gMAIa8CAQDcAwAhsAKAAAAAARkIAACZBAAgCQAAmwQAIAoAAJwEACDpAQEAAAAB9QFAAAAAAYcCAQAAAAGJAgAAAKYCAo4CQAAAAAGWAkAAAAABlwIBAAAAAZ4CAQAAAAGgAgAAAK4CAqECAQAAAAGjAgEAAAABpAIBAAAAAaYCAgAAAAGnAgIAAAABqAJAAAAAAakCAQAAAAGqAgEAAAABqwJAAAAAAawCAgAAAAGuAgEAAAABrwIBAAAAAbACgAAAAAEK9QFAAAAAAYcCAQAAAAGJAgAAALcCAo4CQAAAAAGxAgEAAAABsgIBAAAAAbMCAQAAAAG0AgIAAAABtQIBAAAAAbcCgAAAAAECAAAAMwAgKQAAlQUAIAMAAAAzACApAACVBQAgKgAAlAUAIAEiAACzBgAwEAcAAKoDACDlAQAApgMAMOYBAAAxABDnAQAApgMAMPUBQACjAwAhhwIBAAAAAYkCAACoA7cCIo4CQACjAwAhmgIBAKEDACGxAgEAoQMAIbICAQChAwAhswIBAKEDACG0AgIApwMAIbUCAQChAwAhtwIAAKkDACDGAgAApQMAIAIAAAAzACAiAACUBQAgAgAAAJIFACAiAACTBQAgDuUBAACRBQAw5gEAAJIFABDnAQAAkQUAMPUBQACjAwAhhwIBAKEDACGJAgAAqAO3AiKOAkAAowMAIZoCAQChAwAhsQIBAKEDACGyAgEAoQMAIbMCAQChAwAhtAICAKcDACG1AgEAoQMAIbcCAACpAwAgDuUBAACRBQAw5gEAAJIFABDnAQAAkQUAMPUBQACjAwAhhwIBAKEDACGJAgAAqAO3AiKOAkAAowMAIZoCAQChAwAhsQIBAKEDACGyAgEAoQMAIbMCAQChAwAhtAICAKcDACG1AgEAoQMAIbcCAACpAwAgCvUBQADbAwAhhwIBANoDACGJAgAAogS3AiKOAkAA2wMAIbECAQDaAwAhsgIBANoDACGzAgEA2gMAIbQCAgCTBAAhtQIBANoDACG3AoAAAAABCvUBQADbAwAhhwIBANoDACGJAgAAogS3AiKOAkAA2wMAIbECAQDaAwAhsgIBANoDACGzAgEA2gMAIbQCAgCTBAAhtQIBANoDACG3AoAAAAABCvUBQAAAAAGHAgEAAAABiQIAAAC3AgKOAkAAAAABsQIBAAAAAbICAQAAAAGzAgEAAAABtAICAAAAAbUCAQAAAAG3AoAAAAABCgsAAOEEACARAADiBAAgEwAA4wQAIBQAAOQEACD1AUAAAAABhwIBAAAAAYkCAAAAugICjgJAAAAAAbgCAgAAAAG6AoAAAAABAgAAABEAICkAAKEFACADAAAAEQAgKQAAoQUAICoAAKAFACABIgAAsgYAMBEHAACqAwAgCwAAtAMAIBEAALUDACATAAC2AwAgFAAAzQMAIOUBAADLAwAw5gEAAA8AEOcBAADLAwAw9QFAAKMDACGHAgEAAAABiQIAAMwDugIijgJAAKMDACGaAgEAoQMAIbgCAgCnAwAhugIAAKIDACDLAgAAyQMAIMwCAADKAwAgAgAAABEAICIAAKAFACACAAAAngUAICIAAJ8FACAK5QEAAJ0FADDmAQAAngUAEOcBAACdBQAw9QFAAKMDACGHAgEAoQMAIYkCAADMA7oCIo4CQACjAwAhmgIBAKEDACG4AgIApwMAIboCAACiAwAgCuUBAACdBQAw5gEAAJ4FABDnAQAAnQUAMPUBQACjAwAhhwIBAKEDACGJAgAAzAO6AiKOAkAAowMAIZoCAQChAwAhuAICAKcDACG6AgAAogMAIAb1AUAA2wMAIYcCAQDaAwAhiQIAAKoEugIijgJAANsDACG4AgIAkwQAIboCgAAAAAEKCwAArAQAIBEAAK0EACATAACuBAAgFAAArwQAIPUBQADbAwAhhwIBANoDACGJAgAAqgS6AiKOAkAA2wMAIbgCAgCTBAAhugKAAAAAAQoLAADhBAAgEQAA4gQAIBMAAOMEACAUAADkBAAg9QFAAAAAAYcCAQAAAAGJAgAAALoCAo4CQAAAAAG4AgIAAAABugKAAAAAAQMpAACwBgAg0AIAALEGACDWAgAAAQAgBCkAAJYFADDQAgAAlwUAMNICAACZBQAg1gIAAJoFADAEKQAAigUAMNACAACLBQAw0gIAAI0FACDWAgAAjgUAMAQpAACBBQAw0AIAAIIFADDSAgAAhAUAINYCAADYBAAwBCkAAPgEADDQAgAA-QQAMNICAAD7BAAg1gIAANgEADAEKQAA7wQAMNACAADwBAAw0gIAAPIEACDWAgAAzAQAMAAAAAUpAACrBgAgKgAArgYAINACAACsBgAg0QIAAK0GACDWAgAAAQAgAykAAKsGACDQAgAArAYAINYCAAABACAAAAAB0wIAAADCAgIFKQAApgYAICoAAKkGACDQAgAApwYAINECAACoBgAg1gIAAAEAIAMpAACmBgAg0AIAAKcGACDWAgAAAQAgAAAAAdMCAAAAxgICCykAAP0FADAqAACCBgAw0AIAAP4FADDRAgAA_wUAMNICAACABgAg0wIAAIEGADDUAgAAgQYAMNUCAACBBgAw1gIAAIEGADDXAgAAgwYAMNgCAACEBgAwCykAAPEFADAqAAD2BQAw0AIAAPIFADDRAgAA8wUAMNICAAD0BQAg0wIAAPUFADDUAgAA9QUAMNUCAAD1BQAw1gIAAPUFADDXAgAA9wUAMNgCAAD4BQAwCykAAOUFADAqAADqBQAw0AIAAOYFADDRAgAA5wUAMNICAADoBQAg0wIAAOkFADDUAgAA6QUAMNUCAADpBQAw1gIAAOkFADDXAgAA6wUAMNgCAADsBQAwCykAANkFADAqAADeBQAw0AIAANoFADDRAgAA2wUAMNICAADcBQAg0wIAAN0FADDUAgAA3QUAMNUCAADdBQAw1gIAAN0FADDXAgAA3wUAMNgCAADgBQAwCykAANAFADAqAADUBQAw0AIAANEFADDRAgAA0gUAMNICAADTBQAg0wIAANgEADDUAgAA2AQAMNUCAADYBAAw1gIAANgEADDXAgAA1QUAMNgCAADbBAAwCykAAMcFADAqAADLBQAw0AIAAMgFADDRAgAAyQUAMNICAADKBQAg0wIAAMwEADDUAgAAzAQAMNUCAADMBAAw1gIAAMwEADDXAgAAzAUAMNgCAADPBAAwCykAAL4FADAqAADCBQAw0AIAAL8FADDRAgAAwAUAMNICAADBBQAg0wIAAMAEADDUAgAAwAQAMNUCAADABAAw1gIAAMAEADDXAgAAwwUAMNgCAADDBAAwCQoAAOcDACDpAQEAAAAB8QEBAAAAAfUBQAAAAAGHAgEAAAABiQIAAACJAgKLAgAAAIsCA40CQAAAAAGOAkAAAAABAgAAACQAICkAAMYFACADAAAAJAAgKQAAxgUAICoAAMUFACABIgAApQYAMAIAAAAkACAiAADFBQAgAgAAAMQEACAiAADEBQAgCOkBAQDaAwAh8QEBANwDACH1AUAA2wMAIYcCAQDaAwAhiQIAAOIDiQIiiwIAAOMDiwIjjQJAAOQDACGOAkAA2wMAIQkKAADlAwAg6QEBANoDACHxAQEA3AMAIfUBQADbAwAhhwIBANoDACGJAgAA4gOJAiKLAgAA4wOLAiONAkAA5AMAIY4CQADbAwAhCQoAAOcDACDpAQEAAAAB8QEBAAAAAfUBQAAAAAGHAgEAAAABiQIAAACJAgKLAgAAAIsCA40CQAAAAAGOAkAAAAABCgcAAIUEACANAACGBAAgDwAAhwQAIPUBQAAAAAGHAgEAAAABiQIAAACdAgKOAkAAAAABmgIBAAAAAZsCAQAAAAGdAgEAAAABAgAAABsAICkAAM8FACADAAAAGwAgKQAAzwUAICoAAM4FACABIgAApAYAMAIAAAAbACAiAADOBQAgAgAAANAEACAiAADNBQAgB_UBQADbAwAhhwIBANoDACGJAgAA8wOdAiKOAkAA2wMAIZoCAQDaAwAhmwIBANoDACGdAgEA2gMAIQoHAAD1AwAgDQAA9gMAIA8AAPcDACD1AUAA2wMAIYcCAQDaAwAhiQIAAPMDnQIijgJAANsDACGaAgEA2gMAIZsCAQDaAwAhnQIBANoDACEKBwAAhQQAIA0AAIYEACAPAACHBAAg9QFAAAAAAYcCAQAAAAGJAgAAAJ0CAo4CQAAAAAGaAgEAAAABmwIBAAAAAZ0CAQAAAAEZBwAAmgQAIAkAAJsEACAKAACcBAAg6QEBAAAAAfUBQAAAAAGHAgEAAAABiQIAAACmAgKOAkAAAAABlgJAAAAAAZcCAQAAAAGaAgEAAAABoAIAAACuAgKhAgEAAAABowIBAAAAAaQCAQAAAAGmAgIAAAABpwICAAAAAagCQAAAAAGpAgEAAAABqgIBAAAAAasCQAAAAAGsAgIAAAABrgIBAAAAAa8CAQAAAAGwAoAAAAABAgAAABUAICkAANgFACADAAAAFQAgKQAA2AUAICoAANcFACABIgAAowYAMAIAAAAVACAiAADXBQAgAgAAANwEACAiAADWBQAgFukBAQDcAwAh9QFAANsDACGHAgEA2gMAIYkCAACSBKYCIo4CQADbAwAhlgJAAOQDACGXAgEA3AMAIZoCAQDaAwAhoAIAAJQErgIioQIBANoDACGjAgEA2gMAIaQCAQDaAwAhpgICAJMEACGnAgIAkwQAIagCQADkAwAhqQIBANwDACGqAgEA3AMAIasCQADkAwAhrAICAJMEACGuAgEA2gMAIa8CAQDcAwAhsAKAAAAAARkHAACWBAAgCQAAlwQAIAoAAJgEACDpAQEA3AMAIfUBQADbAwAhhwIBANoDACGJAgAAkgSmAiKOAkAA2wMAIZYCQADkAwAhlwIBANwDACGaAgEA2gMAIaACAACUBK4CIqECAQDaAwAhowIBANoDACGkAgEA2gMAIaYCAgCTBAAhpwICAJMEACGoAkAA5AMAIakCAQDcAwAhqgIBANwDACGrAkAA5AMAIawCAgCTBAAhrgIBANoDACGvAgEA3AMAIbACgAAAAAEZBwAAmgQAIAkAAJsEACAKAACcBAAg6QEBAAAAAfUBQAAAAAGHAgEAAAABiQIAAACmAgKOAkAAAAABlgJAAAAAAZcCAQAAAAGaAgEAAAABoAIAAACuAgKhAgEAAAABowIBAAAAAaQCAQAAAAGmAgIAAAABpwICAAAAAagCQAAAAAGpAgEAAAABqgIBAAAAAasCQAAAAAGsAgIAAAABrgIBAAAAAa8CAQAAAAGwAoAAAAABBvUBQAAAAAGHAgEAAAABnwIBAAAAAaACAQAAAAGhAgEAAAABogKAAAAAAQIAAAA_ACApAADkBQAgAwAAAD8AICkAAOQFACAqAADjBQAgASIAAKIGADALCAAApAMAIOUBAACgAwAw5gEAAD0AEOcBAACgAwAw9QFAAKMDACGHAgEAAAABngIBAKEDACGfAgEAoQMAIaACAQChAwAhoQIBAKEDACGiAgAAogMAIAIAAAA_ACAiAADjBQAgAgAAAOEFACAiAADiBQAgCuUBAADgBQAw5gEAAOEFABDnAQAA4AUAMPUBQACjAwAhhwIBAKEDACGeAgEAoQMAIZ8CAQChAwAhoAIBAKEDACGhAgEAoQMAIaICAACiAwAgCuUBAADgBQAw5gEAAOEFABDnAQAA4AUAMPUBQACjAwAhhwIBAKEDACGeAgEAoQMAIZ8CAQChAwAhoAIBAKEDACGhAgEAoQMAIaICAACiAwAgBvUBQADbAwAhhwIBANoDACGfAgEA2gMAIaACAQDaAwAhoQIBANoDACGiAoAAAAABBvUBQADbAwAhhwIBANoDACGfAgEA2gMAIaACAQDaAwAhoQIBANoDACGiAoAAAAABBvUBQAAAAAGHAgEAAAABnwIBAAAAAaACAQAAAAGhAgEAAAABogKAAAAAAQsRAACnBQAgFQAAowUAIBYAAKQFACAXAAClBQAgGAAApgUAIPUBQAAAAAGHAgEAAAABiQIAAAC_AgKOAkAAAAABvAIBAAAAAb0CAQAAAAECAAAADQAgKQAA8AUAIAMAAAANACApAADwBQAgKgAA7wUAIAEiAAChBgAwEAYAAKQDACARAAC1AwAgFQAA0AMAIBYAANEDACAXAAC0AwAgGAAAtAMAIOUBAADOAwAw5gEAAAsAEOcBAADOAwAw9QFAAKMDACGHAgEAAAABiQIAAM8DvwIijgJAAKMDACG7AgEAoQMAIbwCAQAAAAG9AgEAoQMAIQIAAAANACAiAADvBQAgAgAAAO0FACAiAADuBQAgCuUBAADsBQAw5gEAAO0FABDnAQAA7AUAMPUBQACjAwAhhwIBAKEDACGJAgAAzwO_AiKOAkAAowMAIbsCAQChAwAhvAIBAKEDACG9AgEAoQMAIQrlAQAA7AUAMOYBAADtBQAQ5wEAAOwFADD1AUAAowMAIYcCAQChAwAhiQIAAM8DvwIijgJAAKMDACG7AgEAoQMAIbwCAQChAwAhvQIBAKEDACEG9QFAANsDACGHAgEA2gMAIYkCAADoBL8CIo4CQADbAwAhvAIBANoDACG9AgEA2gMAIQsRAADuBAAgFQAA6gQAIBYAAOsEACAXAADsBAAgGAAA7QQAIPUBQADbAwAhhwIBANoDACGJAgAA6AS_AiKOAkAA2wMAIbwCAQDaAwAhvQIBANoDACELEQAApwUAIBUAAKMFACAWAACkBQAgFwAApQUAIBgAAKYFACD1AUAAAAABhwIBAAAAAYkCAAAAvwICjgJAAAAAAbwCAQAAAAG9AgEAAAABA_UBQAAAAAGHAgEAAAABwAIBAAAAAQIAAAAJACApAAD8BQAgAwAAAAkAICkAAPwFACAqAAD7BQAgASIAAKAGADAIAwAApAMAIOUBAADSAwAw5gEAAAcAEOcBAADSAwAw9QFAAKMDACGHAgEAAAABvwIBAKEDACHAAgEAAAABAgAAAAkAICIAAPsFACACAAAA-QUAICIAAPoFACAH5QEAAPgFADDmAQAA-QUAEOcBAAD4BQAw9QFAAKMDACGHAgEAoQMAIb8CAQChAwAhwAIBAKEDACEH5QEAAPgFADDmAQAA-QUAEOcBAAD4BQAw9QFAAKMDACGHAgEAoQMAIb8CAQChAwAhwAIBAKEDACED9QFAANsDACGHAgEA2gMAIcACAQDaAwAhA_UBQADbAwAhhwIBANoDACHAAgEA2gMAIQP1AUAAAAABhwIBAAAAAcACAQAAAAED9QFAAAAAAYcCAQAAAAHCAgAAAMICAgIAAAAFACApAACIBgAgAwAAAAUAICkAAIgGACAqAACHBgAgASIAAJ8GADAJAwAApAMAIOUBAADUAwAw5gEAAAMAEOcBAADUAwAw9QFAAKMDACGHAgEAAAABvwIBAKEDACHCAgAA1QPCAiLNAgAA0wMAIAIAAAAFACAiAACHBgAgAgAAAIUGACAiAACGBgAgB-UBAACEBgAw5gEAAIUGABDnAQAAhAYAMPUBQACjAwAhhwIBAKEDACG_AgEAoQMAIcICAADVA8ICIgflAQAAhAYAMOYBAACFBgAQ5wEAAIQGADD1AUAAowMAIYcCAQChAwAhvwIBAKEDACHCAgAA1QPCAiID9QFAANsDACGHAgEA2gMAIcICAACwBcICIgP1AUAA2wMAIYcCAQDaAwAhwgIAALAFwgIiA_UBQAAAAAGHAgEAAAABwgIAAADCAgIEKQAA_QUAMNACAAD-BQAw0gIAAIAGACDWAgAAgQYAMAQpAADxBQAw0AIAAPIFADDSAgAA9AUAINYCAAD1BQAwBCkAAOUFADDQAgAA5gUAMNICAADoBQAg1gIAAOkFADAEKQAA2QUAMNACAADaBQAw0gIAANwFACDWAgAA3QUAMAQpAADQBQAw0AIAANEFADDSAgAA0wUAINYCAADYBAAwBCkAAMcFADDQAgAAyAUAMNICAADKBQAg1gIAAMwEADAEKQAAvgUAMNACAAC_BQAw0gIAAMEFACDWAgAAwAQAMAAAAAAAAAAIBAAAkAYAIAUAAJEGACAXAACUBgAgGQAAkgYAIBoAAJMGACAbAACVBgAgHAAAlgYAIMMCAADWAwAgBgYAAJcGACARAACVBgAgFQAAnQYAIBYAAJ4GACAXAACUBgAgGAAAlAYAIAUHAACYBgAgCwAAlAYAIBEAAJUGACATAACWBgAgFAAAnAYAIAQHAACYBgAgDAAAlwYAIA0AAJkGACAPAACbBgAgAAAAAAP1AUAAAAABhwIBAAAAAcICAAAAwgICA_UBQAAAAAGHAgEAAAABwAIBAAAAAQb1AUAAAAABhwIBAAAAAYkCAAAAvwICjgJAAAAAAbwCAQAAAAG9AgEAAAABBvUBQAAAAAGHAgEAAAABnwIBAAAAAaACAQAAAAGhAgEAAAABogKAAAAAARbpAQEAAAAB9QFAAAAAAYcCAQAAAAGJAgAAAKYCAo4CQAAAAAGWAkAAAAABlwIBAAAAAZoCAQAAAAGgAgAAAK4CAqECAQAAAAGjAgEAAAABpAIBAAAAAaYCAgAAAAGnAgIAAAABqAJAAAAAAakCAQAAAAGqAgEAAAABqwJAAAAAAawCAgAAAAGuAgEAAAABrwIBAAAAAbACgAAAAAEH9QFAAAAAAYcCAQAAAAGJAgAAAJ0CAo4CQAAAAAGaAgEAAAABmwIBAAAAAZ0CAQAAAAEI6QEBAAAAAfEBAQAAAAH1AUAAAAABhwIBAAAAAYkCAAAAiQICiwIAAACLAgONAkAAAAABjgJAAAAAAQwFAACKBgAgFwAAjQYAIBkAAIsGACAaAACMBgAgGwAAjgYAIBwAAI8GACD1AUAAAAABhwIBAAAAAYkCAAAAxgICjgJAAAAAAcMCAQAAAAHEAgEAAAABAgAAAAEAICkAAKYGACADAAAAJgAgKQAApgYAICoAAKoGACAOAAAAJgAgBQAAuAUAIBcAALsFACAZAAC5BQAgGgAAugUAIBsAALwFACAcAAC9BQAgIgAAqgYAIPUBQADbAwAhhwIBANoDACGJAgAAtgXGAiKOAkAA2wMAIcMCAQDcAwAhxAIBANoDACEMBQAAuAUAIBcAALsFACAZAAC5BQAgGgAAugUAIBsAALwFACAcAAC9BQAg9QFAANsDACGHAgEA2gMAIYkCAAC2BcYCIo4CQADbAwAhwwIBANwDACHEAgEA2gMAIQwEAACJBgAgFwAAjQYAIBkAAIsGACAaAACMBgAgGwAAjgYAIBwAAI8GACD1AUAAAAABhwIBAAAAAYkCAAAAxgICjgJAAAAAAcMCAQAAAAHEAgEAAAABAgAAAAEAICkAAKsGACADAAAAJgAgKQAAqwYAICoAAK8GACAOAAAAJgAgBAAAtwUAIBcAALsFACAZAAC5BQAgGgAAugUAIBsAALwFACAcAAC9BQAgIgAArwYAIPUBQADbAwAhhwIBANoDACGJAgAAtgXGAiKOAkAA2wMAIcMCAQDcAwAhxAIBANoDACEMBAAAtwUAIBcAALsFACAZAAC5BQAgGgAAugUAIBsAALwFACAcAAC9BQAg9QFAANsDACGHAgEA2gMAIYkCAAC2BcYCIo4CQADbAwAhwwIBANwDACHEAgEA2gMAIQwEAACJBgAgBQAAigYAIBcAAI0GACAaAACMBgAgGwAAjgYAIBwAAI8GACD1AUAAAAABhwIBAAAAAYkCAAAAxgICjgJAAAAAAcMCAQAAAAHEAgEAAAABAgAAAAEAICkAALAGACAG9QFAAAAAAYcCAQAAAAGJAgAAALoCAo4CQAAAAAG4AgIAAAABugKAAAAAAQr1AUAAAAABhwIBAAAAAYkCAAAAtwICjgJAAAAAAbECAQAAAAGyAgEAAAABswIBAAAAAbQCAgAAAAG1AgEAAAABtwKAAAAAARbpAQEAAAAB9QFAAAAAAYcCAQAAAAGJAgAAAKYCAo4CQAAAAAGWAkAAAAABlwIBAAAAAZ4CAQAAAAGgAgAAAK4CAqECAQAAAAGjAgEAAAABpAIBAAAAAaYCAgAAAAGnAgIAAAABqAJAAAAAAakCAQAAAAGqAgEAAAABqwJAAAAAAawCAgAAAAGuAgEAAAABrwIBAAAAAbACgAAAAAEW6QEBAAAAAfUBQAAAAAGHAgEAAAABiQIAAACmAgKOAkAAAAABlgJAAAAAAZcCAQAAAAGaAgEAAAABngIBAAAAAaACAAAArgICoQIBAAAAAaMCAQAAAAGkAgEAAAABpgICAAAAAacCAgAAAAGoAkAAAAABqQIBAAAAAaoCAQAAAAGrAkAAAAABrAICAAAAAa4CAQAAAAGwAoAAAAABB_UBQAAAAAGHAgEAAAABiQIAAACdAgKOAkAAAAABmQIBAAAAAZsCAQAAAAGdAgEAAAABAwAAACYAICkAALAGACAqAAC5BgAgDgAAACYAIAQAALcFACAFAAC4BQAgFwAAuwUAIBoAALoFACAbAAC8BQAgHAAAvQUAICIAALkGACD1AUAA2wMAIYcCAQDaAwAhiQIAALYFxgIijgJAANsDACHDAgEA3AMAIcQCAQDaAwAhDAQAALcFACAFAAC4BQAgFwAAuwUAIBoAALoFACAbAAC8BQAgHAAAvQUAIPUBQADbAwAhhwIBANoDACGJAgAAtgXGAiKOAkAA2wMAIcMCAQDcAwAhxAIBANoDACEMBgAAogUAIBEAAKcFACAWAACkBQAgFwAApQUAIBgAAKYFACD1AUAAAAABhwIBAAAAAYkCAAAAvwICjgJAAAAAAbsCAQAAAAG8AgEAAAABvQIBAAAAAQIAAAANACApAAC6BgAgFfUBQAAAAAGHAgEAAAABiQIAAACmAgKOAkAAAAABlgJAAAAAAZcCAQAAAAGeAgEAAAABoAIAAACuAgKhAgEAAAABowIBAAAAAaQCAQAAAAGmAgIAAAABpwICAAAAAagCQAAAAAGpAgEAAAABqgIBAAAAAasCQAAAAAGsAgIAAAABrgIBAAAAAa8CAQAAAAGwAoAAAAABBvUBQAAAAAGHAgEAAAABiQIAAACdAgKOAkAAAAABmQIBAAAAAZ0CAQAAAAEI8QEBAAAAAfUBQAAAAAGHAgEAAAABiQIAAACJAgKLAgAAAIsCA4wCAQAAAAGNAkAAAAABjgJAAAAAAQ3oAQEAAAAB6gEBAAAAAesBAQAAAAHsAQEAAAAB7QGAAAAAAe4BAQAAAAHvAYAAAAAB8AEBAAAAAfEBAQAAAAHyAUAAAAAB8wEBAAAAAfQBgAAAAAH1AUAAAAABAwAAAAsAICkAALoGACAqAADCBgAgDgAAAAsAIAYAAOkEACARAADuBAAgFgAA6wQAIBcAAOwEACAYAADtBAAgIgAAwgYAIPUBQADbAwAhhwIBANoDACGJAgAA6AS_AiKOAkAA2wMAIbsCAQDaAwAhvAIBANoDACG9AgEA2gMAIQwGAADpBAAgEQAA7gQAIBYAAOsEACAXAADsBAAgGAAA7QQAIPUBQADbAwAhhwIBANoDACGJAgAA6AS_AiKOAkAA2wMAIbsCAQDaAwAhvAIBANoDACG9AgEA2gMAIQwGAACiBQAgEQAApwUAIBUAAKMFACAXAAClBQAgGAAApgUAIPUBQAAAAAGHAgEAAAABiQIAAAC_AgKOAkAAAAABuwIBAAAAAbwCAQAAAAG9AgEAAAABAgAAAA0AICkAAMMGACADAAAACwAgKQAAwwYAICoAAMcGACAOAAAACwAgBgAA6QQAIBEAAO4EACAVAADqBAAgFwAA7AQAIBgAAO0EACAiAADHBgAg9QFAANsDACGHAgEA2gMAIYkCAADoBL8CIo4CQADbAwAhuwIBANoDACG8AgEA2gMAIb0CAQDaAwAhDAYAAOkEACARAADuBAAgFQAA6gQAIBcAAOwEACAYAADtBAAg9QFAANsDACGHAgEA2gMAIYkCAADoBL8CIo4CQADbAwAhuwIBANoDACG8AgEA2gMAIb0CAQDaAwAhCwcAAOAEACARAADiBAAgEwAA4wQAIBQAAOQEACD1AUAAAAABhwIBAAAAAYkCAAAAugICjgJAAAAAAZoCAQAAAAG4AgIAAAABugKAAAAAAQIAAAARACApAADIBgAgDAYAAKIFACARAACnBQAgFQAAowUAIBYAAKQFACAXAAClBQAg9QFAAAAAAYcCAQAAAAGJAgAAAL8CAo4CQAAAAAG7AgEAAAABvAIBAAAAAb0CAQAAAAECAAAADQAgKQAAygYAIAwGAACiBQAgEQAApwUAIBUAAKMFACAWAACkBQAgGAAApgUAIPUBQAAAAAGHAgEAAAABiQIAAAC_AgKOAkAAAAABuwIBAAAAAbwCAQAAAAG9AgEAAAABAgAAAA0AICkAAMwGACAMBAAAiQYAIAUAAIoGACAZAACLBgAgGgAAjAYAIBsAAI4GACAcAACPBgAg9QFAAAAAAYcCAQAAAAGJAgAAAMYCAo4CQAAAAAHDAgEAAAABxAIBAAAAAQIAAAABACApAADOBgAgAwAAAA8AICkAAMgGACAqAADSBgAgDQAAAA8AIAcAAKsEACARAACtBAAgEwAArgQAIBQAAK8EACAiAADSBgAg9QFAANsDACGHAgEA2gMAIYkCAACqBLoCIo4CQADbAwAhmgIBANoDACG4AgIAkwQAIboCgAAAAAELBwAAqwQAIBEAAK0EACATAACuBAAgFAAArwQAIPUBQADbAwAhhwIBANoDACGJAgAAqgS6AiKOAkAA2wMAIZoCAQDaAwAhuAICAJMEACG6AoAAAAABAwAAAAsAICkAAMoGACAqAADVBgAgDgAAAAsAIAYAAOkEACARAADuBAAgFQAA6gQAIBYAAOsEACAXAADsBAAgIgAA1QYAIPUBQADbAwAhhwIBANoDACGJAgAA6AS_AiKOAkAA2wMAIbsCAQDaAwAhvAIBANoDACG9AgEA2gMAIQwGAADpBAAgEQAA7gQAIBUAAOoEACAWAADrBAAgFwAA7AQAIPUBQADbAwAhhwIBANoDACGJAgAA6AS_AiKOAkAA2wMAIbsCAQDaAwAhvAIBANoDACG9AgEA2gMAIQMAAAALACApAADMBgAgKgAA2AYAIA4AAAALACAGAADpBAAgEQAA7gQAIBUAAOoEACAWAADrBAAgGAAA7QQAICIAANgGACD1AUAA2wMAIYcCAQDaAwAhiQIAAOgEvwIijgJAANsDACG7AgEA2gMAIbwCAQDaAwAhvQIBANoDACEMBgAA6QQAIBEAAO4EACAVAADqBAAgFgAA6wQAIBgAAO0EACD1AUAA2wMAIYcCAQDaAwAhiQIAAOgEvwIijgJAANsDACG7AgEA2gMAIbwCAQDaAwAhvQIBANoDACEDAAAAJgAgKQAAzgYAICoAANsGACAOAAAAJgAgBAAAtwUAIAUAALgFACAZAAC5BQAgGgAAugUAIBsAALwFACAcAAC9BQAgIgAA2wYAIPUBQADbAwAhhwIBANoDACGJAgAAtgXGAiKOAkAA2wMAIcMCAQDcAwAhxAIBANoDACEMBAAAtwUAIAUAALgFACAZAAC5BQAgGgAAugUAIBsAALwFACAcAAC9BQAg9QFAANsDACGHAgEA2gMAIYkCAAC2BcYCIo4CQADbAwAhwwIBANwDACHEAgEA2gMAIQwEAACJBgAgBQAAigYAIBcAAI0GACAZAACLBgAgGwAAjgYAIBwAAI8GACD1AUAAAAABhwIBAAAAAYkCAAAAxgICjgJAAAAAAcMCAQAAAAHEAgEAAAABAgAAAAEAICkAANwGACADAAAAJgAgKQAA3AYAICoAAOAGACAOAAAAJgAgBAAAtwUAIAUAALgFACAXAAC7BQAgGQAAuQUAIBsAALwFACAcAAC9BQAgIgAA4AYAIPUBQADbAwAhhwIBANoDACGJAgAAtgXGAiKOAkAA2wMAIcMCAQDcAwAhxAIBANoDACEMBAAAtwUAIAUAALgFACAXAAC7BQAgGQAAuQUAIBsAALwFACAcAAC9BQAg9QFAANsDACGHAgEA2gMAIYkCAAC2BcYCIo4CQADbAwAhwwIBANwDACHEAgEA2gMAIQsHAADgBAAgCwAA4QQAIBMAAOMEACAUAADkBAAg9QFAAAAAAYcCAQAAAAGJAgAAALoCAo4CQAAAAAGaAgEAAAABuAICAAAAAboCgAAAAAECAAAAEQAgKQAA4QYAIAwGAACiBQAgFQAAowUAIBYAAKQFACAXAAClBQAgGAAApgUAIPUBQAAAAAGHAgEAAAABiQIAAAC_AgKOAkAAAAABuwIBAAAAAbwCAQAAAAG9AgEAAAABAgAAAA0AICkAAOMGACAMBAAAiQYAIAUAAIoGACAXAACNBgAgGQAAiwYAIBoAAIwGACAcAACPBgAg9QFAAAAAAYcCAQAAAAGJAgAAAMYCAo4CQAAAAAHDAgEAAAABxAIBAAAAAQIAAAABACApAADlBgAgC_UBQAAAAAGHAgEAAAABiQIAAACWAgKOAkAAAAABkQIAAACRAgKSAgEAAAABkwIBAAAAAZQCAQAAAAGWAkAAAAABlwIBAAAAAZgCAQAAAAEDAAAADwAgKQAA4QYAICoAAOoGACANAAAADwAgBwAAqwQAIAsAAKwEACATAACuBAAgFAAArwQAICIAAOoGACD1AUAA2wMAIYcCAQDaAwAhiQIAAKoEugIijgJAANsDACGaAgEA2gMAIbgCAgCTBAAhugKAAAAAAQsHAACrBAAgCwAArAQAIBMAAK4EACAUAACvBAAg9QFAANsDACGHAgEA2gMAIYkCAACqBLoCIo4CQADbAwAhmgIBANoDACG4AgIAkwQAIboCgAAAAAEDAAAACwAgKQAA4wYAICoAAO0GACAOAAAACwAgBgAA6QQAIBUAAOoEACAWAADrBAAgFwAA7AQAIBgAAO0EACAiAADtBgAg9QFAANsDACGHAgEA2gMAIYkCAADoBL8CIo4CQADbAwAhuwIBANoDACG8AgEA2gMAIb0CAQDaAwAhDAYAAOkEACAVAADqBAAgFgAA6wQAIBcAAOwEACAYAADtBAAg9QFAANsDACGHAgEA2gMAIYkCAADoBL8CIo4CQADbAwAhuwIBANoDACG8AgEA2gMAIb0CAQDaAwAhAwAAACYAICkAAOUGACAqAADwBgAgDgAAACYAIAQAALcFACAFAAC4BQAgFwAAuwUAIBkAALkFACAaAAC6BQAgHAAAvQUAICIAAPAGACD1AUAA2wMAIYcCAQDaAwAhiQIAALYFxgIijgJAANsDACHDAgEA3AMAIcQCAQDaAwAhDAQAALcFACAFAAC4BQAgFwAAuwUAIBkAALkFACAaAAC6BQAgHAAAvQUAIPUBQADbAwAhhwIBANoDACGJAgAAtgXGAiKOAkAA2wMAIcMCAQDcAwAhxAIBANoDACELBwAAhQQAIAwAAIQEACANAACGBAAg9QFAAAAAAYcCAQAAAAGJAgAAAJ0CAo4CQAAAAAGZAgEAAAABmgIBAAAAAZsCAQAAAAGdAgEAAAABAgAAABsAICkAAPEGACADAAAAGQAgKQAA8QYAICoAAPUGACANAAAAGQAgBwAA9QMAIAwAAPQDACANAAD2AwAgIgAA9QYAIPUBQADbAwAhhwIBANoDACGJAgAA8wOdAiKOAkAA2wMAIZkCAQDaAwAhmgIBANoDACGbAgEA2gMAIZ0CAQDaAwAhCwcAAPUDACAMAAD0AwAgDQAA9gMAIPUBQADbAwAhhwIBANoDACGJAgAA8wOdAiKOAkAA2wMAIZkCAQDaAwAhmgIBANoDACGbAgEA2gMAIZ0CAQDaAwAhDAQAAIkGACAFAACKBgAgFwAAjQYAIBkAAIsGACAaAACMBgAgGwAAjgYAIPUBQAAAAAGHAgEAAAABiQIAAADGAgKOAkAAAAABwwIBAAAAAcQCAQAAAAECAAAAAQAgKQAA9gYAIAsHAADgBAAgCwAA4QQAIBEAAOIEACAUAADkBAAg9QFAAAAAAYcCAQAAAAGJAgAAALoCAo4CQAAAAAGaAgEAAAABuAICAAAAAboCgAAAAAECAAAAEQAgKQAA-AYAIAMAAAAmACApAAD2BgAgKgAA_AYAIA4AAAAmACAEAAC3BQAgBQAAuAUAIBcAALsFACAZAAC5BQAgGgAAugUAIBsAALwFACAiAAD8BgAg9QFAANsDACGHAgEA2gMAIYkCAAC2BcYCIo4CQADbAwAhwwIBANwDACHEAgEA2gMAIQwEAAC3BQAgBQAAuAUAIBcAALsFACAZAAC5BQAgGgAAugUAIBsAALwFACD1AUAA2wMAIYcCAQDaAwAhiQIAALYFxgIijgJAANsDACHDAgEA3AMAIcQCAQDaAwAhAwAAAA8AICkAAPgGACAqAAD_BgAgDQAAAA8AIAcAAKsEACALAACsBAAgEQAArQQAIBQAAK8EACAiAAD_BgAg9QFAANsDACGHAgEA2gMAIYkCAACqBLoCIo4CQADbAwAhmgIBANoDACG4AgIAkwQAIboCgAAAAAELBwAAqwQAIAsAAKwEACARAACtBAAgFAAArwQAIPUBQADbAwAhhwIBANoDACGJAgAAqgS6AiKOAkAA2wMAIZoCAQDaAwAhuAICAJMEACG6AoAAAAABCwcAAOAEACALAADhBAAgEQAA4gQAIBMAAOMEACD1AUAAAAABhwIBAAAAAYkCAAAAugICjgJAAAAAAZoCAQAAAAG4AgIAAAABugKAAAAAAQIAAAARACApAACABwAgAwAAAA8AICkAAIAHACAqAACEBwAgDQAAAA8AIAcAAKsEACALAACsBAAgEQAArQQAIBMAAK4EACAiAACEBwAg9QFAANsDACGHAgEA2gMAIYkCAACqBLoCIo4CQADbAwAhmgIBANoDACG4AgIAkwQAIboCgAAAAAELBwAAqwQAIAsAAKwEACARAACtBAAgEwAArgQAIPUBQADbAwAhhwIBANoDACGJAgAAqgS6AiKOAkAA2wMAIZoCAQDaAwAhuAICAJMEACG6AoAAAAABCAQGAgUKAxAAEBdBBhkOBBpADxtCBxxDCgEDAAEBAwABBwYAARAADhE3BxUSBRY0DRc1Bhg2BgYHAAQLFgYQAAwRHAcTJQoUKwsEBwAECAABCRcEChgFBQcABAwAAQ0ABQ8gCBAACQEOAAcBDyEAAgoABRInAQEKLAUECy0AES4AEy8AFDAAAQcABAURPAAVOAAWOQAXOgAYOwABCAABBwREAAVFABdIABlGABpHABtJABxKAAAAAAMQABUvABYwABcAAAADEAAVLwAWMAAXAQMAAQEDAAEDEAAcLwAdMAAeAAAAAxAAHC8AHTAAHgEDAAEBAwABAxAAIy8AJDAAJQAAAAMQACMvACQwACUBBgABAQYAAQMQACovACswACwAAAADEAAqLwArMAAsAQcABAEHAAQFEAAxLwA0MAA1cQAycgAzAAAAAAAFEAAxLwA0MAA1cQAycgAzAQcABAEHAAQFEAA6LwA9MAA-cQA7cgA8AAAAAAAFEAA6LwA9MAA-cQA7cgA8BAcABAgAAQnZAQQK2gEFBAcABAgAAQngAQQK4QEFBRAAQy8ARjAAR3EARHIARQAAAAAABRAAQy8ARjAAR3EARHIARQEIAAEBCAABAxAATC8ATTAATgAAAAMQAEwvAE0wAE4DBwAEDAABDQAFAwcABAwAAQ0ABQMQAFMvAFQwAFUAAAADEABTLwBUMABVAQ4ABwEOAAcDEABaLwBbMABcAAAAAxAAWi8AWzAAXAIKAAUStQIBAgoABRK7AgEDEABhLwBiMABjAAAAAxAAYS8AYjAAYwEKzQIFAQrTAgUDEABoLwBpMABqAAAAAxAAaC8AaTAAah0CAR5LAR9NASBOASFPASNRASRTESVUEiZWASdYEShZEytaASxbAS1cETFfFDJgGDNhAjRiAjVjAjZkAjdlAjhnAjlpETpqGTtsAjxuET1vGj5wAj9xAkByEUF1G0J2H0N3A0R4A0V5A0Z6A0d7A0h9A0l_EUqAASBLggEDTIQBEU2FASFOhgEDT4cBA1CIARFRiwEiUowBJlONAQRUjgEEVY8BBFaQAQRXkQEEWJMBBFmVARFalgEnW5gBBFyaARFdmwEoXpwBBF-dAQRgngERYaEBKWKiAS1jowEFZKQBBWWlAQVmpgEFZ6cBBWipAQVpqwERaqwBLmuuAQVssAERbbEBL26yAQVvswEFcLQBEXO3ATB0uAE2dbkBDXa6AQ13uwENeLwBDXm9AQ16vwENe8EBEXzCATd9xAENfsYBEX_HATiAAcgBDYEByQENggHKARGDAc0BOYQBzgE_hQHPAQaGAdABBocB0QEGiAHSAQaJAdMBBooB1QEGiwHXARGMAdgBQI0B3AEGjgHeARGPAd8BQZAB4gEGkQHjAQaSAeQBEZMB5wFClAHoAUiVAekBD5YB6gEPlwHrAQ-YAewBD5kB7QEPmgHvAQ-bAfEBEZwB8gFJnQH0AQ-eAfYBEZ8B9wFKoAH4AQ-hAfkBD6IB-gERowH9AUukAf4BT6UB_wEHpgGAAgenAYECB6gBggIHqQGDAgeqAYUCB6sBhwIRrAGIAlCtAYoCB64BjAIRrwGNAlGwAY4CB7EBjwIHsgGQAhGzAZMCUrQBlAJWtQGVAgi2AZYCCLcBlwIIuAGYAgi5AZkCCLoBmwIIuwGdAhG8AZ4CV70BoAIIvgGiAhG_AaMCWMABpAIIwQGlAgjCAaYCEcMBqQJZxAGqAl3FAasCCsYBrAIKxwGtAgrIAa4CCskBrwIKygGxAgrLAbMCEcwBtAJezQG3AgrOAbkCEc8BugJf0AG8AgrRAb0CCtIBvgIR0wHBAmDUAcICZNUBwwIL1gHEAgvXAcUCC9gBxgIL2QHHAgvaAckCC9sBywIR3AHMAmXdAc8CC94B0QIR3wHSAmbgAdQCC-EB1QIL4gHWAhHjAdkCZ-QB2gJr" +} + +async function decodeBase64AsWasm(wasmBase64: string): Promise { + const { Buffer } = await import('node:buffer') + const wasmArray = Buffer.from(wasmBase64, 'base64') + return new WebAssembly.Module(wasmArray) +} + +config.compilerWasm = { + getRuntime: async () => await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.mjs"), + + getQueryCompilerWasmModule: async () => { + const { wasm } = await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.wasm-base64.mjs") + return await decodeBase64AsWasm(wasm) + }, + + importName: "./query_compiler_fast_bg.js" +} + + + +export type LogOptions = + 'log' extends keyof ClientOptions ? ClientOptions['log'] extends Array ? Prisma.GetEvents : never : never + +export interface PrismaClientConstructor { + /** + * ## Prisma Client + * + * Type-safe database client for TypeScript + * @example + * ``` + * const prisma = new PrismaClient({ + * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) + * }) + * // Fetch zero or more Users + * const users = await prisma.user.findMany() + * ``` + * + * Read more in our [docs](https://pris.ly/d/client). + */ + + new < + Options extends Prisma.PrismaClientOptions = Prisma.PrismaClientOptions, + LogOpts extends LogOptions = LogOptions, + OmitOpts extends Prisma.PrismaClientOptions['omit'] = Options extends { omit: infer U } ? U : Prisma.PrismaClientOptions['omit'], + ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs + >(options: Prisma.Subset ): PrismaClient +} + +/** + * ## Prisma Client + * + * Type-safe database client for TypeScript + * @example + * ``` + * const prisma = new PrismaClient({ + * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }) + * }) + * // Fetch zero or more Users + * const users = await prisma.user.findMany() + * ``` + * + * Read more in our [docs](https://pris.ly/d/client). + */ + +export interface PrismaClient< + in LogOpts extends Prisma.LogLevel = never, + in out OmitOpts extends Prisma.PrismaClientOptions['omit'] = undefined, + in out ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs +> { + [K: symbol]: { types: Prisma.TypeMap['other'] } + + $on(eventType: V, callback: (event: V extends 'query' ? Prisma.QueryEvent : Prisma.LogEvent) => void): PrismaClient; + + /** + * Connect with the database + */ + $connect(): runtime.Types.Utils.JsPromise; + + /** + * Disconnect from the database + */ + $disconnect(): runtime.Types.Utils.JsPromise; + +/** + * Executes a prepared raw query and returns the number of affected rows. + * @example + * ``` + * const result = await prisma.$executeRaw`UPDATE User SET cool = ${true} WHERE email = ${'user@email.com'};` + * ``` + * + * Read more in our [docs](https://pris.ly/d/raw-queries). + */ + $executeRaw(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise; + + /** + * Executes a raw query and returns the number of affected rows. + * Susceptible to SQL injections, see documentation. + * @example + * ``` + * const result = await prisma.$executeRawUnsafe('UPDATE User SET cool = $1 WHERE email = $2 ;', true, 'user@email.com') + * ``` + * + * Read more in our [docs](https://pris.ly/d/raw-queries). + */ + $executeRawUnsafe(query: string, ...values: any[]): Prisma.PrismaPromise; + + /** + * Performs a prepared raw query and returns the `SELECT` data. + * @example + * ``` + * const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${1} OR email = ${'user@email.com'};` + * ``` + * + * Read more in our [docs](https://pris.ly/d/raw-queries). + */ + $queryRaw(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise; + + /** + * Performs a raw query and returns the `SELECT` data. + * Susceptible to SQL injections, see documentation. + * @example + * ``` + * const result = await prisma.$queryRawUnsafe('SELECT * FROM User WHERE id = $1 OR email = $2;', 1, 'user@email.com') + * ``` + * + * Read more in our [docs](https://pris.ly/d/raw-queries). + */ + $queryRawUnsafe(query: string, ...values: any[]): Prisma.PrismaPromise; + + + /** + * Allows the running of a sequence of read/write operations that are guaranteed to either succeed or fail as a whole. + * @example + * ``` + * const [george, bob, alice] = await prisma.$transaction([ + * prisma.user.create({ data: { name: 'George' } }), + * prisma.user.create({ data: { name: 'Bob' } }), + * prisma.user.create({ data: { name: 'Alice' } }), + * ]) + * ``` + * + * Read more in our [docs](https://www.prisma.io/docs/orm/prisma-client/queries/transactions). + */ + $transaction

[]>(arg: [...P], options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise> + + $transaction(fn: (prisma: Omit) => runtime.Types.Utils.JsPromise, options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise + + $extends: runtime.Types.Extensions.ExtendsHook<"extends", Prisma.TypeMapCb, ExtArgs, runtime.Types.Utils.Call, { + extArgs: ExtArgs + }>> + + /** + * `prisma.user`: Exposes CRUD operations for the **User** model. + * Example usage: + * ```ts + * // Fetch zero or more Users + * const users = await prisma.user.findMany() + * ``` + */ + get user(): Prisma.UserDelegate; + + /** + * `prisma.userRole`: Exposes CRUD operations for the **UserRole** model. + * Example usage: + * ```ts + * // Fetch zero or more UserRoles + * const userRoles = await prisma.userRole.findMany() + * ``` + */ + get userRole(): Prisma.UserRoleDelegate; + + /** + * `prisma.anonymousIdentity`: Exposes CRUD operations for the **AnonymousIdentity** model. + * Example usage: + * ```ts + * // Fetch zero or more AnonymousIdentities + * const anonymousIdentities = await prisma.anonymousIdentity.findMany() + * ``` + */ + get anonymousIdentity(): Prisma.AnonymousIdentityDelegate; + + /** + * `prisma.gameProject`: Exposes CRUD operations for the **GameProject** model. + * Example usage: + * ```ts + * // Fetch zero or more GameProjects + * const gameProjects = await prisma.gameProject.findMany() + * ``` + */ + get gameProject(): Prisma.GameProjectDelegate; + + /** + * `prisma.gameVersion`: Exposes CRUD operations for the **GameVersion** model. + * Example usage: + * ```ts + * // Fetch zero or more GameVersions + * const gameVersions = await prisma.gameVersion.findMany() + * ``` + */ + get gameVersion(): Prisma.GameVersionDelegate; + + /** + * `prisma.asset`: Exposes CRUD operations for the **Asset** model. + * Example usage: + * ```ts + * // Fetch zero or more Assets + * const assets = await prisma.asset.findMany() + * ``` + */ + get asset(): Prisma.AssetDelegate; + + /** + * `prisma.job`: Exposes CRUD operations for the **Job** model. + * Example usage: + * ```ts + * // Fetch zero or more Jobs + * const jobs = await prisma.job.findMany() + * ``` + */ + get job(): Prisma.JobDelegate; + + /** + * `prisma.auditLog`: Exposes CRUD operations for the **AuditLog** model. + * Example usage: + * ```ts + * // Fetch zero or more AuditLogs + * const auditLogs = await prisma.auditLog.findMany() + * ``` + */ + get auditLog(): Prisma.AuditLogDelegate; + + /** + * `prisma.mainCreationAgentSession`: Exposes CRUD operations for the **MainCreationAgentSession** model. + * Example usage: + * ```ts + * // Fetch zero or more MainCreationAgentSessions + * const mainCreationAgentSessions = await prisma.mainCreationAgentSession.findMany() + * ``` + */ + get mainCreationAgentSession(): Prisma.MainCreationAgentSessionDelegate; + + /** + * `prisma.agentTask`: Exposes CRUD operations for the **AgentTask** model. + * Example usage: + * ```ts + * // Fetch zero or more AgentTasks + * const agentTasks = await prisma.agentTask.findMany() + * ``` + */ + get agentTask(): Prisma.AgentTaskDelegate; + + /** + * `prisma.reviewRecord`: Exposes CRUD operations for the **ReviewRecord** model. + * Example usage: + * ```ts + * // Fetch zero or more ReviewRecords + * const reviewRecords = await prisma.reviewRecord.findMany() + * ``` + */ + get reviewRecord(): Prisma.ReviewRecordDelegate; + + /** + * `prisma.lifecycleEvent`: Exposes CRUD operations for the **LifecycleEvent** model. + * Example usage: + * ```ts + * // Fetch zero or more LifecycleEvents + * const lifecycleEvents = await prisma.lifecycleEvent.findMany() + * ``` + */ + get lifecycleEvent(): Prisma.LifecycleEventDelegate; +} + +export function getPrismaClientClass(): PrismaClientConstructor { + return runtime.getPrismaClient(config) as unknown as PrismaClientConstructor +} diff --git a/apps/api/src/generated/prisma/internal/prismaNamespace.ts b/apps/api/src/generated/prisma/internal/prismaNamespace.ts new file mode 100644 index 00000000..8e307077 --- /dev/null +++ b/apps/api/src/generated/prisma/internal/prismaNamespace.ts @@ -0,0 +1,2004 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * WARNING: This is an internal file that is subject to change! + * + * 🛑 Under no circumstances should you import this file directly! 🛑 + * + * All exports from this file are wrapped under a `Prisma` namespace object in the client.ts file. + * While this enables partial backward compatibility, it is not part of the stable public API. + * + * If you are looking for your Models, Enums, and Input Types, please import them from the respective + * model files in the `model` directory! + */ + +import * as runtime from "@prisma/client/runtime/client" +import type * as Prisma from "../models.js" +import { type PrismaClient } from "./class.js" + +export type * from '../models.js' + +export type DMMF = typeof runtime.DMMF + +export type PrismaPromise = runtime.Types.Public.PrismaPromise + +/** + * Prisma Errors + */ + +export const PrismaClientKnownRequestError = runtime.PrismaClientKnownRequestError +export type PrismaClientKnownRequestError = runtime.PrismaClientKnownRequestError + +export const PrismaClientUnknownRequestError = runtime.PrismaClientUnknownRequestError +export type PrismaClientUnknownRequestError = runtime.PrismaClientUnknownRequestError + +export const PrismaClientRustPanicError = runtime.PrismaClientRustPanicError +export type PrismaClientRustPanicError = runtime.PrismaClientRustPanicError + +export const PrismaClientInitializationError = runtime.PrismaClientInitializationError +export type PrismaClientInitializationError = runtime.PrismaClientInitializationError + +export const PrismaClientValidationError = runtime.PrismaClientValidationError +export type PrismaClientValidationError = runtime.PrismaClientValidationError + +/** + * Re-export of sql-template-tag + */ +export const sql = runtime.sqltag +export const empty = runtime.empty +export const join = runtime.join +export const raw = runtime.raw +export const Sql = runtime.Sql +export type Sql = runtime.Sql + + + +/** + * Decimal.js + */ +export const Decimal = runtime.Decimal +export type Decimal = runtime.Decimal + +export type DecimalJsLike = runtime.DecimalJsLike + +/** +* Extensions +*/ +export type Extension = runtime.Types.Extensions.UserArgs +export const getExtensionContext = runtime.Extensions.getExtensionContext +export type Args = runtime.Types.Public.Args +export type Payload = runtime.Types.Public.Payload +export type Result = runtime.Types.Public.Result +export type Exact = runtime.Types.Public.Exact + +export type PrismaVersion = { + client: string + engine: string +} + +/** + * Prisma Client JS version: 7.8.0 + * Query Engine version: 3c6e192761c0362d496ed980de936e2f3cebcd3a + */ +export const prismaVersion: PrismaVersion = { + client: "7.8.0", + engine: "3c6e192761c0362d496ed980de936e2f3cebcd3a" +} + +/** + * Utility Types + */ + +export type Bytes = runtime.Bytes +export type JsonObject = runtime.JsonObject +export type JsonArray = runtime.JsonArray +export type JsonValue = runtime.JsonValue +export type InputJsonObject = runtime.InputJsonObject +export type InputJsonArray = runtime.InputJsonArray +export type InputJsonValue = runtime.InputJsonValue + + +export const NullTypes = { + DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull), + JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull), + AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull), +} +/** + * Helper for filtering JSON entries that have `null` on the database (empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const DbNull = runtime.DbNull + +/** + * Helper for filtering JSON entries that have JSON `null` values (not empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const JsonNull = runtime.JsonNull + +/** + * Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull` + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const AnyNull = runtime.AnyNull + + +type SelectAndInclude = { + select: any + include: any +} + +type SelectAndOmit = { + select: any + omit: any +} + +/** + * From T, pick a set of properties whose keys are in the union K + */ +type Prisma__Pick = { + [P in K]: T[P]; +}; + +export type Enumerable = T | Array; + +/** + * Subset + * @desc From `T` pick properties that exist in `U`. Simple version of Intersection + */ +export type Subset = { + [key in keyof T]: key extends keyof U ? T[key] : never; +}; + +/** + * SelectSubset + * @desc From `T` pick properties that exist in `U`. Simple version of Intersection. + * Additionally, it validates, if both select and include are present. If the case, it errors. + */ +export type SelectSubset = { + [key in keyof T]: key extends keyof U ? T[key] : never +} & + (T extends SelectAndInclude + ? 'Please either choose `select` or `include`.' + : T extends SelectAndOmit + ? 'Please either choose `select` or `omit`.' + : {}) + +/** + * Subset + Intersection + * @desc From `T` pick properties that exist in `U` and intersect `K` + */ +export type SubsetIntersection = { + [key in keyof T]: key extends keyof U ? T[key] : never +} & + K + +type Without = { [P in Exclude]?: never }; + +/** + * XOR is needed to have a real mutually exclusive union type + * https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types + */ +export type XOR = + T extends object ? + U extends object ? + (Without & U) | (Without & T) + : U : T + + +/** + * Is T a Record? + */ +type IsObject = T extends Array +? False +: T extends Date +? False +: T extends Uint8Array +? False +: T extends BigInt +? False +: T extends object +? True +: False + + +/** + * If it's T[], return T + */ +export type UnEnumerate = T extends Array ? U : T + +/** + * From ts-toolbelt + */ + +type __Either = Omit & + { + // Merge all but K + [P in K]: Prisma__Pick // With K possibilities + }[K] + +type EitherStrict = Strict<__Either> + +type EitherLoose = ComputeRaw<__Either> + +type _Either< + O extends object, + K extends Key, + strict extends Boolean +> = { + 1: EitherStrict + 0: EitherLoose +}[strict] + +export type Either< + O extends object, + K extends Key, + strict extends Boolean = 1 +> = O extends unknown ? _Either : never + +export type Union = any + +export type PatchUndefined = { + [K in keyof O]: O[K] extends undefined ? At : O[K] +} & {} + +/** Helper Types for "Merge" **/ +export type IntersectOf = ( + U extends unknown ? (k: U) => void : never +) extends (k: infer I) => void + ? I + : never + +export type Overwrite = { + [K in keyof O]: K extends keyof O1 ? O1[K] : O[K]; +} & {}; + +type _Merge = IntersectOf; +}>>; + +type Key = string | number | symbol; +type AtStrict = O[K & keyof O]; +type AtLoose = O extends unknown ? AtStrict : never; +export type At = { + 1: AtStrict; + 0: AtLoose; +}[strict]; + +export type ComputeRaw = A extends Function ? A : { + [K in keyof A]: A[K]; +} & {}; + +export type OptionalFlat = { + [K in keyof O]?: O[K]; +} & {}; + +type _Record = { + [P in K]: T; +}; + +// cause typescript not to expand types and preserve names +type NoExpand = T extends unknown ? T : never; + +// this type assumes the passed object is entirely optional +export type AtLeast = NoExpand< + O extends unknown + ? | (K extends keyof O ? { [P in K]: O[P] } & O : O) + | {[P in keyof O as P extends K ? P : never]-?: O[P]} & O + : never>; + +type _Strict = U extends unknown ? U & OptionalFlat<_Record, keyof U>, never>> : never; + +export type Strict = ComputeRaw<_Strict>; +/** End Helper Types for "Merge" **/ + +export type Merge = ComputeRaw<_Merge>>; + +export type Boolean = True | False + +export type True = 1 + +export type False = 0 + +export type Not = { + 0: 1 + 1: 0 +}[B] + +export type Extends = [A1] extends [never] + ? 0 // anything `never` is false + : A1 extends A2 + ? 1 + : 0 + +export type Has = Not< + Extends, U1> +> + +export type Or = { + 0: { + 0: 0 + 1: 1 + } + 1: { + 0: 1 + 1: 1 + } +}[B1][B2] + +export type Keys = U extends unknown ? keyof U : never + +export type GetScalarType = O extends object ? { + [P in keyof T]: P extends keyof O + ? O[P] + : never +} : never + +type FieldPaths< + T, + U = Omit +> = IsObject extends True ? U : T + +export type GetHavingFields = { + [K in keyof T]: Or< + Or, Extends<'AND', K>>, + Extends<'NOT', K> + > extends True + ? // infer is only needed to not hit TS limit + // based on the brilliant idea of Pierre-Antoine Mills + // https://github.com/microsoft/TypeScript/issues/30188#issuecomment-478938437 + T[K] extends infer TK + ? GetHavingFields extends object ? Merge> : never> + : never + : {} extends FieldPaths + ? never + : K +}[keyof T] + +/** + * Convert tuple to union + */ +type _TupleToUnion = T extends (infer E)[] ? E : never +type TupleToUnion = _TupleToUnion +export type MaybeTupleToUnion = T extends any[] ? TupleToUnion : T + +/** + * Like `Pick`, but additionally can also accept an array of keys + */ +export type PickEnumerable | keyof T> = Prisma__Pick> + +/** + * Exclude all keys with underscores + */ +export type ExcludeUnderscoreKeys = T extends `_${string}` ? never : T + + +export type FieldRef = runtime.FieldRef + +type FieldRefInputType = Model extends never ? never : FieldRef + + +export const ModelName = { + User: 'User', + UserRole: 'UserRole', + AnonymousIdentity: 'AnonymousIdentity', + GameProject: 'GameProject', + GameVersion: 'GameVersion', + Asset: 'Asset', + Job: 'Job', + AuditLog: 'AuditLog', + MainCreationAgentSession: 'MainCreationAgentSession', + AgentTask: 'AgentTask', + ReviewRecord: 'ReviewRecord', + LifecycleEvent: 'LifecycleEvent' +} as const + +export type ModelName = (typeof ModelName)[keyof typeof ModelName] + + + +export interface TypeMapCb extends runtime.Types.Utils.Fn<{extArgs: runtime.Types.Extensions.InternalArgs }, runtime.Types.Utils.Record> { + returns: TypeMap +} + +export type TypeMap = { + globalOmitOptions: { + omit: GlobalOmitOptions + } + meta: { + modelProps: "user" | "userRole" | "anonymousIdentity" | "gameProject" | "gameVersion" | "asset" | "job" | "auditLog" | "mainCreationAgentSession" | "agentTask" | "reviewRecord" | "lifecycleEvent" + txIsolationLevel: TransactionIsolationLevel + } + model: { + User: { + payload: Prisma.$UserPayload + fields: Prisma.UserFieldRefs + operations: { + findUnique: { + args: Prisma.UserFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.UserFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.UserFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.UserFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.UserFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.UserCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.UserCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.UserCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.UserDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.UserUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.UserDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.UserUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.UserUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.UserUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.UserAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.UserGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.UserCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + UserRole: { + payload: Prisma.$UserRolePayload + fields: Prisma.UserRoleFieldRefs + operations: { + findUnique: { + args: Prisma.UserRoleFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.UserRoleFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.UserRoleFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.UserRoleFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.UserRoleFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.UserRoleCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.UserRoleCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.UserRoleCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.UserRoleDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.UserRoleUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.UserRoleDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.UserRoleUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.UserRoleUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.UserRoleUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.UserRoleAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.UserRoleGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.UserRoleCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + AnonymousIdentity: { + payload: Prisma.$AnonymousIdentityPayload + fields: Prisma.AnonymousIdentityFieldRefs + operations: { + findUnique: { + args: Prisma.AnonymousIdentityFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.AnonymousIdentityFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.AnonymousIdentityFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.AnonymousIdentityFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.AnonymousIdentityFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.AnonymousIdentityCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.AnonymousIdentityCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.AnonymousIdentityCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.AnonymousIdentityDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.AnonymousIdentityUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.AnonymousIdentityDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.AnonymousIdentityUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.AnonymousIdentityUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.AnonymousIdentityUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.AnonymousIdentityAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.AnonymousIdentityGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.AnonymousIdentityCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + GameProject: { + payload: Prisma.$GameProjectPayload + fields: Prisma.GameProjectFieldRefs + operations: { + findUnique: { + args: Prisma.GameProjectFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.GameProjectFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.GameProjectFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.GameProjectFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.GameProjectFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.GameProjectCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.GameProjectCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.GameProjectCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.GameProjectDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.GameProjectUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.GameProjectDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.GameProjectUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.GameProjectUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.GameProjectUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.GameProjectAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.GameProjectGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.GameProjectCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + GameVersion: { + payload: Prisma.$GameVersionPayload + fields: Prisma.GameVersionFieldRefs + operations: { + findUnique: { + args: Prisma.GameVersionFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.GameVersionFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.GameVersionFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.GameVersionFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.GameVersionFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.GameVersionCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.GameVersionCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.GameVersionCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.GameVersionDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.GameVersionUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.GameVersionDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.GameVersionUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.GameVersionUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.GameVersionUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.GameVersionAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.GameVersionGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.GameVersionCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + Asset: { + payload: Prisma.$AssetPayload + fields: Prisma.AssetFieldRefs + operations: { + findUnique: { + args: Prisma.AssetFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.AssetFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.AssetFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.AssetFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.AssetFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.AssetCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.AssetCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.AssetCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.AssetDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.AssetUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.AssetDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.AssetUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.AssetUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.AssetUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.AssetAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.AssetGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.AssetCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + Job: { + payload: Prisma.$JobPayload + fields: Prisma.JobFieldRefs + operations: { + findUnique: { + args: Prisma.JobFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.JobFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.JobFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.JobFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.JobFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.JobCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.JobCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.JobCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.JobDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.JobUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.JobDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.JobUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.JobUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.JobUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.JobAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.JobGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.JobCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + AuditLog: { + payload: Prisma.$AuditLogPayload + fields: Prisma.AuditLogFieldRefs + operations: { + findUnique: { + args: Prisma.AuditLogFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.AuditLogFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.AuditLogFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.AuditLogFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.AuditLogFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.AuditLogCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.AuditLogCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.AuditLogCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.AuditLogDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.AuditLogUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.AuditLogDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.AuditLogUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.AuditLogUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.AuditLogUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.AuditLogAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.AuditLogGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.AuditLogCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + MainCreationAgentSession: { + payload: Prisma.$MainCreationAgentSessionPayload + fields: Prisma.MainCreationAgentSessionFieldRefs + operations: { + findUnique: { + args: Prisma.MainCreationAgentSessionFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.MainCreationAgentSessionFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.MainCreationAgentSessionFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.MainCreationAgentSessionFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.MainCreationAgentSessionFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.MainCreationAgentSessionCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.MainCreationAgentSessionCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.MainCreationAgentSessionCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.MainCreationAgentSessionDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.MainCreationAgentSessionUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.MainCreationAgentSessionDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.MainCreationAgentSessionUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.MainCreationAgentSessionUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.MainCreationAgentSessionUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.MainCreationAgentSessionAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.MainCreationAgentSessionGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.MainCreationAgentSessionCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + AgentTask: { + payload: Prisma.$AgentTaskPayload + fields: Prisma.AgentTaskFieldRefs + operations: { + findUnique: { + args: Prisma.AgentTaskFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.AgentTaskFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.AgentTaskFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.AgentTaskFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.AgentTaskFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.AgentTaskCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.AgentTaskCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.AgentTaskCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.AgentTaskDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.AgentTaskUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.AgentTaskDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.AgentTaskUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.AgentTaskUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.AgentTaskUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.AgentTaskAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.AgentTaskGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.AgentTaskCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + ReviewRecord: { + payload: Prisma.$ReviewRecordPayload + fields: Prisma.ReviewRecordFieldRefs + operations: { + findUnique: { + args: Prisma.ReviewRecordFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.ReviewRecordFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.ReviewRecordFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.ReviewRecordFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.ReviewRecordFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.ReviewRecordCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.ReviewRecordCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.ReviewRecordCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.ReviewRecordDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.ReviewRecordUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.ReviewRecordDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.ReviewRecordUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.ReviewRecordUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.ReviewRecordUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.ReviewRecordAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.ReviewRecordGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.ReviewRecordCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + LifecycleEvent: { + payload: Prisma.$LifecycleEventPayload + fields: Prisma.LifecycleEventFieldRefs + operations: { + findUnique: { + args: Prisma.LifecycleEventFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.LifecycleEventFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.LifecycleEventFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.LifecycleEventFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.LifecycleEventFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.LifecycleEventCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.LifecycleEventCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.LifecycleEventCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.LifecycleEventDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.LifecycleEventUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.LifecycleEventDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.LifecycleEventUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.LifecycleEventUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.LifecycleEventUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.LifecycleEventAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.LifecycleEventGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.LifecycleEventCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + } +} & { + other: { + payload: any + operations: { + $executeRaw: { + args: [query: TemplateStringsArray | Sql, ...values: any[]], + result: any + } + $executeRawUnsafe: { + args: [query: string, ...values: any[]], + result: any + } + $queryRaw: { + args: [query: TemplateStringsArray | Sql, ...values: any[]], + result: any + } + $queryRawUnsafe: { + args: [query: string, ...values: any[]], + result: any + } + } + } +} + +/** + * Enums + */ + +export const TransactionIsolationLevel = runtime.makeStrictEnum({ + ReadUncommitted: 'ReadUncommitted', + ReadCommitted: 'ReadCommitted', + RepeatableRead: 'RepeatableRead', + Serializable: 'Serializable' +} as const) + +export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel] + + +export const UserScalarFieldEnum = { + id: 'id', + email: 'email', + displayName: 'displayName', + status: 'status', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] + + +export const UserRoleScalarFieldEnum = { + id: 'id', + userId: 'userId', + role: 'role', + createdAt: 'createdAt' +} as const + +export type UserRoleScalarFieldEnum = (typeof UserRoleScalarFieldEnum)[keyof typeof UserRoleScalarFieldEnum] + + +export const AnonymousIdentityScalarFieldEnum = { + id: 'id', + userId: 'userId', + deviceKey: 'deviceKey', + createdAt: 'createdAt' +} as const + +export type AnonymousIdentityScalarFieldEnum = (typeof AnonymousIdentityScalarFieldEnum)[keyof typeof AnonymousIdentityScalarFieldEnum] + + +export const GameProjectScalarFieldEnum = { + id: 'id', + ownerId: 'ownerId', + slug: 'slug', + title: 'title', + status: 'status', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type GameProjectScalarFieldEnum = (typeof GameProjectScalarFieldEnum)[keyof typeof GameProjectScalarFieldEnum] + + +export const GameVersionScalarFieldEnum = { + id: 'id', + projectId: 'projectId', + versionNumber: 'versionNumber', + status: 'status', + configJson: 'configJson', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type GameVersionScalarFieldEnum = (typeof GameVersionScalarFieldEnum)[keyof typeof GameVersionScalarFieldEnum] + + +export const AssetScalarFieldEnum = { + id: 'id', + projectId: 'projectId', + kind: 'kind', + storageKey: 'storageKey', + mimeType: 'mimeType', + byteSize: 'byteSize', + sha256: 'sha256', + status: 'status', + metadataJson: 'metadataJson', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type AssetScalarFieldEnum = (typeof AssetScalarFieldEnum)[keyof typeof AssetScalarFieldEnum] + + +export const JobScalarFieldEnum = { + id: 'id', + actorId: 'actorId', + projectId: 'projectId', + type: 'type', + idempotencyKey: 'idempotencyKey', + status: 'status', + attempts: 'attempts', + maxAttempts: 'maxAttempts', + timeoutAt: 'timeoutAt', + nextRetryAt: 'nextRetryAt', + errorCode: 'errorCode', + leaseToken: 'leaseToken', + leasedBy: 'leasedBy', + leaseExpiresAt: 'leaseExpiresAt', + lockVersion: 'lockVersion', + targetType: 'targetType', + targetId: 'targetId', + targetScopeKey: 'targetScopeKey', + gameProjectId: 'gameProjectId', + gameVersionId: 'gameVersionId', + payloadJson: 'payloadJson', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type JobScalarFieldEnum = (typeof JobScalarFieldEnum)[keyof typeof JobScalarFieldEnum] + + +export const AuditLogScalarFieldEnum = { + id: 'id', + actorId: 'actorId', + action: 'action', + targetType: 'targetType', + targetId: 'targetId', + eventJson: 'eventJson', + createdAt: 'createdAt' +} as const + +export type AuditLogScalarFieldEnum = (typeof AuditLogScalarFieldEnum)[keyof typeof AuditLogScalarFieldEnum] + + +export const MainCreationAgentSessionScalarFieldEnum = { + id: 'id', + creatorId: 'creatorId', + projectId: 'projectId', + versionId: 'versionId', + status: 'status', + contextSummary: 'contextSummary', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type MainCreationAgentSessionScalarFieldEnum = (typeof MainCreationAgentSessionScalarFieldEnum)[keyof typeof MainCreationAgentSessionScalarFieldEnum] + + +export const AgentTaskScalarFieldEnum = { + id: 'id', + sessionId: 'sessionId', + taskType: 'taskType', + subagentId: 'subagentId', + inputRef: 'inputRef', + outputRef: 'outputRef', + status: 'status', + timeoutAt: 'timeoutAt', + errorCode: 'errorCode', + auditLogId: 'auditLogId', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type AgentTaskScalarFieldEnum = (typeof AgentTaskScalarFieldEnum)[keyof typeof AgentTaskScalarFieldEnum] + + +export const ReviewRecordScalarFieldEnum = { + id: 'id', + gameVersionId: 'gameVersionId', + status: 'status', + decision: 'decision', + reasonCode: 'reasonCode', + decidedById: 'decidedById', + decidedAt: 'decidedAt', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type ReviewRecordScalarFieldEnum = (typeof ReviewRecordScalarFieldEnum)[keyof typeof ReviewRecordScalarFieldEnum] + + +export const LifecycleEventScalarFieldEnum = { + eventId: 'eventId', + gameVersionId: 'gameVersionId', + event: 'event', + from: 'from', + to: 'to', + actorJson: 'actorJson', + requiredRole: 'requiredRole', + requiredRecordRefsJson: 'requiredRecordRefsJson', + auditEvent: 'auditEvent', + reasonCode: 'reasonCode', + occurredAt: 'occurredAt', + approval: 'approval', + requiredRecordsJson: 'requiredRecordsJson', + createdAt: 'createdAt' +} as const + +export type LifecycleEventScalarFieldEnum = (typeof LifecycleEventScalarFieldEnum)[keyof typeof LifecycleEventScalarFieldEnum] + + +export const SortOrder = { + asc: 'asc', + desc: 'desc' +} as const + +export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder] + + +export const JsonNullValueInput = { + JsonNull: JsonNull +} as const + +export type JsonNullValueInput = (typeof JsonNullValueInput)[keyof typeof JsonNullValueInput] + + +export const NullableJsonNullValueInput = { + DbNull: DbNull, + JsonNull: JsonNull +} as const + +export type NullableJsonNullValueInput = (typeof NullableJsonNullValueInput)[keyof typeof NullableJsonNullValueInput] + + +export const QueryMode = { + default: 'default', + insensitive: 'insensitive' +} as const + +export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode] + + +export const NullsOrder = { + first: 'first', + last: 'last' +} as const + +export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder] + + +export const JsonNullValueFilter = { + DbNull: DbNull, + JsonNull: JsonNull, + AnyNull: AnyNull +} as const + +export type JsonNullValueFilter = (typeof JsonNullValueFilter)[keyof typeof JsonNullValueFilter] + + + +/** + * Field references + */ + + +/** + * Reference to a field of type 'String' + */ +export type StringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'String'> + + + +/** + * Reference to a field of type 'String[]' + */ +export type ListStringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'String[]'> + + + +/** + * Reference to a field of type 'UserStatus' + */ +export type EnumUserStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'UserStatus'> + + + +/** + * Reference to a field of type 'UserStatus[]' + */ +export type ListEnumUserStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'UserStatus[]'> + + + +/** + * Reference to a field of type 'DateTime' + */ +export type DateTimeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'DateTime'> + + + +/** + * Reference to a field of type 'DateTime[]' + */ +export type ListDateTimeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'DateTime[]'> + + + +/** + * Reference to a field of type 'UserRoleName' + */ +export type EnumUserRoleNameFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'UserRoleName'> + + + +/** + * Reference to a field of type 'UserRoleName[]' + */ +export type ListEnumUserRoleNameFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'UserRoleName[]'> + + + +/** + * Reference to a field of type 'ProjectStatus' + */ +export type EnumProjectStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ProjectStatus'> + + + +/** + * Reference to a field of type 'ProjectStatus[]' + */ +export type ListEnumProjectStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ProjectStatus[]'> + + + +/** + * Reference to a field of type 'Int' + */ +export type IntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int'> + + + +/** + * Reference to a field of type 'Int[]' + */ +export type ListIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int[]'> + + + +/** + * Reference to a field of type 'GameVersionStatus' + */ +export type EnumGameVersionStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'GameVersionStatus'> + + + +/** + * Reference to a field of type 'GameVersionStatus[]' + */ +export type ListEnumGameVersionStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'GameVersionStatus[]'> + + + +/** + * Reference to a field of type 'Json' + */ +export type JsonFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Json'> + + + +/** + * Reference to a field of type 'QueryMode' + */ +export type EnumQueryModeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'QueryMode'> + + + +/** + * Reference to a field of type 'AssetStatus' + */ +export type EnumAssetStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'AssetStatus'> + + + +/** + * Reference to a field of type 'AssetStatus[]' + */ +export type ListEnumAssetStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'AssetStatus[]'> + + + +/** + * Reference to a field of type 'JobStatus' + */ +export type EnumJobStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'JobStatus'> + + + +/** + * Reference to a field of type 'JobStatus[]' + */ +export type ListEnumJobStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'JobStatus[]'> + + + +/** + * Reference to a field of type 'JobTargetType' + */ +export type EnumJobTargetTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'JobTargetType'> + + + +/** + * Reference to a field of type 'JobTargetType[]' + */ +export type ListEnumJobTargetTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'JobTargetType[]'> + + + +/** + * Reference to a field of type 'MainCreationAgentSessionStatus' + */ +export type EnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'MainCreationAgentSessionStatus'> + + + +/** + * Reference to a field of type 'MainCreationAgentSessionStatus[]' + */ +export type ListEnumMainCreationAgentSessionStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'MainCreationAgentSessionStatus[]'> + + + +/** + * Reference to a field of type 'AgentTaskType' + */ +export type EnumAgentTaskTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'AgentTaskType'> + + + +/** + * Reference to a field of type 'AgentTaskType[]' + */ +export type ListEnumAgentTaskTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'AgentTaskType[]'> + + + +/** + * Reference to a field of type 'AgentTaskStatus' + */ +export type EnumAgentTaskStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'AgentTaskStatus'> + + + +/** + * Reference to a field of type 'AgentTaskStatus[]' + */ +export type ListEnumAgentTaskStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'AgentTaskStatus[]'> + + + +/** + * Reference to a field of type 'ReviewRecordStatus' + */ +export type EnumReviewRecordStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ReviewRecordStatus'> + + + +/** + * Reference to a field of type 'ReviewRecordStatus[]' + */ +export type ListEnumReviewRecordStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ReviewRecordStatus[]'> + + + +/** + * Reference to a field of type 'ReviewDecision' + */ +export type EnumReviewDecisionFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ReviewDecision'> + + + +/** + * Reference to a field of type 'ReviewDecision[]' + */ +export type ListEnumReviewDecisionFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ReviewDecision[]'> + + + +/** + * Reference to a field of type 'Float' + */ +export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'> + + + +/** + * Reference to a field of type 'Float[]' + */ +export type ListFloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float[]'> + + +/** + * Batch Payload for updateMany & deleteMany & createMany + */ +export type BatchPayload = { + count: number +} + +export const defineExtension = runtime.Extensions.defineExtension as unknown as runtime.Types.Extensions.ExtendsHook<"define", TypeMapCb, runtime.Types.Extensions.DefaultArgs> +export type DefaultPrismaClient = PrismaClient +export type ErrorFormat = 'pretty' | 'colorless' | 'minimal' +export type PrismaClientOptions = ({ + /** + * Instance of a Driver Adapter, e.g., like one provided by `@prisma/adapter-pg`. + */ + adapter: runtime.SqlDriverAdapterFactory + accelerateUrl?: never +} | { + /** + * Prisma Accelerate URL allowing the client to connect through Accelerate instead of a direct database. + */ + accelerateUrl: string + adapter?: never +}) & { + /** + * @default "colorless" + */ + errorFormat?: ErrorFormat + /** + * @example + * ``` + * // Shorthand for `emit: 'stdout'` + * log: ['query', 'info', 'warn', 'error'] + * + * // Emit as events only + * log: [ + * { emit: 'event', level: 'query' }, + * { emit: 'event', level: 'info' }, + * { emit: 'event', level: 'warn' } + * { emit: 'event', level: 'error' } + * ] + * + * / Emit as events and log to stdout + * og: [ + * { emit: 'stdout', level: 'query' }, + * { emit: 'stdout', level: 'info' }, + * { emit: 'stdout', level: 'warn' } + * { emit: 'stdout', level: 'error' } + * + * ``` + * Read more in our [docs](https://pris.ly/d/logging). + */ + log?: (LogLevel | LogDefinition)[] + /** + * The default values for transactionOptions + * maxWait ?= 2000 + * timeout ?= 5000 + */ + transactionOptions?: { + maxWait?: number + timeout?: number + isolationLevel?: TransactionIsolationLevel + } + /** + * Global configuration for omitting model fields by default. + * + * @example + * ``` + * const prisma = new PrismaClient({ + * omit: { + * user: { + * password: true + * } + * } + * }) + * ``` + */ + omit?: GlobalOmitConfig + /** + * SQL commenter plugins that add metadata to SQL queries as comments. + * Comments follow the sqlcommenter format: https://google.github.io/sqlcommenter/ + * + * @example + * ``` + * const prisma = new PrismaClient({ + * adapter, + * comments: [ + * traceContext(), + * queryInsights(), + * ], + * }) + * ``` + */ + comments?: runtime.SqlCommenterPlugin[] + /** + * Optional maximum size for the query plan cache. If not provided, a default size will be used. + * A value of `0` can be used to disable the cache entirely. A higher cache size can improve + * performance for applications that execute a large number of unique queries, while a smaller + * cache size can reduce memory usage. + * + * @example + * ``` + * const prisma = new PrismaClient({ + * adapter, + * queryPlanCacheMaxSize: 100, + * }) + * ``` + */ + queryPlanCacheMaxSize?: number +} +export type GlobalOmitConfig = { + user?: Prisma.UserOmit + userRole?: Prisma.UserRoleOmit + anonymousIdentity?: Prisma.AnonymousIdentityOmit + gameProject?: Prisma.GameProjectOmit + gameVersion?: Prisma.GameVersionOmit + asset?: Prisma.AssetOmit + job?: Prisma.JobOmit + auditLog?: Prisma.AuditLogOmit + mainCreationAgentSession?: Prisma.MainCreationAgentSessionOmit + agentTask?: Prisma.AgentTaskOmit + reviewRecord?: Prisma.ReviewRecordOmit + lifecycleEvent?: Prisma.LifecycleEventOmit +} + +/* Types for Logging */ +export type LogLevel = 'info' | 'query' | 'warn' | 'error' +export type LogDefinition = { + level: LogLevel + emit: 'stdout' | 'event' +} + +export type CheckIsLogLevel = T extends LogLevel ? T : never; + +export type GetLogType = CheckIsLogLevel< + T extends LogDefinition ? T['level'] : T +>; + +export type GetEvents = T extends Array + ? GetLogType + : never; + +export type QueryEvent = { + timestamp: Date + query: string + params: string + duration: number + target: string +} + +export type LogEvent = { + timestamp: Date + message: string + target: string +} +/* End Types for Logging */ + + +export type PrismaAction = + | 'findUnique' + | 'findUniqueOrThrow' + | 'findMany' + | 'findFirst' + | 'findFirstOrThrow' + | 'create' + | 'createMany' + | 'createManyAndReturn' + | 'update' + | 'updateMany' + | 'updateManyAndReturn' + | 'upsert' + | 'delete' + | 'deleteMany' + | 'executeRaw' + | 'queryRaw' + | 'aggregate' + | 'count' + | 'runCommandRaw' + | 'findRaw' + | 'groupBy' + +/** + * `PrismaClient` proxy available in interactive transactions. + */ +export type TransactionClient = Omit + diff --git a/apps/api/src/generated/prisma/internal/prismaNamespaceBrowser.ts b/apps/api/src/generated/prisma/internal/prismaNamespaceBrowser.ts new file mode 100644 index 00000000..c42ca21d --- /dev/null +++ b/apps/api/src/generated/prisma/internal/prismaNamespaceBrowser.ts @@ -0,0 +1,314 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * WARNING: This is an internal file that is subject to change! + * + * 🛑 Under no circumstances should you import this file directly! 🛑 + * + * All exports from this file are wrapped under a `Prisma` namespace object in the browser.ts file. + * While this enables partial backward compatibility, it is not part of the stable public API. + * + * If you are looking for your Models, Enums, and Input Types, please import them from the respective + * model files in the `model` directory! + */ + +import * as runtime from "@prisma/client/runtime/index-browser" + +export type * from '../models.js' +export type * from './prismaNamespace.js' + +export const Decimal = runtime.Decimal + + +export const NullTypes = { + DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull), + JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull), + AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull), +} +/** + * Helper for filtering JSON entries that have `null` on the database (empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const DbNull = runtime.DbNull + +/** + * Helper for filtering JSON entries that have JSON `null` values (not empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const JsonNull = runtime.JsonNull + +/** + * Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull` + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const AnyNull = runtime.AnyNull + + +export const ModelName = { + User: 'User', + UserRole: 'UserRole', + AnonymousIdentity: 'AnonymousIdentity', + GameProject: 'GameProject', + GameVersion: 'GameVersion', + Asset: 'Asset', + Job: 'Job', + AuditLog: 'AuditLog', + MainCreationAgentSession: 'MainCreationAgentSession', + AgentTask: 'AgentTask', + ReviewRecord: 'ReviewRecord', + LifecycleEvent: 'LifecycleEvent' +} as const + +export type ModelName = (typeof ModelName)[keyof typeof ModelName] + +/* + * Enums + */ + +export const TransactionIsolationLevel = runtime.makeStrictEnum({ + ReadUncommitted: 'ReadUncommitted', + ReadCommitted: 'ReadCommitted', + RepeatableRead: 'RepeatableRead', + Serializable: 'Serializable' +} as const) + +export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel] + + +export const UserScalarFieldEnum = { + id: 'id', + email: 'email', + displayName: 'displayName', + status: 'status', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] + + +export const UserRoleScalarFieldEnum = { + id: 'id', + userId: 'userId', + role: 'role', + createdAt: 'createdAt' +} as const + +export type UserRoleScalarFieldEnum = (typeof UserRoleScalarFieldEnum)[keyof typeof UserRoleScalarFieldEnum] + + +export const AnonymousIdentityScalarFieldEnum = { + id: 'id', + userId: 'userId', + deviceKey: 'deviceKey', + createdAt: 'createdAt' +} as const + +export type AnonymousIdentityScalarFieldEnum = (typeof AnonymousIdentityScalarFieldEnum)[keyof typeof AnonymousIdentityScalarFieldEnum] + + +export const GameProjectScalarFieldEnum = { + id: 'id', + ownerId: 'ownerId', + slug: 'slug', + title: 'title', + status: 'status', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type GameProjectScalarFieldEnum = (typeof GameProjectScalarFieldEnum)[keyof typeof GameProjectScalarFieldEnum] + + +export const GameVersionScalarFieldEnum = { + id: 'id', + projectId: 'projectId', + versionNumber: 'versionNumber', + status: 'status', + configJson: 'configJson', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type GameVersionScalarFieldEnum = (typeof GameVersionScalarFieldEnum)[keyof typeof GameVersionScalarFieldEnum] + + +export const AssetScalarFieldEnum = { + id: 'id', + projectId: 'projectId', + kind: 'kind', + storageKey: 'storageKey', + mimeType: 'mimeType', + byteSize: 'byteSize', + sha256: 'sha256', + status: 'status', + metadataJson: 'metadataJson', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type AssetScalarFieldEnum = (typeof AssetScalarFieldEnum)[keyof typeof AssetScalarFieldEnum] + + +export const JobScalarFieldEnum = { + id: 'id', + actorId: 'actorId', + projectId: 'projectId', + type: 'type', + idempotencyKey: 'idempotencyKey', + status: 'status', + attempts: 'attempts', + maxAttempts: 'maxAttempts', + timeoutAt: 'timeoutAt', + nextRetryAt: 'nextRetryAt', + errorCode: 'errorCode', + leaseToken: 'leaseToken', + leasedBy: 'leasedBy', + leaseExpiresAt: 'leaseExpiresAt', + lockVersion: 'lockVersion', + targetType: 'targetType', + targetId: 'targetId', + targetScopeKey: 'targetScopeKey', + gameProjectId: 'gameProjectId', + gameVersionId: 'gameVersionId', + payloadJson: 'payloadJson', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type JobScalarFieldEnum = (typeof JobScalarFieldEnum)[keyof typeof JobScalarFieldEnum] + + +export const AuditLogScalarFieldEnum = { + id: 'id', + actorId: 'actorId', + action: 'action', + targetType: 'targetType', + targetId: 'targetId', + eventJson: 'eventJson', + createdAt: 'createdAt' +} as const + +export type AuditLogScalarFieldEnum = (typeof AuditLogScalarFieldEnum)[keyof typeof AuditLogScalarFieldEnum] + + +export const MainCreationAgentSessionScalarFieldEnum = { + id: 'id', + creatorId: 'creatorId', + projectId: 'projectId', + versionId: 'versionId', + status: 'status', + contextSummary: 'contextSummary', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type MainCreationAgentSessionScalarFieldEnum = (typeof MainCreationAgentSessionScalarFieldEnum)[keyof typeof MainCreationAgentSessionScalarFieldEnum] + + +export const AgentTaskScalarFieldEnum = { + id: 'id', + sessionId: 'sessionId', + taskType: 'taskType', + subagentId: 'subagentId', + inputRef: 'inputRef', + outputRef: 'outputRef', + status: 'status', + timeoutAt: 'timeoutAt', + errorCode: 'errorCode', + auditLogId: 'auditLogId', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type AgentTaskScalarFieldEnum = (typeof AgentTaskScalarFieldEnum)[keyof typeof AgentTaskScalarFieldEnum] + + +export const ReviewRecordScalarFieldEnum = { + id: 'id', + gameVersionId: 'gameVersionId', + status: 'status', + decision: 'decision', + reasonCode: 'reasonCode', + decidedById: 'decidedById', + decidedAt: 'decidedAt', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type ReviewRecordScalarFieldEnum = (typeof ReviewRecordScalarFieldEnum)[keyof typeof ReviewRecordScalarFieldEnum] + + +export const LifecycleEventScalarFieldEnum = { + eventId: 'eventId', + gameVersionId: 'gameVersionId', + event: 'event', + from: 'from', + to: 'to', + actorJson: 'actorJson', + requiredRole: 'requiredRole', + requiredRecordRefsJson: 'requiredRecordRefsJson', + auditEvent: 'auditEvent', + reasonCode: 'reasonCode', + occurredAt: 'occurredAt', + approval: 'approval', + requiredRecordsJson: 'requiredRecordsJson', + createdAt: 'createdAt' +} as const + +export type LifecycleEventScalarFieldEnum = (typeof LifecycleEventScalarFieldEnum)[keyof typeof LifecycleEventScalarFieldEnum] + + +export const SortOrder = { + asc: 'asc', + desc: 'desc' +} as const + +export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder] + + +export const JsonNullValueInput = { + JsonNull: JsonNull +} as const + +export type JsonNullValueInput = (typeof JsonNullValueInput)[keyof typeof JsonNullValueInput] + + +export const NullableJsonNullValueInput = { + DbNull: DbNull, + JsonNull: JsonNull +} as const + +export type NullableJsonNullValueInput = (typeof NullableJsonNullValueInput)[keyof typeof NullableJsonNullValueInput] + + +export const QueryMode = { + default: 'default', + insensitive: 'insensitive' +} as const + +export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode] + + +export const NullsOrder = { + first: 'first', + last: 'last' +} as const + +export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder] + + +export const JsonNullValueFilter = { + DbNull: DbNull, + JsonNull: JsonNull, + AnyNull: AnyNull +} as const + +export type JsonNullValueFilter = (typeof JsonNullValueFilter)[keyof typeof JsonNullValueFilter] + diff --git a/apps/api/src/generated/prisma/models.ts b/apps/api/src/generated/prisma/models.ts new file mode 100644 index 00000000..8e0023f6 --- /dev/null +++ b/apps/api/src/generated/prisma/models.ts @@ -0,0 +1,23 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This is a barrel export file for all models and their related types. + * + * 🟢 You can import this file directly. + */ +export type * from './models/User.js' +export type * from './models/UserRole.js' +export type * from './models/AnonymousIdentity.js' +export type * from './models/GameProject.js' +export type * from './models/GameVersion.js' +export type * from './models/Asset.js' +export type * from './models/Job.js' +export type * from './models/AuditLog.js' +export type * from './models/MainCreationAgentSession.js' +export type * from './models/AgentTask.js' +export type * from './models/ReviewRecord.js' +export type * from './models/LifecycleEvent.js' +export type * from './commonInputTypes.js' \ No newline at end of file diff --git a/apps/api/src/generated/prisma/models/AgentTask.ts b/apps/api/src/generated/prisma/models/AgentTask.ts new file mode 100644 index 00000000..22f8afb3 --- /dev/null +++ b/apps/api/src/generated/prisma/models/AgentTask.ts @@ -0,0 +1,1598 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `AgentTask` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model AgentTask + * + */ +export type AgentTaskModel = runtime.Types.Result.DefaultSelection + +export type AggregateAgentTask = { + _count: AgentTaskCountAggregateOutputType | null + _min: AgentTaskMinAggregateOutputType | null + _max: AgentTaskMaxAggregateOutputType | null +} + +export type AgentTaskMinAggregateOutputType = { + id: string | null + sessionId: string | null + taskType: $Enums.AgentTaskType | null + subagentId: string | null + inputRef: string | null + outputRef: string | null + status: $Enums.AgentTaskStatus | null + timeoutAt: Date | null + errorCode: string | null + auditLogId: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type AgentTaskMaxAggregateOutputType = { + id: string | null + sessionId: string | null + taskType: $Enums.AgentTaskType | null + subagentId: string | null + inputRef: string | null + outputRef: string | null + status: $Enums.AgentTaskStatus | null + timeoutAt: Date | null + errorCode: string | null + auditLogId: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type AgentTaskCountAggregateOutputType = { + id: number + sessionId: number + taskType: number + subagentId: number + inputRef: number + outputRef: number + status: number + timeoutAt: number + errorCode: number + auditLogId: number + createdAt: number + updatedAt: number + _all: number +} + + +export type AgentTaskMinAggregateInputType = { + id?: true + sessionId?: true + taskType?: true + subagentId?: true + inputRef?: true + outputRef?: true + status?: true + timeoutAt?: true + errorCode?: true + auditLogId?: true + createdAt?: true + updatedAt?: true +} + +export type AgentTaskMaxAggregateInputType = { + id?: true + sessionId?: true + taskType?: true + subagentId?: true + inputRef?: true + outputRef?: true + status?: true + timeoutAt?: true + errorCode?: true + auditLogId?: true + createdAt?: true + updatedAt?: true +} + +export type AgentTaskCountAggregateInputType = { + id?: true + sessionId?: true + taskType?: true + subagentId?: true + inputRef?: true + outputRef?: true + status?: true + timeoutAt?: true + errorCode?: true + auditLogId?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type AgentTaskAggregateArgs = { + /** + * Filter which AgentTask to aggregate. + */ + where?: Prisma.AgentTaskWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AgentTasks to fetch. + */ + orderBy?: Prisma.AgentTaskOrderByWithRelationInput | Prisma.AgentTaskOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.AgentTaskWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AgentTasks from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AgentTasks. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned AgentTasks + **/ + _count?: true | AgentTaskCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: AgentTaskMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: AgentTaskMaxAggregateInputType +} + +export type GetAgentTaskAggregateType = { + [P in keyof T & keyof AggregateAgentTask]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type AgentTaskGroupByArgs = { + where?: Prisma.AgentTaskWhereInput + orderBy?: Prisma.AgentTaskOrderByWithAggregationInput | Prisma.AgentTaskOrderByWithAggregationInput[] + by: Prisma.AgentTaskScalarFieldEnum[] | Prisma.AgentTaskScalarFieldEnum + having?: Prisma.AgentTaskScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: AgentTaskCountAggregateInputType | true + _min?: AgentTaskMinAggregateInputType + _max?: AgentTaskMaxAggregateInputType +} + +export type AgentTaskGroupByOutputType = { + id: string + sessionId: string + taskType: $Enums.AgentTaskType + subagentId: string + inputRef: string + outputRef: string | null + status: $Enums.AgentTaskStatus + timeoutAt: Date + errorCode: string | null + auditLogId: string + createdAt: Date + updatedAt: Date + _count: AgentTaskCountAggregateOutputType | null + _min: AgentTaskMinAggregateOutputType | null + _max: AgentTaskMaxAggregateOutputType | null +} + +export type GetAgentTaskGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof AgentTaskGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type AgentTaskWhereInput = { + AND?: Prisma.AgentTaskWhereInput | Prisma.AgentTaskWhereInput[] + OR?: Prisma.AgentTaskWhereInput[] + NOT?: Prisma.AgentTaskWhereInput | Prisma.AgentTaskWhereInput[] + id?: Prisma.StringFilter<"AgentTask"> | string + sessionId?: Prisma.StringFilter<"AgentTask"> | string + taskType?: Prisma.EnumAgentTaskTypeFilter<"AgentTask"> | $Enums.AgentTaskType + subagentId?: Prisma.StringFilter<"AgentTask"> | string + inputRef?: Prisma.StringFilter<"AgentTask"> | string + outputRef?: Prisma.StringNullableFilter<"AgentTask"> | string | null + status?: Prisma.EnumAgentTaskStatusFilter<"AgentTask"> | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeFilter<"AgentTask"> | Date | string + errorCode?: Prisma.StringNullableFilter<"AgentTask"> | string | null + auditLogId?: Prisma.StringFilter<"AgentTask"> | string + createdAt?: Prisma.DateTimeFilter<"AgentTask"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"AgentTask"> | Date | string + session?: Prisma.XOR +} + +export type AgentTaskOrderByWithRelationInput = { + id?: Prisma.SortOrder + sessionId?: Prisma.SortOrder + taskType?: Prisma.SortOrder + subagentId?: Prisma.SortOrder + inputRef?: Prisma.SortOrder + outputRef?: Prisma.SortOrderInput | Prisma.SortOrder + status?: Prisma.SortOrder + timeoutAt?: Prisma.SortOrder + errorCode?: Prisma.SortOrderInput | Prisma.SortOrder + auditLogId?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + session?: Prisma.MainCreationAgentSessionOrderByWithRelationInput +} + +export type AgentTaskWhereUniqueInput = Prisma.AtLeast<{ + id?: string + AND?: Prisma.AgentTaskWhereInput | Prisma.AgentTaskWhereInput[] + OR?: Prisma.AgentTaskWhereInput[] + NOT?: Prisma.AgentTaskWhereInput | Prisma.AgentTaskWhereInput[] + sessionId?: Prisma.StringFilter<"AgentTask"> | string + taskType?: Prisma.EnumAgentTaskTypeFilter<"AgentTask"> | $Enums.AgentTaskType + subagentId?: Prisma.StringFilter<"AgentTask"> | string + inputRef?: Prisma.StringFilter<"AgentTask"> | string + outputRef?: Prisma.StringNullableFilter<"AgentTask"> | string | null + status?: Prisma.EnumAgentTaskStatusFilter<"AgentTask"> | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeFilter<"AgentTask"> | Date | string + errorCode?: Prisma.StringNullableFilter<"AgentTask"> | string | null + auditLogId?: Prisma.StringFilter<"AgentTask"> | string + createdAt?: Prisma.DateTimeFilter<"AgentTask"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"AgentTask"> | Date | string + session?: Prisma.XOR +}, "id"> + +export type AgentTaskOrderByWithAggregationInput = { + id?: Prisma.SortOrder + sessionId?: Prisma.SortOrder + taskType?: Prisma.SortOrder + subagentId?: Prisma.SortOrder + inputRef?: Prisma.SortOrder + outputRef?: Prisma.SortOrderInput | Prisma.SortOrder + status?: Prisma.SortOrder + timeoutAt?: Prisma.SortOrder + errorCode?: Prisma.SortOrderInput | Prisma.SortOrder + auditLogId?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.AgentTaskCountOrderByAggregateInput + _max?: Prisma.AgentTaskMaxOrderByAggregateInput + _min?: Prisma.AgentTaskMinOrderByAggregateInput +} + +export type AgentTaskScalarWhereWithAggregatesInput = { + AND?: Prisma.AgentTaskScalarWhereWithAggregatesInput | Prisma.AgentTaskScalarWhereWithAggregatesInput[] + OR?: Prisma.AgentTaskScalarWhereWithAggregatesInput[] + NOT?: Prisma.AgentTaskScalarWhereWithAggregatesInput | Prisma.AgentTaskScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"AgentTask"> | string + sessionId?: Prisma.StringWithAggregatesFilter<"AgentTask"> | string + taskType?: Prisma.EnumAgentTaskTypeWithAggregatesFilter<"AgentTask"> | $Enums.AgentTaskType + subagentId?: Prisma.StringWithAggregatesFilter<"AgentTask"> | string + inputRef?: Prisma.StringWithAggregatesFilter<"AgentTask"> | string + outputRef?: Prisma.StringNullableWithAggregatesFilter<"AgentTask"> | string | null + status?: Prisma.EnumAgentTaskStatusWithAggregatesFilter<"AgentTask"> | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeWithAggregatesFilter<"AgentTask"> | Date | string + errorCode?: Prisma.StringNullableWithAggregatesFilter<"AgentTask"> | string | null + auditLogId?: Prisma.StringWithAggregatesFilter<"AgentTask"> | string + createdAt?: Prisma.DateTimeWithAggregatesFilter<"AgentTask"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"AgentTask"> | Date | string +} + +export type AgentTaskCreateInput = { + id: string + taskType: $Enums.AgentTaskType + subagentId: string + inputRef: string + outputRef?: string | null + status: $Enums.AgentTaskStatus + timeoutAt: Date | string + errorCode?: string | null + auditLogId: string + createdAt?: Date | string + updatedAt?: Date | string + session: Prisma.MainCreationAgentSessionCreateNestedOneWithoutTasksInput +} + +export type AgentTaskUncheckedCreateInput = { + id: string + sessionId: string + taskType: $Enums.AgentTaskType + subagentId: string + inputRef: string + outputRef?: string | null + status: $Enums.AgentTaskStatus + timeoutAt: Date | string + errorCode?: string | null + auditLogId: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type AgentTaskUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + taskType?: Prisma.EnumAgentTaskTypeFieldUpdateOperationsInput | $Enums.AgentTaskType + subagentId?: Prisma.StringFieldUpdateOperationsInput | string + inputRef?: Prisma.StringFieldUpdateOperationsInput | string + outputRef?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + status?: Prisma.EnumAgentTaskStatusFieldUpdateOperationsInput | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + auditLogId?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + session?: Prisma.MainCreationAgentSessionUpdateOneRequiredWithoutTasksNestedInput +} + +export type AgentTaskUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + sessionId?: Prisma.StringFieldUpdateOperationsInput | string + taskType?: Prisma.EnumAgentTaskTypeFieldUpdateOperationsInput | $Enums.AgentTaskType + subagentId?: Prisma.StringFieldUpdateOperationsInput | string + inputRef?: Prisma.StringFieldUpdateOperationsInput | string + outputRef?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + status?: Prisma.EnumAgentTaskStatusFieldUpdateOperationsInput | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + auditLogId?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AgentTaskCreateManyInput = { + id: string + sessionId: string + taskType: $Enums.AgentTaskType + subagentId: string + inputRef: string + outputRef?: string | null + status: $Enums.AgentTaskStatus + timeoutAt: Date | string + errorCode?: string | null + auditLogId: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type AgentTaskUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + taskType?: Prisma.EnumAgentTaskTypeFieldUpdateOperationsInput | $Enums.AgentTaskType + subagentId?: Prisma.StringFieldUpdateOperationsInput | string + inputRef?: Prisma.StringFieldUpdateOperationsInput | string + outputRef?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + status?: Prisma.EnumAgentTaskStatusFieldUpdateOperationsInput | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + auditLogId?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AgentTaskUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + sessionId?: Prisma.StringFieldUpdateOperationsInput | string + taskType?: Prisma.EnumAgentTaskTypeFieldUpdateOperationsInput | $Enums.AgentTaskType + subagentId?: Prisma.StringFieldUpdateOperationsInput | string + inputRef?: Prisma.StringFieldUpdateOperationsInput | string + outputRef?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + status?: Prisma.EnumAgentTaskStatusFieldUpdateOperationsInput | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + auditLogId?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AgentTaskListRelationFilter = { + every?: Prisma.AgentTaskWhereInput + some?: Prisma.AgentTaskWhereInput + none?: Prisma.AgentTaskWhereInput +} + +export type AgentTaskOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type AgentTaskCountOrderByAggregateInput = { + id?: Prisma.SortOrder + sessionId?: Prisma.SortOrder + taskType?: Prisma.SortOrder + subagentId?: Prisma.SortOrder + inputRef?: Prisma.SortOrder + outputRef?: Prisma.SortOrder + status?: Prisma.SortOrder + timeoutAt?: Prisma.SortOrder + errorCode?: Prisma.SortOrder + auditLogId?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type AgentTaskMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + sessionId?: Prisma.SortOrder + taskType?: Prisma.SortOrder + subagentId?: Prisma.SortOrder + inputRef?: Prisma.SortOrder + outputRef?: Prisma.SortOrder + status?: Prisma.SortOrder + timeoutAt?: Prisma.SortOrder + errorCode?: Prisma.SortOrder + auditLogId?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type AgentTaskMinOrderByAggregateInput = { + id?: Prisma.SortOrder + sessionId?: Prisma.SortOrder + taskType?: Prisma.SortOrder + subagentId?: Prisma.SortOrder + inputRef?: Prisma.SortOrder + outputRef?: Prisma.SortOrder + status?: Prisma.SortOrder + timeoutAt?: Prisma.SortOrder + errorCode?: Prisma.SortOrder + auditLogId?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type AgentTaskCreateNestedManyWithoutSessionInput = { + create?: Prisma.XOR | Prisma.AgentTaskCreateWithoutSessionInput[] | Prisma.AgentTaskUncheckedCreateWithoutSessionInput[] + connectOrCreate?: Prisma.AgentTaskCreateOrConnectWithoutSessionInput | Prisma.AgentTaskCreateOrConnectWithoutSessionInput[] + createMany?: Prisma.AgentTaskCreateManySessionInputEnvelope + connect?: Prisma.AgentTaskWhereUniqueInput | Prisma.AgentTaskWhereUniqueInput[] +} + +export type AgentTaskUncheckedCreateNestedManyWithoutSessionInput = { + create?: Prisma.XOR | Prisma.AgentTaskCreateWithoutSessionInput[] | Prisma.AgentTaskUncheckedCreateWithoutSessionInput[] + connectOrCreate?: Prisma.AgentTaskCreateOrConnectWithoutSessionInput | Prisma.AgentTaskCreateOrConnectWithoutSessionInput[] + createMany?: Prisma.AgentTaskCreateManySessionInputEnvelope + connect?: Prisma.AgentTaskWhereUniqueInput | Prisma.AgentTaskWhereUniqueInput[] +} + +export type AgentTaskUpdateManyWithoutSessionNestedInput = { + create?: Prisma.XOR | Prisma.AgentTaskCreateWithoutSessionInput[] | Prisma.AgentTaskUncheckedCreateWithoutSessionInput[] + connectOrCreate?: Prisma.AgentTaskCreateOrConnectWithoutSessionInput | Prisma.AgentTaskCreateOrConnectWithoutSessionInput[] + upsert?: Prisma.AgentTaskUpsertWithWhereUniqueWithoutSessionInput | Prisma.AgentTaskUpsertWithWhereUniqueWithoutSessionInput[] + createMany?: Prisma.AgentTaskCreateManySessionInputEnvelope + set?: Prisma.AgentTaskWhereUniqueInput | Prisma.AgentTaskWhereUniqueInput[] + disconnect?: Prisma.AgentTaskWhereUniqueInput | Prisma.AgentTaskWhereUniqueInput[] + delete?: Prisma.AgentTaskWhereUniqueInput | Prisma.AgentTaskWhereUniqueInput[] + connect?: Prisma.AgentTaskWhereUniqueInput | Prisma.AgentTaskWhereUniqueInput[] + update?: Prisma.AgentTaskUpdateWithWhereUniqueWithoutSessionInput | Prisma.AgentTaskUpdateWithWhereUniqueWithoutSessionInput[] + updateMany?: Prisma.AgentTaskUpdateManyWithWhereWithoutSessionInput | Prisma.AgentTaskUpdateManyWithWhereWithoutSessionInput[] + deleteMany?: Prisma.AgentTaskScalarWhereInput | Prisma.AgentTaskScalarWhereInput[] +} + +export type AgentTaskUncheckedUpdateManyWithoutSessionNestedInput = { + create?: Prisma.XOR | Prisma.AgentTaskCreateWithoutSessionInput[] | Prisma.AgentTaskUncheckedCreateWithoutSessionInput[] + connectOrCreate?: Prisma.AgentTaskCreateOrConnectWithoutSessionInput | Prisma.AgentTaskCreateOrConnectWithoutSessionInput[] + upsert?: Prisma.AgentTaskUpsertWithWhereUniqueWithoutSessionInput | Prisma.AgentTaskUpsertWithWhereUniqueWithoutSessionInput[] + createMany?: Prisma.AgentTaskCreateManySessionInputEnvelope + set?: Prisma.AgentTaskWhereUniqueInput | Prisma.AgentTaskWhereUniqueInput[] + disconnect?: Prisma.AgentTaskWhereUniqueInput | Prisma.AgentTaskWhereUniqueInput[] + delete?: Prisma.AgentTaskWhereUniqueInput | Prisma.AgentTaskWhereUniqueInput[] + connect?: Prisma.AgentTaskWhereUniqueInput | Prisma.AgentTaskWhereUniqueInput[] + update?: Prisma.AgentTaskUpdateWithWhereUniqueWithoutSessionInput | Prisma.AgentTaskUpdateWithWhereUniqueWithoutSessionInput[] + updateMany?: Prisma.AgentTaskUpdateManyWithWhereWithoutSessionInput | Prisma.AgentTaskUpdateManyWithWhereWithoutSessionInput[] + deleteMany?: Prisma.AgentTaskScalarWhereInput | Prisma.AgentTaskScalarWhereInput[] +} + +export type EnumAgentTaskTypeFieldUpdateOperationsInput = { + set?: $Enums.AgentTaskType +} + +export type EnumAgentTaskStatusFieldUpdateOperationsInput = { + set?: $Enums.AgentTaskStatus +} + +export type AgentTaskCreateWithoutSessionInput = { + id: string + taskType: $Enums.AgentTaskType + subagentId: string + inputRef: string + outputRef?: string | null + status: $Enums.AgentTaskStatus + timeoutAt: Date | string + errorCode?: string | null + auditLogId: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type AgentTaskUncheckedCreateWithoutSessionInput = { + id: string + taskType: $Enums.AgentTaskType + subagentId: string + inputRef: string + outputRef?: string | null + status: $Enums.AgentTaskStatus + timeoutAt: Date | string + errorCode?: string | null + auditLogId: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type AgentTaskCreateOrConnectWithoutSessionInput = { + where: Prisma.AgentTaskWhereUniqueInput + create: Prisma.XOR +} + +export type AgentTaskCreateManySessionInputEnvelope = { + data: Prisma.AgentTaskCreateManySessionInput | Prisma.AgentTaskCreateManySessionInput[] + skipDuplicates?: boolean +} + +export type AgentTaskUpsertWithWhereUniqueWithoutSessionInput = { + where: Prisma.AgentTaskWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type AgentTaskUpdateWithWhereUniqueWithoutSessionInput = { + where: Prisma.AgentTaskWhereUniqueInput + data: Prisma.XOR +} + +export type AgentTaskUpdateManyWithWhereWithoutSessionInput = { + where: Prisma.AgentTaskScalarWhereInput + data: Prisma.XOR +} + +export type AgentTaskScalarWhereInput = { + AND?: Prisma.AgentTaskScalarWhereInput | Prisma.AgentTaskScalarWhereInput[] + OR?: Prisma.AgentTaskScalarWhereInput[] + NOT?: Prisma.AgentTaskScalarWhereInput | Prisma.AgentTaskScalarWhereInput[] + id?: Prisma.StringFilter<"AgentTask"> | string + sessionId?: Prisma.StringFilter<"AgentTask"> | string + taskType?: Prisma.EnumAgentTaskTypeFilter<"AgentTask"> | $Enums.AgentTaskType + subagentId?: Prisma.StringFilter<"AgentTask"> | string + inputRef?: Prisma.StringFilter<"AgentTask"> | string + outputRef?: Prisma.StringNullableFilter<"AgentTask"> | string | null + status?: Prisma.EnumAgentTaskStatusFilter<"AgentTask"> | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeFilter<"AgentTask"> | Date | string + errorCode?: Prisma.StringNullableFilter<"AgentTask"> | string | null + auditLogId?: Prisma.StringFilter<"AgentTask"> | string + createdAt?: Prisma.DateTimeFilter<"AgentTask"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"AgentTask"> | Date | string +} + +export type AgentTaskCreateManySessionInput = { + id: string + taskType: $Enums.AgentTaskType + subagentId: string + inputRef: string + outputRef?: string | null + status: $Enums.AgentTaskStatus + timeoutAt: Date | string + errorCode?: string | null + auditLogId: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type AgentTaskUpdateWithoutSessionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + taskType?: Prisma.EnumAgentTaskTypeFieldUpdateOperationsInput | $Enums.AgentTaskType + subagentId?: Prisma.StringFieldUpdateOperationsInput | string + inputRef?: Prisma.StringFieldUpdateOperationsInput | string + outputRef?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + status?: Prisma.EnumAgentTaskStatusFieldUpdateOperationsInput | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + auditLogId?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AgentTaskUncheckedUpdateWithoutSessionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + taskType?: Prisma.EnumAgentTaskTypeFieldUpdateOperationsInput | $Enums.AgentTaskType + subagentId?: Prisma.StringFieldUpdateOperationsInput | string + inputRef?: Prisma.StringFieldUpdateOperationsInput | string + outputRef?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + status?: Prisma.EnumAgentTaskStatusFieldUpdateOperationsInput | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + auditLogId?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AgentTaskUncheckedUpdateManyWithoutSessionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + taskType?: Prisma.EnumAgentTaskTypeFieldUpdateOperationsInput | $Enums.AgentTaskType + subagentId?: Prisma.StringFieldUpdateOperationsInput | string + inputRef?: Prisma.StringFieldUpdateOperationsInput | string + outputRef?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + status?: Prisma.EnumAgentTaskStatusFieldUpdateOperationsInput | $Enums.AgentTaskStatus + timeoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + auditLogId?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + + +export type AgentTaskSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + sessionId?: boolean + taskType?: boolean + subagentId?: boolean + inputRef?: boolean + outputRef?: boolean + status?: boolean + timeoutAt?: boolean + errorCode?: boolean + auditLogId?: boolean + createdAt?: boolean + updatedAt?: boolean + session?: boolean | Prisma.MainCreationAgentSessionDefaultArgs +}, ExtArgs["result"]["agentTask"]> + +export type AgentTaskSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + sessionId?: boolean + taskType?: boolean + subagentId?: boolean + inputRef?: boolean + outputRef?: boolean + status?: boolean + timeoutAt?: boolean + errorCode?: boolean + auditLogId?: boolean + createdAt?: boolean + updatedAt?: boolean + session?: boolean | Prisma.MainCreationAgentSessionDefaultArgs +}, ExtArgs["result"]["agentTask"]> + +export type AgentTaskSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + sessionId?: boolean + taskType?: boolean + subagentId?: boolean + inputRef?: boolean + outputRef?: boolean + status?: boolean + timeoutAt?: boolean + errorCode?: boolean + auditLogId?: boolean + createdAt?: boolean + updatedAt?: boolean + session?: boolean | Prisma.MainCreationAgentSessionDefaultArgs +}, ExtArgs["result"]["agentTask"]> + +export type AgentTaskSelectScalar = { + id?: boolean + sessionId?: boolean + taskType?: boolean + subagentId?: boolean + inputRef?: boolean + outputRef?: boolean + status?: boolean + timeoutAt?: boolean + errorCode?: boolean + auditLogId?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type AgentTaskOmit = runtime.Types.Extensions.GetOmit<"id" | "sessionId" | "taskType" | "subagentId" | "inputRef" | "outputRef" | "status" | "timeoutAt" | "errorCode" | "auditLogId" | "createdAt" | "updatedAt", ExtArgs["result"]["agentTask"]> +export type AgentTaskInclude = { + session?: boolean | Prisma.MainCreationAgentSessionDefaultArgs +} +export type AgentTaskIncludeCreateManyAndReturn = { + session?: boolean | Prisma.MainCreationAgentSessionDefaultArgs +} +export type AgentTaskIncludeUpdateManyAndReturn = { + session?: boolean | Prisma.MainCreationAgentSessionDefaultArgs +} + +export type $AgentTaskPayload = { + name: "AgentTask" + objects: { + session: Prisma.$MainCreationAgentSessionPayload + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + sessionId: string + taskType: $Enums.AgentTaskType + subagentId: string + inputRef: string + outputRef: string | null + status: $Enums.AgentTaskStatus + timeoutAt: Date + errorCode: string | null + auditLogId: string + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["agentTask"]> + composites: {} +} + +export type AgentTaskGetPayload = runtime.Types.Result.GetResult + +export type AgentTaskCountArgs = + Omit & { + select?: AgentTaskCountAggregateInputType | true + } + +export interface AgentTaskDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['AgentTask'], meta: { name: 'AgentTask' } } + /** + * Find zero or one AgentTask that matches the filter. + * @param {AgentTaskFindUniqueArgs} args - Arguments to find a AgentTask + * @example + * // Get one AgentTask + * const agentTask = await prisma.agentTask.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__AgentTaskClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one AgentTask that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {AgentTaskFindUniqueOrThrowArgs} args - Arguments to find a AgentTask + * @example + * // Get one AgentTask + * const agentTask = await prisma.agentTask.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__AgentTaskClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first AgentTask that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AgentTaskFindFirstArgs} args - Arguments to find a AgentTask + * @example + * // Get one AgentTask + * const agentTask = await prisma.agentTask.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__AgentTaskClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first AgentTask that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AgentTaskFindFirstOrThrowArgs} args - Arguments to find a AgentTask + * @example + * // Get one AgentTask + * const agentTask = await prisma.agentTask.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__AgentTaskClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more AgentTasks that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AgentTaskFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all AgentTasks + * const agentTasks = await prisma.agentTask.findMany() + * + * // Get first 10 AgentTasks + * const agentTasks = await prisma.agentTask.findMany({ take: 10 }) + * + * // Only select the `id` + * const agentTaskWithIdOnly = await prisma.agentTask.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a AgentTask. + * @param {AgentTaskCreateArgs} args - Arguments to create a AgentTask. + * @example + * // Create one AgentTask + * const AgentTask = await prisma.agentTask.create({ + * data: { + * // ... data to create a AgentTask + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__AgentTaskClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many AgentTasks. + * @param {AgentTaskCreateManyArgs} args - Arguments to create many AgentTasks. + * @example + * // Create many AgentTasks + * const agentTask = await prisma.agentTask.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many AgentTasks and returns the data saved in the database. + * @param {AgentTaskCreateManyAndReturnArgs} args - Arguments to create many AgentTasks. + * @example + * // Create many AgentTasks + * const agentTask = await prisma.agentTask.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many AgentTasks and only return the `id` + * const agentTaskWithIdOnly = await prisma.agentTask.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a AgentTask. + * @param {AgentTaskDeleteArgs} args - Arguments to delete one AgentTask. + * @example + * // Delete one AgentTask + * const AgentTask = await prisma.agentTask.delete({ + * where: { + * // ... filter to delete one AgentTask + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__AgentTaskClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one AgentTask. + * @param {AgentTaskUpdateArgs} args - Arguments to update one AgentTask. + * @example + * // Update one AgentTask + * const agentTask = await prisma.agentTask.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__AgentTaskClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more AgentTasks. + * @param {AgentTaskDeleteManyArgs} args - Arguments to filter AgentTasks to delete. + * @example + * // Delete a few AgentTasks + * const { count } = await prisma.agentTask.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more AgentTasks. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AgentTaskUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many AgentTasks + * const agentTask = await prisma.agentTask.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more AgentTasks and returns the data updated in the database. + * @param {AgentTaskUpdateManyAndReturnArgs} args - Arguments to update many AgentTasks. + * @example + * // Update many AgentTasks + * const agentTask = await prisma.agentTask.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more AgentTasks and only return the `id` + * const agentTaskWithIdOnly = await prisma.agentTask.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one AgentTask. + * @param {AgentTaskUpsertArgs} args - Arguments to update or create a AgentTask. + * @example + * // Update or create a AgentTask + * const agentTask = await prisma.agentTask.upsert({ + * create: { + * // ... data to create a AgentTask + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the AgentTask we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__AgentTaskClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of AgentTasks. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AgentTaskCountArgs} args - Arguments to filter AgentTasks to count. + * @example + * // Count the number of AgentTasks + * const count = await prisma.agentTask.count({ + * where: { + * // ... the filter for the AgentTasks we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a AgentTask. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AgentTaskAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by AgentTask. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AgentTaskGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends AgentTaskGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: AgentTaskGroupByArgs['orderBy'] } + : { orderBy?: AgentTaskGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetAgentTaskGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the AgentTask model + */ +readonly fields: AgentTaskFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for AgentTask. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__AgentTaskClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + session = {}>(args?: Prisma.Subset>): Prisma.Prisma__MainCreationAgentSessionClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the AgentTask model + */ +export interface AgentTaskFieldRefs { + readonly id: Prisma.FieldRef<"AgentTask", 'String'> + readonly sessionId: Prisma.FieldRef<"AgentTask", 'String'> + readonly taskType: Prisma.FieldRef<"AgentTask", 'AgentTaskType'> + readonly subagentId: Prisma.FieldRef<"AgentTask", 'String'> + readonly inputRef: Prisma.FieldRef<"AgentTask", 'String'> + readonly outputRef: Prisma.FieldRef<"AgentTask", 'String'> + readonly status: Prisma.FieldRef<"AgentTask", 'AgentTaskStatus'> + readonly timeoutAt: Prisma.FieldRef<"AgentTask", 'DateTime'> + readonly errorCode: Prisma.FieldRef<"AgentTask", 'String'> + readonly auditLogId: Prisma.FieldRef<"AgentTask", 'String'> + readonly createdAt: Prisma.FieldRef<"AgentTask", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"AgentTask", 'DateTime'> +} + + +// Custom InputTypes +/** + * AgentTask findUnique + */ +export type AgentTaskFindUniqueArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null + /** + * Filter, which AgentTask to fetch. + */ + where: Prisma.AgentTaskWhereUniqueInput +} + +/** + * AgentTask findUniqueOrThrow + */ +export type AgentTaskFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null + /** + * Filter, which AgentTask to fetch. + */ + where: Prisma.AgentTaskWhereUniqueInput +} + +/** + * AgentTask findFirst + */ +export type AgentTaskFindFirstArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null + /** + * Filter, which AgentTask to fetch. + */ + where?: Prisma.AgentTaskWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AgentTasks to fetch. + */ + orderBy?: Prisma.AgentTaskOrderByWithRelationInput | Prisma.AgentTaskOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for AgentTasks. + */ + cursor?: Prisma.AgentTaskWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AgentTasks from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AgentTasks. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AgentTasks. + */ + distinct?: Prisma.AgentTaskScalarFieldEnum | Prisma.AgentTaskScalarFieldEnum[] +} + +/** + * AgentTask findFirstOrThrow + */ +export type AgentTaskFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null + /** + * Filter, which AgentTask to fetch. + */ + where?: Prisma.AgentTaskWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AgentTasks to fetch. + */ + orderBy?: Prisma.AgentTaskOrderByWithRelationInput | Prisma.AgentTaskOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for AgentTasks. + */ + cursor?: Prisma.AgentTaskWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AgentTasks from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AgentTasks. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AgentTasks. + */ + distinct?: Prisma.AgentTaskScalarFieldEnum | Prisma.AgentTaskScalarFieldEnum[] +} + +/** + * AgentTask findMany + */ +export type AgentTaskFindManyArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null + /** + * Filter, which AgentTasks to fetch. + */ + where?: Prisma.AgentTaskWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AgentTasks to fetch. + */ + orderBy?: Prisma.AgentTaskOrderByWithRelationInput | Prisma.AgentTaskOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing AgentTasks. + */ + cursor?: Prisma.AgentTaskWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AgentTasks from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AgentTasks. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AgentTasks. + */ + distinct?: Prisma.AgentTaskScalarFieldEnum | Prisma.AgentTaskScalarFieldEnum[] +} + +/** + * AgentTask create + */ +export type AgentTaskCreateArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null + /** + * The data needed to create a AgentTask. + */ + data: Prisma.XOR +} + +/** + * AgentTask createMany + */ +export type AgentTaskCreateManyArgs = { + /** + * The data used to create many AgentTasks. + */ + data: Prisma.AgentTaskCreateManyInput | Prisma.AgentTaskCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * AgentTask createManyAndReturn + */ +export type AgentTaskCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelectCreateManyAndReturn | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * The data used to create many AgentTasks. + */ + data: Prisma.AgentTaskCreateManyInput | Prisma.AgentTaskCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskIncludeCreateManyAndReturn | null +} + +/** + * AgentTask update + */ +export type AgentTaskUpdateArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null + /** + * The data needed to update a AgentTask. + */ + data: Prisma.XOR + /** + * Choose, which AgentTask to update. + */ + where: Prisma.AgentTaskWhereUniqueInput +} + +/** + * AgentTask updateMany + */ +export type AgentTaskUpdateManyArgs = { + /** + * The data used to update AgentTasks. + */ + data: Prisma.XOR + /** + * Filter which AgentTasks to update + */ + where?: Prisma.AgentTaskWhereInput + /** + * Limit how many AgentTasks to update. + */ + limit?: number +} + +/** + * AgentTask updateManyAndReturn + */ +export type AgentTaskUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * The data used to update AgentTasks. + */ + data: Prisma.XOR + /** + * Filter which AgentTasks to update + */ + where?: Prisma.AgentTaskWhereInput + /** + * Limit how many AgentTasks to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskIncludeUpdateManyAndReturn | null +} + +/** + * AgentTask upsert + */ +export type AgentTaskUpsertArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null + /** + * The filter to search for the AgentTask to update in case it exists. + */ + where: Prisma.AgentTaskWhereUniqueInput + /** + * In case the AgentTask found by the `where` argument doesn't exist, create a new AgentTask with this data. + */ + create: Prisma.XOR + /** + * In case the AgentTask was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * AgentTask delete + */ +export type AgentTaskDeleteArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null + /** + * Filter which AgentTask to delete. + */ + where: Prisma.AgentTaskWhereUniqueInput +} + +/** + * AgentTask deleteMany + */ +export type AgentTaskDeleteManyArgs = { + /** + * Filter which AgentTasks to delete + */ + where?: Prisma.AgentTaskWhereInput + /** + * Limit how many AgentTasks to delete. + */ + limit?: number +} + +/** + * AgentTask without action + */ +export type AgentTaskDefaultArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null +} diff --git a/apps/api/src/generated/prisma/models/AnonymousIdentity.ts b/apps/api/src/generated/prisma/models/AnonymousIdentity.ts new file mode 100644 index 00000000..71ed5990 --- /dev/null +++ b/apps/api/src/generated/prisma/models/AnonymousIdentity.ts @@ -0,0 +1,1310 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `AnonymousIdentity` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model AnonymousIdentity + * + */ +export type AnonymousIdentityModel = runtime.Types.Result.DefaultSelection + +export type AggregateAnonymousIdentity = { + _count: AnonymousIdentityCountAggregateOutputType | null + _min: AnonymousIdentityMinAggregateOutputType | null + _max: AnonymousIdentityMaxAggregateOutputType | null +} + +export type AnonymousIdentityMinAggregateOutputType = { + id: string | null + userId: string | null + deviceKey: string | null + createdAt: Date | null +} + +export type AnonymousIdentityMaxAggregateOutputType = { + id: string | null + userId: string | null + deviceKey: string | null + createdAt: Date | null +} + +export type AnonymousIdentityCountAggregateOutputType = { + id: number + userId: number + deviceKey: number + createdAt: number + _all: number +} + + +export type AnonymousIdentityMinAggregateInputType = { + id?: true + userId?: true + deviceKey?: true + createdAt?: true +} + +export type AnonymousIdentityMaxAggregateInputType = { + id?: true + userId?: true + deviceKey?: true + createdAt?: true +} + +export type AnonymousIdentityCountAggregateInputType = { + id?: true + userId?: true + deviceKey?: true + createdAt?: true + _all?: true +} + +export type AnonymousIdentityAggregateArgs = { + /** + * Filter which AnonymousIdentity to aggregate. + */ + where?: Prisma.AnonymousIdentityWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AnonymousIdentities to fetch. + */ + orderBy?: Prisma.AnonymousIdentityOrderByWithRelationInput | Prisma.AnonymousIdentityOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.AnonymousIdentityWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AnonymousIdentities from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AnonymousIdentities. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned AnonymousIdentities + **/ + _count?: true | AnonymousIdentityCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: AnonymousIdentityMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: AnonymousIdentityMaxAggregateInputType +} + +export type GetAnonymousIdentityAggregateType = { + [P in keyof T & keyof AggregateAnonymousIdentity]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type AnonymousIdentityGroupByArgs = { + where?: Prisma.AnonymousIdentityWhereInput + orderBy?: Prisma.AnonymousIdentityOrderByWithAggregationInput | Prisma.AnonymousIdentityOrderByWithAggregationInput[] + by: Prisma.AnonymousIdentityScalarFieldEnum[] | Prisma.AnonymousIdentityScalarFieldEnum + having?: Prisma.AnonymousIdentityScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: AnonymousIdentityCountAggregateInputType | true + _min?: AnonymousIdentityMinAggregateInputType + _max?: AnonymousIdentityMaxAggregateInputType +} + +export type AnonymousIdentityGroupByOutputType = { + id: string + userId: string + deviceKey: string + createdAt: Date + _count: AnonymousIdentityCountAggregateOutputType | null + _min: AnonymousIdentityMinAggregateOutputType | null + _max: AnonymousIdentityMaxAggregateOutputType | null +} + +export type GetAnonymousIdentityGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof AnonymousIdentityGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type AnonymousIdentityWhereInput = { + AND?: Prisma.AnonymousIdentityWhereInput | Prisma.AnonymousIdentityWhereInput[] + OR?: Prisma.AnonymousIdentityWhereInput[] + NOT?: Prisma.AnonymousIdentityWhereInput | Prisma.AnonymousIdentityWhereInput[] + id?: Prisma.StringFilter<"AnonymousIdentity"> | string + userId?: Prisma.StringFilter<"AnonymousIdentity"> | string + deviceKey?: Prisma.StringFilter<"AnonymousIdentity"> | string + createdAt?: Prisma.DateTimeFilter<"AnonymousIdentity"> | Date | string + user?: Prisma.XOR +} + +export type AnonymousIdentityOrderByWithRelationInput = { + id?: Prisma.SortOrder + userId?: Prisma.SortOrder + deviceKey?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + user?: Prisma.UserOrderByWithRelationInput +} + +export type AnonymousIdentityWhereUniqueInput = Prisma.AtLeast<{ + id?: string + deviceKey?: string + AND?: Prisma.AnonymousIdentityWhereInput | Prisma.AnonymousIdentityWhereInput[] + OR?: Prisma.AnonymousIdentityWhereInput[] + NOT?: Prisma.AnonymousIdentityWhereInput | Prisma.AnonymousIdentityWhereInput[] + userId?: Prisma.StringFilter<"AnonymousIdentity"> | string + createdAt?: Prisma.DateTimeFilter<"AnonymousIdentity"> | Date | string + user?: Prisma.XOR +}, "id" | "deviceKey"> + +export type AnonymousIdentityOrderByWithAggregationInput = { + id?: Prisma.SortOrder + userId?: Prisma.SortOrder + deviceKey?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + _count?: Prisma.AnonymousIdentityCountOrderByAggregateInput + _max?: Prisma.AnonymousIdentityMaxOrderByAggregateInput + _min?: Prisma.AnonymousIdentityMinOrderByAggregateInput +} + +export type AnonymousIdentityScalarWhereWithAggregatesInput = { + AND?: Prisma.AnonymousIdentityScalarWhereWithAggregatesInput | Prisma.AnonymousIdentityScalarWhereWithAggregatesInput[] + OR?: Prisma.AnonymousIdentityScalarWhereWithAggregatesInput[] + NOT?: Prisma.AnonymousIdentityScalarWhereWithAggregatesInput | Prisma.AnonymousIdentityScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"AnonymousIdentity"> | string + userId?: Prisma.StringWithAggregatesFilter<"AnonymousIdentity"> | string + deviceKey?: Prisma.StringWithAggregatesFilter<"AnonymousIdentity"> | string + createdAt?: Prisma.DateTimeWithAggregatesFilter<"AnonymousIdentity"> | Date | string +} + +export type AnonymousIdentityCreateInput = { + id: string + deviceKey: string + createdAt?: Date | string + user: Prisma.UserCreateNestedOneWithoutAnonymousIdentitiesInput +} + +export type AnonymousIdentityUncheckedCreateInput = { + id: string + userId: string + deviceKey: string + createdAt?: Date | string +} + +export type AnonymousIdentityUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + deviceKey?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + user?: Prisma.UserUpdateOneRequiredWithoutAnonymousIdentitiesNestedInput +} + +export type AnonymousIdentityUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + userId?: Prisma.StringFieldUpdateOperationsInput | string + deviceKey?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AnonymousIdentityCreateManyInput = { + id: string + userId: string + deviceKey: string + createdAt?: Date | string +} + +export type AnonymousIdentityUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + deviceKey?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AnonymousIdentityUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + userId?: Prisma.StringFieldUpdateOperationsInput | string + deviceKey?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AnonymousIdentityListRelationFilter = { + every?: Prisma.AnonymousIdentityWhereInput + some?: Prisma.AnonymousIdentityWhereInput + none?: Prisma.AnonymousIdentityWhereInput +} + +export type AnonymousIdentityOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type AnonymousIdentityCountOrderByAggregateInput = { + id?: Prisma.SortOrder + userId?: Prisma.SortOrder + deviceKey?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type AnonymousIdentityMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + userId?: Prisma.SortOrder + deviceKey?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type AnonymousIdentityMinOrderByAggregateInput = { + id?: Prisma.SortOrder + userId?: Prisma.SortOrder + deviceKey?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type AnonymousIdentityCreateNestedManyWithoutUserInput = { + create?: Prisma.XOR | Prisma.AnonymousIdentityCreateWithoutUserInput[] | Prisma.AnonymousIdentityUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.AnonymousIdentityCreateOrConnectWithoutUserInput | Prisma.AnonymousIdentityCreateOrConnectWithoutUserInput[] + createMany?: Prisma.AnonymousIdentityCreateManyUserInputEnvelope + connect?: Prisma.AnonymousIdentityWhereUniqueInput | Prisma.AnonymousIdentityWhereUniqueInput[] +} + +export type AnonymousIdentityUncheckedCreateNestedManyWithoutUserInput = { + create?: Prisma.XOR | Prisma.AnonymousIdentityCreateWithoutUserInput[] | Prisma.AnonymousIdentityUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.AnonymousIdentityCreateOrConnectWithoutUserInput | Prisma.AnonymousIdentityCreateOrConnectWithoutUserInput[] + createMany?: Prisma.AnonymousIdentityCreateManyUserInputEnvelope + connect?: Prisma.AnonymousIdentityWhereUniqueInput | Prisma.AnonymousIdentityWhereUniqueInput[] +} + +export type AnonymousIdentityUpdateManyWithoutUserNestedInput = { + create?: Prisma.XOR | Prisma.AnonymousIdentityCreateWithoutUserInput[] | Prisma.AnonymousIdentityUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.AnonymousIdentityCreateOrConnectWithoutUserInput | Prisma.AnonymousIdentityCreateOrConnectWithoutUserInput[] + upsert?: Prisma.AnonymousIdentityUpsertWithWhereUniqueWithoutUserInput | Prisma.AnonymousIdentityUpsertWithWhereUniqueWithoutUserInput[] + createMany?: Prisma.AnonymousIdentityCreateManyUserInputEnvelope + set?: Prisma.AnonymousIdentityWhereUniqueInput | Prisma.AnonymousIdentityWhereUniqueInput[] + disconnect?: Prisma.AnonymousIdentityWhereUniqueInput | Prisma.AnonymousIdentityWhereUniqueInput[] + delete?: Prisma.AnonymousIdentityWhereUniqueInput | Prisma.AnonymousIdentityWhereUniqueInput[] + connect?: Prisma.AnonymousIdentityWhereUniqueInput | Prisma.AnonymousIdentityWhereUniqueInput[] + update?: Prisma.AnonymousIdentityUpdateWithWhereUniqueWithoutUserInput | Prisma.AnonymousIdentityUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: Prisma.AnonymousIdentityUpdateManyWithWhereWithoutUserInput | Prisma.AnonymousIdentityUpdateManyWithWhereWithoutUserInput[] + deleteMany?: Prisma.AnonymousIdentityScalarWhereInput | Prisma.AnonymousIdentityScalarWhereInput[] +} + +export type AnonymousIdentityUncheckedUpdateManyWithoutUserNestedInput = { + create?: Prisma.XOR | Prisma.AnonymousIdentityCreateWithoutUserInput[] | Prisma.AnonymousIdentityUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.AnonymousIdentityCreateOrConnectWithoutUserInput | Prisma.AnonymousIdentityCreateOrConnectWithoutUserInput[] + upsert?: Prisma.AnonymousIdentityUpsertWithWhereUniqueWithoutUserInput | Prisma.AnonymousIdentityUpsertWithWhereUniqueWithoutUserInput[] + createMany?: Prisma.AnonymousIdentityCreateManyUserInputEnvelope + set?: Prisma.AnonymousIdentityWhereUniqueInput | Prisma.AnonymousIdentityWhereUniqueInput[] + disconnect?: Prisma.AnonymousIdentityWhereUniqueInput | Prisma.AnonymousIdentityWhereUniqueInput[] + delete?: Prisma.AnonymousIdentityWhereUniqueInput | Prisma.AnonymousIdentityWhereUniqueInput[] + connect?: Prisma.AnonymousIdentityWhereUniqueInput | Prisma.AnonymousIdentityWhereUniqueInput[] + update?: Prisma.AnonymousIdentityUpdateWithWhereUniqueWithoutUserInput | Prisma.AnonymousIdentityUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: Prisma.AnonymousIdentityUpdateManyWithWhereWithoutUserInput | Prisma.AnonymousIdentityUpdateManyWithWhereWithoutUserInput[] + deleteMany?: Prisma.AnonymousIdentityScalarWhereInput | Prisma.AnonymousIdentityScalarWhereInput[] +} + +export type AnonymousIdentityCreateWithoutUserInput = { + id: string + deviceKey: string + createdAt?: Date | string +} + +export type AnonymousIdentityUncheckedCreateWithoutUserInput = { + id: string + deviceKey: string + createdAt?: Date | string +} + +export type AnonymousIdentityCreateOrConnectWithoutUserInput = { + where: Prisma.AnonymousIdentityWhereUniqueInput + create: Prisma.XOR +} + +export type AnonymousIdentityCreateManyUserInputEnvelope = { + data: Prisma.AnonymousIdentityCreateManyUserInput | Prisma.AnonymousIdentityCreateManyUserInput[] + skipDuplicates?: boolean +} + +export type AnonymousIdentityUpsertWithWhereUniqueWithoutUserInput = { + where: Prisma.AnonymousIdentityWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type AnonymousIdentityUpdateWithWhereUniqueWithoutUserInput = { + where: Prisma.AnonymousIdentityWhereUniqueInput + data: Prisma.XOR +} + +export type AnonymousIdentityUpdateManyWithWhereWithoutUserInput = { + where: Prisma.AnonymousIdentityScalarWhereInput + data: Prisma.XOR +} + +export type AnonymousIdentityScalarWhereInput = { + AND?: Prisma.AnonymousIdentityScalarWhereInput | Prisma.AnonymousIdentityScalarWhereInput[] + OR?: Prisma.AnonymousIdentityScalarWhereInput[] + NOT?: Prisma.AnonymousIdentityScalarWhereInput | Prisma.AnonymousIdentityScalarWhereInput[] + id?: Prisma.StringFilter<"AnonymousIdentity"> | string + userId?: Prisma.StringFilter<"AnonymousIdentity"> | string + deviceKey?: Prisma.StringFilter<"AnonymousIdentity"> | string + createdAt?: Prisma.DateTimeFilter<"AnonymousIdentity"> | Date | string +} + +export type AnonymousIdentityCreateManyUserInput = { + id: string + deviceKey: string + createdAt?: Date | string +} + +export type AnonymousIdentityUpdateWithoutUserInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + deviceKey?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AnonymousIdentityUncheckedUpdateWithoutUserInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + deviceKey?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AnonymousIdentityUncheckedUpdateManyWithoutUserInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + deviceKey?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + + +export type AnonymousIdentitySelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + userId?: boolean + deviceKey?: boolean + createdAt?: boolean + user?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["anonymousIdentity"]> + +export type AnonymousIdentitySelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + userId?: boolean + deviceKey?: boolean + createdAt?: boolean + user?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["anonymousIdentity"]> + +export type AnonymousIdentitySelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + userId?: boolean + deviceKey?: boolean + createdAt?: boolean + user?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["anonymousIdentity"]> + +export type AnonymousIdentitySelectScalar = { + id?: boolean + userId?: boolean + deviceKey?: boolean + createdAt?: boolean +} + +export type AnonymousIdentityOmit = runtime.Types.Extensions.GetOmit<"id" | "userId" | "deviceKey" | "createdAt", ExtArgs["result"]["anonymousIdentity"]> +export type AnonymousIdentityInclude = { + user?: boolean | Prisma.UserDefaultArgs +} +export type AnonymousIdentityIncludeCreateManyAndReturn = { + user?: boolean | Prisma.UserDefaultArgs +} +export type AnonymousIdentityIncludeUpdateManyAndReturn = { + user?: boolean | Prisma.UserDefaultArgs +} + +export type $AnonymousIdentityPayload = { + name: "AnonymousIdentity" + objects: { + user: Prisma.$UserPayload + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + userId: string + deviceKey: string + createdAt: Date + }, ExtArgs["result"]["anonymousIdentity"]> + composites: {} +} + +export type AnonymousIdentityGetPayload = runtime.Types.Result.GetResult + +export type AnonymousIdentityCountArgs = + Omit & { + select?: AnonymousIdentityCountAggregateInputType | true + } + +export interface AnonymousIdentityDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['AnonymousIdentity'], meta: { name: 'AnonymousIdentity' } } + /** + * Find zero or one AnonymousIdentity that matches the filter. + * @param {AnonymousIdentityFindUniqueArgs} args - Arguments to find a AnonymousIdentity + * @example + * // Get one AnonymousIdentity + * const anonymousIdentity = await prisma.anonymousIdentity.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__AnonymousIdentityClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one AnonymousIdentity that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {AnonymousIdentityFindUniqueOrThrowArgs} args - Arguments to find a AnonymousIdentity + * @example + * // Get one AnonymousIdentity + * const anonymousIdentity = await prisma.anonymousIdentity.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__AnonymousIdentityClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first AnonymousIdentity that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AnonymousIdentityFindFirstArgs} args - Arguments to find a AnonymousIdentity + * @example + * // Get one AnonymousIdentity + * const anonymousIdentity = await prisma.anonymousIdentity.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__AnonymousIdentityClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first AnonymousIdentity that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AnonymousIdentityFindFirstOrThrowArgs} args - Arguments to find a AnonymousIdentity + * @example + * // Get one AnonymousIdentity + * const anonymousIdentity = await prisma.anonymousIdentity.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__AnonymousIdentityClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more AnonymousIdentities that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AnonymousIdentityFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all AnonymousIdentities + * const anonymousIdentities = await prisma.anonymousIdentity.findMany() + * + * // Get first 10 AnonymousIdentities + * const anonymousIdentities = await prisma.anonymousIdentity.findMany({ take: 10 }) + * + * // Only select the `id` + * const anonymousIdentityWithIdOnly = await prisma.anonymousIdentity.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a AnonymousIdentity. + * @param {AnonymousIdentityCreateArgs} args - Arguments to create a AnonymousIdentity. + * @example + * // Create one AnonymousIdentity + * const AnonymousIdentity = await prisma.anonymousIdentity.create({ + * data: { + * // ... data to create a AnonymousIdentity + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__AnonymousIdentityClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many AnonymousIdentities. + * @param {AnonymousIdentityCreateManyArgs} args - Arguments to create many AnonymousIdentities. + * @example + * // Create many AnonymousIdentities + * const anonymousIdentity = await prisma.anonymousIdentity.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many AnonymousIdentities and returns the data saved in the database. + * @param {AnonymousIdentityCreateManyAndReturnArgs} args - Arguments to create many AnonymousIdentities. + * @example + * // Create many AnonymousIdentities + * const anonymousIdentity = await prisma.anonymousIdentity.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many AnonymousIdentities and only return the `id` + * const anonymousIdentityWithIdOnly = await prisma.anonymousIdentity.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a AnonymousIdentity. + * @param {AnonymousIdentityDeleteArgs} args - Arguments to delete one AnonymousIdentity. + * @example + * // Delete one AnonymousIdentity + * const AnonymousIdentity = await prisma.anonymousIdentity.delete({ + * where: { + * // ... filter to delete one AnonymousIdentity + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__AnonymousIdentityClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one AnonymousIdentity. + * @param {AnonymousIdentityUpdateArgs} args - Arguments to update one AnonymousIdentity. + * @example + * // Update one AnonymousIdentity + * const anonymousIdentity = await prisma.anonymousIdentity.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__AnonymousIdentityClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more AnonymousIdentities. + * @param {AnonymousIdentityDeleteManyArgs} args - Arguments to filter AnonymousIdentities to delete. + * @example + * // Delete a few AnonymousIdentities + * const { count } = await prisma.anonymousIdentity.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more AnonymousIdentities. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AnonymousIdentityUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many AnonymousIdentities + * const anonymousIdentity = await prisma.anonymousIdentity.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more AnonymousIdentities and returns the data updated in the database. + * @param {AnonymousIdentityUpdateManyAndReturnArgs} args - Arguments to update many AnonymousIdentities. + * @example + * // Update many AnonymousIdentities + * const anonymousIdentity = await prisma.anonymousIdentity.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more AnonymousIdentities and only return the `id` + * const anonymousIdentityWithIdOnly = await prisma.anonymousIdentity.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one AnonymousIdentity. + * @param {AnonymousIdentityUpsertArgs} args - Arguments to update or create a AnonymousIdentity. + * @example + * // Update or create a AnonymousIdentity + * const anonymousIdentity = await prisma.anonymousIdentity.upsert({ + * create: { + * // ... data to create a AnonymousIdentity + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the AnonymousIdentity we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__AnonymousIdentityClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of AnonymousIdentities. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AnonymousIdentityCountArgs} args - Arguments to filter AnonymousIdentities to count. + * @example + * // Count the number of AnonymousIdentities + * const count = await prisma.anonymousIdentity.count({ + * where: { + * // ... the filter for the AnonymousIdentities we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a AnonymousIdentity. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AnonymousIdentityAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by AnonymousIdentity. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AnonymousIdentityGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends AnonymousIdentityGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: AnonymousIdentityGroupByArgs['orderBy'] } + : { orderBy?: AnonymousIdentityGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetAnonymousIdentityGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the AnonymousIdentity model + */ +readonly fields: AnonymousIdentityFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for AnonymousIdentity. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__AnonymousIdentityClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + user = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the AnonymousIdentity model + */ +export interface AnonymousIdentityFieldRefs { + readonly id: Prisma.FieldRef<"AnonymousIdentity", 'String'> + readonly userId: Prisma.FieldRef<"AnonymousIdentity", 'String'> + readonly deviceKey: Prisma.FieldRef<"AnonymousIdentity", 'String'> + readonly createdAt: Prisma.FieldRef<"AnonymousIdentity", 'DateTime'> +} + + +// Custom InputTypes +/** + * AnonymousIdentity findUnique + */ +export type AnonymousIdentityFindUniqueArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null + /** + * Filter, which AnonymousIdentity to fetch. + */ + where: Prisma.AnonymousIdentityWhereUniqueInput +} + +/** + * AnonymousIdentity findUniqueOrThrow + */ +export type AnonymousIdentityFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null + /** + * Filter, which AnonymousIdentity to fetch. + */ + where: Prisma.AnonymousIdentityWhereUniqueInput +} + +/** + * AnonymousIdentity findFirst + */ +export type AnonymousIdentityFindFirstArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null + /** + * Filter, which AnonymousIdentity to fetch. + */ + where?: Prisma.AnonymousIdentityWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AnonymousIdentities to fetch. + */ + orderBy?: Prisma.AnonymousIdentityOrderByWithRelationInput | Prisma.AnonymousIdentityOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for AnonymousIdentities. + */ + cursor?: Prisma.AnonymousIdentityWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AnonymousIdentities from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AnonymousIdentities. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AnonymousIdentities. + */ + distinct?: Prisma.AnonymousIdentityScalarFieldEnum | Prisma.AnonymousIdentityScalarFieldEnum[] +} + +/** + * AnonymousIdentity findFirstOrThrow + */ +export type AnonymousIdentityFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null + /** + * Filter, which AnonymousIdentity to fetch. + */ + where?: Prisma.AnonymousIdentityWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AnonymousIdentities to fetch. + */ + orderBy?: Prisma.AnonymousIdentityOrderByWithRelationInput | Prisma.AnonymousIdentityOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for AnonymousIdentities. + */ + cursor?: Prisma.AnonymousIdentityWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AnonymousIdentities from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AnonymousIdentities. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AnonymousIdentities. + */ + distinct?: Prisma.AnonymousIdentityScalarFieldEnum | Prisma.AnonymousIdentityScalarFieldEnum[] +} + +/** + * AnonymousIdentity findMany + */ +export type AnonymousIdentityFindManyArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null + /** + * Filter, which AnonymousIdentities to fetch. + */ + where?: Prisma.AnonymousIdentityWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AnonymousIdentities to fetch. + */ + orderBy?: Prisma.AnonymousIdentityOrderByWithRelationInput | Prisma.AnonymousIdentityOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing AnonymousIdentities. + */ + cursor?: Prisma.AnonymousIdentityWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AnonymousIdentities from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AnonymousIdentities. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AnonymousIdentities. + */ + distinct?: Prisma.AnonymousIdentityScalarFieldEnum | Prisma.AnonymousIdentityScalarFieldEnum[] +} + +/** + * AnonymousIdentity create + */ +export type AnonymousIdentityCreateArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null + /** + * The data needed to create a AnonymousIdentity. + */ + data: Prisma.XOR +} + +/** + * AnonymousIdentity createMany + */ +export type AnonymousIdentityCreateManyArgs = { + /** + * The data used to create many AnonymousIdentities. + */ + data: Prisma.AnonymousIdentityCreateManyInput | Prisma.AnonymousIdentityCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * AnonymousIdentity createManyAndReturn + */ +export type AnonymousIdentityCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelectCreateManyAndReturn | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * The data used to create many AnonymousIdentities. + */ + data: Prisma.AnonymousIdentityCreateManyInput | Prisma.AnonymousIdentityCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityIncludeCreateManyAndReturn | null +} + +/** + * AnonymousIdentity update + */ +export type AnonymousIdentityUpdateArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null + /** + * The data needed to update a AnonymousIdentity. + */ + data: Prisma.XOR + /** + * Choose, which AnonymousIdentity to update. + */ + where: Prisma.AnonymousIdentityWhereUniqueInput +} + +/** + * AnonymousIdentity updateMany + */ +export type AnonymousIdentityUpdateManyArgs = { + /** + * The data used to update AnonymousIdentities. + */ + data: Prisma.XOR + /** + * Filter which AnonymousIdentities to update + */ + where?: Prisma.AnonymousIdentityWhereInput + /** + * Limit how many AnonymousIdentities to update. + */ + limit?: number +} + +/** + * AnonymousIdentity updateManyAndReturn + */ +export type AnonymousIdentityUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelectUpdateManyAndReturn | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * The data used to update AnonymousIdentities. + */ + data: Prisma.XOR + /** + * Filter which AnonymousIdentities to update + */ + where?: Prisma.AnonymousIdentityWhereInput + /** + * Limit how many AnonymousIdentities to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityIncludeUpdateManyAndReturn | null +} + +/** + * AnonymousIdentity upsert + */ +export type AnonymousIdentityUpsertArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null + /** + * The filter to search for the AnonymousIdentity to update in case it exists. + */ + where: Prisma.AnonymousIdentityWhereUniqueInput + /** + * In case the AnonymousIdentity found by the `where` argument doesn't exist, create a new AnonymousIdentity with this data. + */ + create: Prisma.XOR + /** + * In case the AnonymousIdentity was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * AnonymousIdentity delete + */ +export type AnonymousIdentityDeleteArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null + /** + * Filter which AnonymousIdentity to delete. + */ + where: Prisma.AnonymousIdentityWhereUniqueInput +} + +/** + * AnonymousIdentity deleteMany + */ +export type AnonymousIdentityDeleteManyArgs = { + /** + * Filter which AnonymousIdentities to delete + */ + where?: Prisma.AnonymousIdentityWhereInput + /** + * Limit how many AnonymousIdentities to delete. + */ + limit?: number +} + +/** + * AnonymousIdentity without action + */ +export type AnonymousIdentityDefaultArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null +} diff --git a/apps/api/src/generated/prisma/models/Asset.ts b/apps/api/src/generated/prisma/models/Asset.ts new file mode 100644 index 00000000..70b40d4d --- /dev/null +++ b/apps/api/src/generated/prisma/models/Asset.ts @@ -0,0 +1,1603 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `Asset` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model Asset + * + */ +export type AssetModel = runtime.Types.Result.DefaultSelection + +export type AggregateAsset = { + _count: AssetCountAggregateOutputType | null + _avg: AssetAvgAggregateOutputType | null + _sum: AssetSumAggregateOutputType | null + _min: AssetMinAggregateOutputType | null + _max: AssetMaxAggregateOutputType | null +} + +export type AssetAvgAggregateOutputType = { + byteSize: number | null +} + +export type AssetSumAggregateOutputType = { + byteSize: number | null +} + +export type AssetMinAggregateOutputType = { + id: string | null + projectId: string | null + kind: string | null + storageKey: string | null + mimeType: string | null + byteSize: number | null + sha256: string | null + status: $Enums.AssetStatus | null + createdAt: Date | null + updatedAt: Date | null +} + +export type AssetMaxAggregateOutputType = { + id: string | null + projectId: string | null + kind: string | null + storageKey: string | null + mimeType: string | null + byteSize: number | null + sha256: string | null + status: $Enums.AssetStatus | null + createdAt: Date | null + updatedAt: Date | null +} + +export type AssetCountAggregateOutputType = { + id: number + projectId: number + kind: number + storageKey: number + mimeType: number + byteSize: number + sha256: number + status: number + metadataJson: number + createdAt: number + updatedAt: number + _all: number +} + + +export type AssetAvgAggregateInputType = { + byteSize?: true +} + +export type AssetSumAggregateInputType = { + byteSize?: true +} + +export type AssetMinAggregateInputType = { + id?: true + projectId?: true + kind?: true + storageKey?: true + mimeType?: true + byteSize?: true + sha256?: true + status?: true + createdAt?: true + updatedAt?: true +} + +export type AssetMaxAggregateInputType = { + id?: true + projectId?: true + kind?: true + storageKey?: true + mimeType?: true + byteSize?: true + sha256?: true + status?: true + createdAt?: true + updatedAt?: true +} + +export type AssetCountAggregateInputType = { + id?: true + projectId?: true + kind?: true + storageKey?: true + mimeType?: true + byteSize?: true + sha256?: true + status?: true + metadataJson?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type AssetAggregateArgs = { + /** + * Filter which Asset to aggregate. + */ + where?: Prisma.AssetWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Assets to fetch. + */ + orderBy?: Prisma.AssetOrderByWithRelationInput | Prisma.AssetOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.AssetWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Assets from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Assets. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Assets + **/ + _count?: true | AssetCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: AssetAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: AssetSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: AssetMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: AssetMaxAggregateInputType +} + +export type GetAssetAggregateType = { + [P in keyof T & keyof AggregateAsset]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type AssetGroupByArgs = { + where?: Prisma.AssetWhereInput + orderBy?: Prisma.AssetOrderByWithAggregationInput | Prisma.AssetOrderByWithAggregationInput[] + by: Prisma.AssetScalarFieldEnum[] | Prisma.AssetScalarFieldEnum + having?: Prisma.AssetScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: AssetCountAggregateInputType | true + _avg?: AssetAvgAggregateInputType + _sum?: AssetSumAggregateInputType + _min?: AssetMinAggregateInputType + _max?: AssetMaxAggregateInputType +} + +export type AssetGroupByOutputType = { + id: string + projectId: string + kind: string + storageKey: string + mimeType: string + byteSize: number + sha256: string + status: $Enums.AssetStatus + metadataJson: runtime.JsonValue | null + createdAt: Date + updatedAt: Date + _count: AssetCountAggregateOutputType | null + _avg: AssetAvgAggregateOutputType | null + _sum: AssetSumAggregateOutputType | null + _min: AssetMinAggregateOutputType | null + _max: AssetMaxAggregateOutputType | null +} + +export type GetAssetGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof AssetGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type AssetWhereInput = { + AND?: Prisma.AssetWhereInput | Prisma.AssetWhereInput[] + OR?: Prisma.AssetWhereInput[] + NOT?: Prisma.AssetWhereInput | Prisma.AssetWhereInput[] + id?: Prisma.StringFilter<"Asset"> | string + projectId?: Prisma.StringFilter<"Asset"> | string + kind?: Prisma.StringFilter<"Asset"> | string + storageKey?: Prisma.StringFilter<"Asset"> | string + mimeType?: Prisma.StringFilter<"Asset"> | string + byteSize?: Prisma.IntFilter<"Asset"> | number + sha256?: Prisma.StringFilter<"Asset"> | string + status?: Prisma.EnumAssetStatusFilter<"Asset"> | $Enums.AssetStatus + metadataJson?: Prisma.JsonNullableFilter<"Asset"> + createdAt?: Prisma.DateTimeFilter<"Asset"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Asset"> | Date | string + project?: Prisma.XOR +} + +export type AssetOrderByWithRelationInput = { + id?: Prisma.SortOrder + projectId?: Prisma.SortOrder + kind?: Prisma.SortOrder + storageKey?: Prisma.SortOrder + mimeType?: Prisma.SortOrder + byteSize?: Prisma.SortOrder + sha256?: Prisma.SortOrder + status?: Prisma.SortOrder + metadataJson?: Prisma.SortOrderInput | Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + project?: Prisma.GameProjectOrderByWithRelationInput +} + +export type AssetWhereUniqueInput = Prisma.AtLeast<{ + id?: string + projectId_storageKey?: Prisma.AssetProjectIdStorageKeyCompoundUniqueInput + AND?: Prisma.AssetWhereInput | Prisma.AssetWhereInput[] + OR?: Prisma.AssetWhereInput[] + NOT?: Prisma.AssetWhereInput | Prisma.AssetWhereInput[] + projectId?: Prisma.StringFilter<"Asset"> | string + kind?: Prisma.StringFilter<"Asset"> | string + storageKey?: Prisma.StringFilter<"Asset"> | string + mimeType?: Prisma.StringFilter<"Asset"> | string + byteSize?: Prisma.IntFilter<"Asset"> | number + sha256?: Prisma.StringFilter<"Asset"> | string + status?: Prisma.EnumAssetStatusFilter<"Asset"> | $Enums.AssetStatus + metadataJson?: Prisma.JsonNullableFilter<"Asset"> + createdAt?: Prisma.DateTimeFilter<"Asset"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Asset"> | Date | string + project?: Prisma.XOR +}, "id" | "projectId_storageKey"> + +export type AssetOrderByWithAggregationInput = { + id?: Prisma.SortOrder + projectId?: Prisma.SortOrder + kind?: Prisma.SortOrder + storageKey?: Prisma.SortOrder + mimeType?: Prisma.SortOrder + byteSize?: Prisma.SortOrder + sha256?: Prisma.SortOrder + status?: Prisma.SortOrder + metadataJson?: Prisma.SortOrderInput | Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.AssetCountOrderByAggregateInput + _avg?: Prisma.AssetAvgOrderByAggregateInput + _max?: Prisma.AssetMaxOrderByAggregateInput + _min?: Prisma.AssetMinOrderByAggregateInput + _sum?: Prisma.AssetSumOrderByAggregateInput +} + +export type AssetScalarWhereWithAggregatesInput = { + AND?: Prisma.AssetScalarWhereWithAggregatesInput | Prisma.AssetScalarWhereWithAggregatesInput[] + OR?: Prisma.AssetScalarWhereWithAggregatesInput[] + NOT?: Prisma.AssetScalarWhereWithAggregatesInput | Prisma.AssetScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"Asset"> | string + projectId?: Prisma.StringWithAggregatesFilter<"Asset"> | string + kind?: Prisma.StringWithAggregatesFilter<"Asset"> | string + storageKey?: Prisma.StringWithAggregatesFilter<"Asset"> | string + mimeType?: Prisma.StringWithAggregatesFilter<"Asset"> | string + byteSize?: Prisma.IntWithAggregatesFilter<"Asset"> | number + sha256?: Prisma.StringWithAggregatesFilter<"Asset"> | string + status?: Prisma.EnumAssetStatusWithAggregatesFilter<"Asset"> | $Enums.AssetStatus + metadataJson?: Prisma.JsonNullableWithAggregatesFilter<"Asset"> + createdAt?: Prisma.DateTimeWithAggregatesFilter<"Asset"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Asset"> | Date | string +} + +export type AssetCreateInput = { + id: string + kind: string + storageKey: string + mimeType: string + byteSize: number + sha256: string + status?: $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + project: Prisma.GameProjectCreateNestedOneWithoutAssetsInput +} + +export type AssetUncheckedCreateInput = { + id: string + projectId: string + kind: string + storageKey: string + mimeType: string + byteSize: number + sha256: string + status?: $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type AssetUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + kind?: Prisma.StringFieldUpdateOperationsInput | string + storageKey?: Prisma.StringFieldUpdateOperationsInput | string + mimeType?: Prisma.StringFieldUpdateOperationsInput | string + byteSize?: Prisma.IntFieldUpdateOperationsInput | number + sha256?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumAssetStatusFieldUpdateOperationsInput | $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + project?: Prisma.GameProjectUpdateOneRequiredWithoutAssetsNestedInput +} + +export type AssetUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + kind?: Prisma.StringFieldUpdateOperationsInput | string + storageKey?: Prisma.StringFieldUpdateOperationsInput | string + mimeType?: Prisma.StringFieldUpdateOperationsInput | string + byteSize?: Prisma.IntFieldUpdateOperationsInput | number + sha256?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumAssetStatusFieldUpdateOperationsInput | $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AssetCreateManyInput = { + id: string + projectId: string + kind: string + storageKey: string + mimeType: string + byteSize: number + sha256: string + status?: $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type AssetUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + kind?: Prisma.StringFieldUpdateOperationsInput | string + storageKey?: Prisma.StringFieldUpdateOperationsInput | string + mimeType?: Prisma.StringFieldUpdateOperationsInput | string + byteSize?: Prisma.IntFieldUpdateOperationsInput | number + sha256?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumAssetStatusFieldUpdateOperationsInput | $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AssetUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + kind?: Prisma.StringFieldUpdateOperationsInput | string + storageKey?: Prisma.StringFieldUpdateOperationsInput | string + mimeType?: Prisma.StringFieldUpdateOperationsInput | string + byteSize?: Prisma.IntFieldUpdateOperationsInput | number + sha256?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumAssetStatusFieldUpdateOperationsInput | $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AssetListRelationFilter = { + every?: Prisma.AssetWhereInput + some?: Prisma.AssetWhereInput + none?: Prisma.AssetWhereInput +} + +export type AssetOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type AssetProjectIdStorageKeyCompoundUniqueInput = { + projectId: string + storageKey: string +} + +export type AssetCountOrderByAggregateInput = { + id?: Prisma.SortOrder + projectId?: Prisma.SortOrder + kind?: Prisma.SortOrder + storageKey?: Prisma.SortOrder + mimeType?: Prisma.SortOrder + byteSize?: Prisma.SortOrder + sha256?: Prisma.SortOrder + status?: Prisma.SortOrder + metadataJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type AssetAvgOrderByAggregateInput = { + byteSize?: Prisma.SortOrder +} + +export type AssetMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + projectId?: Prisma.SortOrder + kind?: Prisma.SortOrder + storageKey?: Prisma.SortOrder + mimeType?: Prisma.SortOrder + byteSize?: Prisma.SortOrder + sha256?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type AssetMinOrderByAggregateInput = { + id?: Prisma.SortOrder + projectId?: Prisma.SortOrder + kind?: Prisma.SortOrder + storageKey?: Prisma.SortOrder + mimeType?: Prisma.SortOrder + byteSize?: Prisma.SortOrder + sha256?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type AssetSumOrderByAggregateInput = { + byteSize?: Prisma.SortOrder +} + +export type AssetCreateNestedManyWithoutProjectInput = { + create?: Prisma.XOR | Prisma.AssetCreateWithoutProjectInput[] | Prisma.AssetUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.AssetCreateOrConnectWithoutProjectInput | Prisma.AssetCreateOrConnectWithoutProjectInput[] + createMany?: Prisma.AssetCreateManyProjectInputEnvelope + connect?: Prisma.AssetWhereUniqueInput | Prisma.AssetWhereUniqueInput[] +} + +export type AssetUncheckedCreateNestedManyWithoutProjectInput = { + create?: Prisma.XOR | Prisma.AssetCreateWithoutProjectInput[] | Prisma.AssetUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.AssetCreateOrConnectWithoutProjectInput | Prisma.AssetCreateOrConnectWithoutProjectInput[] + createMany?: Prisma.AssetCreateManyProjectInputEnvelope + connect?: Prisma.AssetWhereUniqueInput | Prisma.AssetWhereUniqueInput[] +} + +export type AssetUpdateManyWithoutProjectNestedInput = { + create?: Prisma.XOR | Prisma.AssetCreateWithoutProjectInput[] | Prisma.AssetUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.AssetCreateOrConnectWithoutProjectInput | Prisma.AssetCreateOrConnectWithoutProjectInput[] + upsert?: Prisma.AssetUpsertWithWhereUniqueWithoutProjectInput | Prisma.AssetUpsertWithWhereUniqueWithoutProjectInput[] + createMany?: Prisma.AssetCreateManyProjectInputEnvelope + set?: Prisma.AssetWhereUniqueInput | Prisma.AssetWhereUniqueInput[] + disconnect?: Prisma.AssetWhereUniqueInput | Prisma.AssetWhereUniqueInput[] + delete?: Prisma.AssetWhereUniqueInput | Prisma.AssetWhereUniqueInput[] + connect?: Prisma.AssetWhereUniqueInput | Prisma.AssetWhereUniqueInput[] + update?: Prisma.AssetUpdateWithWhereUniqueWithoutProjectInput | Prisma.AssetUpdateWithWhereUniqueWithoutProjectInput[] + updateMany?: Prisma.AssetUpdateManyWithWhereWithoutProjectInput | Prisma.AssetUpdateManyWithWhereWithoutProjectInput[] + deleteMany?: Prisma.AssetScalarWhereInput | Prisma.AssetScalarWhereInput[] +} + +export type AssetUncheckedUpdateManyWithoutProjectNestedInput = { + create?: Prisma.XOR | Prisma.AssetCreateWithoutProjectInput[] | Prisma.AssetUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.AssetCreateOrConnectWithoutProjectInput | Prisma.AssetCreateOrConnectWithoutProjectInput[] + upsert?: Prisma.AssetUpsertWithWhereUniqueWithoutProjectInput | Prisma.AssetUpsertWithWhereUniqueWithoutProjectInput[] + createMany?: Prisma.AssetCreateManyProjectInputEnvelope + set?: Prisma.AssetWhereUniqueInput | Prisma.AssetWhereUniqueInput[] + disconnect?: Prisma.AssetWhereUniqueInput | Prisma.AssetWhereUniqueInput[] + delete?: Prisma.AssetWhereUniqueInput | Prisma.AssetWhereUniqueInput[] + connect?: Prisma.AssetWhereUniqueInput | Prisma.AssetWhereUniqueInput[] + update?: Prisma.AssetUpdateWithWhereUniqueWithoutProjectInput | Prisma.AssetUpdateWithWhereUniqueWithoutProjectInput[] + updateMany?: Prisma.AssetUpdateManyWithWhereWithoutProjectInput | Prisma.AssetUpdateManyWithWhereWithoutProjectInput[] + deleteMany?: Prisma.AssetScalarWhereInput | Prisma.AssetScalarWhereInput[] +} + +export type EnumAssetStatusFieldUpdateOperationsInput = { + set?: $Enums.AssetStatus +} + +export type AssetCreateWithoutProjectInput = { + id: string + kind: string + storageKey: string + mimeType: string + byteSize: number + sha256: string + status?: $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type AssetUncheckedCreateWithoutProjectInput = { + id: string + kind: string + storageKey: string + mimeType: string + byteSize: number + sha256: string + status?: $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type AssetCreateOrConnectWithoutProjectInput = { + where: Prisma.AssetWhereUniqueInput + create: Prisma.XOR +} + +export type AssetCreateManyProjectInputEnvelope = { + data: Prisma.AssetCreateManyProjectInput | Prisma.AssetCreateManyProjectInput[] + skipDuplicates?: boolean +} + +export type AssetUpsertWithWhereUniqueWithoutProjectInput = { + where: Prisma.AssetWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type AssetUpdateWithWhereUniqueWithoutProjectInput = { + where: Prisma.AssetWhereUniqueInput + data: Prisma.XOR +} + +export type AssetUpdateManyWithWhereWithoutProjectInput = { + where: Prisma.AssetScalarWhereInput + data: Prisma.XOR +} + +export type AssetScalarWhereInput = { + AND?: Prisma.AssetScalarWhereInput | Prisma.AssetScalarWhereInput[] + OR?: Prisma.AssetScalarWhereInput[] + NOT?: Prisma.AssetScalarWhereInput | Prisma.AssetScalarWhereInput[] + id?: Prisma.StringFilter<"Asset"> | string + projectId?: Prisma.StringFilter<"Asset"> | string + kind?: Prisma.StringFilter<"Asset"> | string + storageKey?: Prisma.StringFilter<"Asset"> | string + mimeType?: Prisma.StringFilter<"Asset"> | string + byteSize?: Prisma.IntFilter<"Asset"> | number + sha256?: Prisma.StringFilter<"Asset"> | string + status?: Prisma.EnumAssetStatusFilter<"Asset"> | $Enums.AssetStatus + metadataJson?: Prisma.JsonNullableFilter<"Asset"> + createdAt?: Prisma.DateTimeFilter<"Asset"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Asset"> | Date | string +} + +export type AssetCreateManyProjectInput = { + id: string + kind: string + storageKey: string + mimeType: string + byteSize: number + sha256: string + status?: $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type AssetUpdateWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + kind?: Prisma.StringFieldUpdateOperationsInput | string + storageKey?: Prisma.StringFieldUpdateOperationsInput | string + mimeType?: Prisma.StringFieldUpdateOperationsInput | string + byteSize?: Prisma.IntFieldUpdateOperationsInput | number + sha256?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumAssetStatusFieldUpdateOperationsInput | $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AssetUncheckedUpdateWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + kind?: Prisma.StringFieldUpdateOperationsInput | string + storageKey?: Prisma.StringFieldUpdateOperationsInput | string + mimeType?: Prisma.StringFieldUpdateOperationsInput | string + byteSize?: Prisma.IntFieldUpdateOperationsInput | number + sha256?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumAssetStatusFieldUpdateOperationsInput | $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AssetUncheckedUpdateManyWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + kind?: Prisma.StringFieldUpdateOperationsInput | string + storageKey?: Prisma.StringFieldUpdateOperationsInput | string + mimeType?: Prisma.StringFieldUpdateOperationsInput | string + byteSize?: Prisma.IntFieldUpdateOperationsInput | number + sha256?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumAssetStatusFieldUpdateOperationsInput | $Enums.AssetStatus + metadataJson?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + + +export type AssetSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + projectId?: boolean + kind?: boolean + storageKey?: boolean + mimeType?: boolean + byteSize?: boolean + sha256?: boolean + status?: boolean + metadataJson?: boolean + createdAt?: boolean + updatedAt?: boolean + project?: boolean | Prisma.GameProjectDefaultArgs +}, ExtArgs["result"]["asset"]> + +export type AssetSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + projectId?: boolean + kind?: boolean + storageKey?: boolean + mimeType?: boolean + byteSize?: boolean + sha256?: boolean + status?: boolean + metadataJson?: boolean + createdAt?: boolean + updatedAt?: boolean + project?: boolean | Prisma.GameProjectDefaultArgs +}, ExtArgs["result"]["asset"]> + +export type AssetSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + projectId?: boolean + kind?: boolean + storageKey?: boolean + mimeType?: boolean + byteSize?: boolean + sha256?: boolean + status?: boolean + metadataJson?: boolean + createdAt?: boolean + updatedAt?: boolean + project?: boolean | Prisma.GameProjectDefaultArgs +}, ExtArgs["result"]["asset"]> + +export type AssetSelectScalar = { + id?: boolean + projectId?: boolean + kind?: boolean + storageKey?: boolean + mimeType?: boolean + byteSize?: boolean + sha256?: boolean + status?: boolean + metadataJson?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type AssetOmit = runtime.Types.Extensions.GetOmit<"id" | "projectId" | "kind" | "storageKey" | "mimeType" | "byteSize" | "sha256" | "status" | "metadataJson" | "createdAt" | "updatedAt", ExtArgs["result"]["asset"]> +export type AssetInclude = { + project?: boolean | Prisma.GameProjectDefaultArgs +} +export type AssetIncludeCreateManyAndReturn = { + project?: boolean | Prisma.GameProjectDefaultArgs +} +export type AssetIncludeUpdateManyAndReturn = { + project?: boolean | Prisma.GameProjectDefaultArgs +} + +export type $AssetPayload = { + name: "Asset" + objects: { + project: Prisma.$GameProjectPayload + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + projectId: string + kind: string + storageKey: string + mimeType: string + byteSize: number + sha256: string + status: $Enums.AssetStatus + metadataJson: runtime.JsonValue | null + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["asset"]> + composites: {} +} + +export type AssetGetPayload = runtime.Types.Result.GetResult + +export type AssetCountArgs = + Omit & { + select?: AssetCountAggregateInputType | true + } + +export interface AssetDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['Asset'], meta: { name: 'Asset' } } + /** + * Find zero or one Asset that matches the filter. + * @param {AssetFindUniqueArgs} args - Arguments to find a Asset + * @example + * // Get one Asset + * const asset = await prisma.asset.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__AssetClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one Asset that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {AssetFindUniqueOrThrowArgs} args - Arguments to find a Asset + * @example + * // Get one Asset + * const asset = await prisma.asset.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__AssetClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Asset that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AssetFindFirstArgs} args - Arguments to find a Asset + * @example + * // Get one Asset + * const asset = await prisma.asset.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__AssetClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Asset that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AssetFindFirstOrThrowArgs} args - Arguments to find a Asset + * @example + * // Get one Asset + * const asset = await prisma.asset.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__AssetClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Assets that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AssetFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Assets + * const assets = await prisma.asset.findMany() + * + * // Get first 10 Assets + * const assets = await prisma.asset.findMany({ take: 10 }) + * + * // Only select the `id` + * const assetWithIdOnly = await prisma.asset.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a Asset. + * @param {AssetCreateArgs} args - Arguments to create a Asset. + * @example + * // Create one Asset + * const Asset = await prisma.asset.create({ + * data: { + * // ... data to create a Asset + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__AssetClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Assets. + * @param {AssetCreateManyArgs} args - Arguments to create many Assets. + * @example + * // Create many Assets + * const asset = await prisma.asset.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Assets and returns the data saved in the database. + * @param {AssetCreateManyAndReturnArgs} args - Arguments to create many Assets. + * @example + * // Create many Assets + * const asset = await prisma.asset.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Assets and only return the `id` + * const assetWithIdOnly = await prisma.asset.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a Asset. + * @param {AssetDeleteArgs} args - Arguments to delete one Asset. + * @example + * // Delete one Asset + * const Asset = await prisma.asset.delete({ + * where: { + * // ... filter to delete one Asset + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__AssetClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one Asset. + * @param {AssetUpdateArgs} args - Arguments to update one Asset. + * @example + * // Update one Asset + * const asset = await prisma.asset.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__AssetClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Assets. + * @param {AssetDeleteManyArgs} args - Arguments to filter Assets to delete. + * @example + * // Delete a few Assets + * const { count } = await prisma.asset.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Assets. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AssetUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Assets + * const asset = await prisma.asset.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Assets and returns the data updated in the database. + * @param {AssetUpdateManyAndReturnArgs} args - Arguments to update many Assets. + * @example + * // Update many Assets + * const asset = await prisma.asset.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Assets and only return the `id` + * const assetWithIdOnly = await prisma.asset.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one Asset. + * @param {AssetUpsertArgs} args - Arguments to update or create a Asset. + * @example + * // Update or create a Asset + * const asset = await prisma.asset.upsert({ + * create: { + * // ... data to create a Asset + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the Asset we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__AssetClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Assets. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AssetCountArgs} args - Arguments to filter Assets to count. + * @example + * // Count the number of Assets + * const count = await prisma.asset.count({ + * where: { + * // ... the filter for the Assets we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a Asset. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AssetAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by Asset. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AssetGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends AssetGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: AssetGroupByArgs['orderBy'] } + : { orderBy?: AssetGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetAssetGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the Asset model + */ +readonly fields: AssetFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for Asset. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__AssetClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + project = {}>(args?: Prisma.Subset>): Prisma.Prisma__GameProjectClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the Asset model + */ +export interface AssetFieldRefs { + readonly id: Prisma.FieldRef<"Asset", 'String'> + readonly projectId: Prisma.FieldRef<"Asset", 'String'> + readonly kind: Prisma.FieldRef<"Asset", 'String'> + readonly storageKey: Prisma.FieldRef<"Asset", 'String'> + readonly mimeType: Prisma.FieldRef<"Asset", 'String'> + readonly byteSize: Prisma.FieldRef<"Asset", 'Int'> + readonly sha256: Prisma.FieldRef<"Asset", 'String'> + readonly status: Prisma.FieldRef<"Asset", 'AssetStatus'> + readonly metadataJson: Prisma.FieldRef<"Asset", 'Json'> + readonly createdAt: Prisma.FieldRef<"Asset", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"Asset", 'DateTime'> +} + + +// Custom InputTypes +/** + * Asset findUnique + */ +export type AssetFindUniqueArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null + /** + * Filter, which Asset to fetch. + */ + where: Prisma.AssetWhereUniqueInput +} + +/** + * Asset findUniqueOrThrow + */ +export type AssetFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null + /** + * Filter, which Asset to fetch. + */ + where: Prisma.AssetWhereUniqueInput +} + +/** + * Asset findFirst + */ +export type AssetFindFirstArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null + /** + * Filter, which Asset to fetch. + */ + where?: Prisma.AssetWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Assets to fetch. + */ + orderBy?: Prisma.AssetOrderByWithRelationInput | Prisma.AssetOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Assets. + */ + cursor?: Prisma.AssetWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Assets from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Assets. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Assets. + */ + distinct?: Prisma.AssetScalarFieldEnum | Prisma.AssetScalarFieldEnum[] +} + +/** + * Asset findFirstOrThrow + */ +export type AssetFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null + /** + * Filter, which Asset to fetch. + */ + where?: Prisma.AssetWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Assets to fetch. + */ + orderBy?: Prisma.AssetOrderByWithRelationInput | Prisma.AssetOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Assets. + */ + cursor?: Prisma.AssetWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Assets from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Assets. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Assets. + */ + distinct?: Prisma.AssetScalarFieldEnum | Prisma.AssetScalarFieldEnum[] +} + +/** + * Asset findMany + */ +export type AssetFindManyArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null + /** + * Filter, which Assets to fetch. + */ + where?: Prisma.AssetWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Assets to fetch. + */ + orderBy?: Prisma.AssetOrderByWithRelationInput | Prisma.AssetOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Assets. + */ + cursor?: Prisma.AssetWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Assets from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Assets. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Assets. + */ + distinct?: Prisma.AssetScalarFieldEnum | Prisma.AssetScalarFieldEnum[] +} + +/** + * Asset create + */ +export type AssetCreateArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null + /** + * The data needed to create a Asset. + */ + data: Prisma.XOR +} + +/** + * Asset createMany + */ +export type AssetCreateManyArgs = { + /** + * The data used to create many Assets. + */ + data: Prisma.AssetCreateManyInput | Prisma.AssetCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * Asset createManyAndReturn + */ +export type AssetCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelectCreateManyAndReturn | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * The data used to create many Assets. + */ + data: Prisma.AssetCreateManyInput | Prisma.AssetCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetIncludeCreateManyAndReturn | null +} + +/** + * Asset update + */ +export type AssetUpdateArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null + /** + * The data needed to update a Asset. + */ + data: Prisma.XOR + /** + * Choose, which Asset to update. + */ + where: Prisma.AssetWhereUniqueInput +} + +/** + * Asset updateMany + */ +export type AssetUpdateManyArgs = { + /** + * The data used to update Assets. + */ + data: Prisma.XOR + /** + * Filter which Assets to update + */ + where?: Prisma.AssetWhereInput + /** + * Limit how many Assets to update. + */ + limit?: number +} + +/** + * Asset updateManyAndReturn + */ +export type AssetUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * The data used to update Assets. + */ + data: Prisma.XOR + /** + * Filter which Assets to update + */ + where?: Prisma.AssetWhereInput + /** + * Limit how many Assets to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetIncludeUpdateManyAndReturn | null +} + +/** + * Asset upsert + */ +export type AssetUpsertArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null + /** + * The filter to search for the Asset to update in case it exists. + */ + where: Prisma.AssetWhereUniqueInput + /** + * In case the Asset found by the `where` argument doesn't exist, create a new Asset with this data. + */ + create: Prisma.XOR + /** + * In case the Asset was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * Asset delete + */ +export type AssetDeleteArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null + /** + * Filter which Asset to delete. + */ + where: Prisma.AssetWhereUniqueInput +} + +/** + * Asset deleteMany + */ +export type AssetDeleteManyArgs = { + /** + * Filter which Assets to delete + */ + where?: Prisma.AssetWhereInput + /** + * Limit how many Assets to delete. + */ + limit?: number +} + +/** + * Asset without action + */ +export type AssetDefaultArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null +} diff --git a/apps/api/src/generated/prisma/models/AuditLog.ts b/apps/api/src/generated/prisma/models/AuditLog.ts new file mode 100644 index 00000000..d221ed15 --- /dev/null +++ b/apps/api/src/generated/prisma/models/AuditLog.ts @@ -0,0 +1,1409 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `AuditLog` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model AuditLog + * + */ +export type AuditLogModel = runtime.Types.Result.DefaultSelection + +export type AggregateAuditLog = { + _count: AuditLogCountAggregateOutputType | null + _min: AuditLogMinAggregateOutputType | null + _max: AuditLogMaxAggregateOutputType | null +} + +export type AuditLogMinAggregateOutputType = { + id: string | null + actorId: string | null + action: string | null + targetType: string | null + targetId: string | null + createdAt: Date | null +} + +export type AuditLogMaxAggregateOutputType = { + id: string | null + actorId: string | null + action: string | null + targetType: string | null + targetId: string | null + createdAt: Date | null +} + +export type AuditLogCountAggregateOutputType = { + id: number + actorId: number + action: number + targetType: number + targetId: number + eventJson: number + createdAt: number + _all: number +} + + +export type AuditLogMinAggregateInputType = { + id?: true + actorId?: true + action?: true + targetType?: true + targetId?: true + createdAt?: true +} + +export type AuditLogMaxAggregateInputType = { + id?: true + actorId?: true + action?: true + targetType?: true + targetId?: true + createdAt?: true +} + +export type AuditLogCountAggregateInputType = { + id?: true + actorId?: true + action?: true + targetType?: true + targetId?: true + eventJson?: true + createdAt?: true + _all?: true +} + +export type AuditLogAggregateArgs = { + /** + * Filter which AuditLog to aggregate. + */ + where?: Prisma.AuditLogWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AuditLogs to fetch. + */ + orderBy?: Prisma.AuditLogOrderByWithRelationInput | Prisma.AuditLogOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.AuditLogWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AuditLogs from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AuditLogs. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned AuditLogs + **/ + _count?: true | AuditLogCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: AuditLogMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: AuditLogMaxAggregateInputType +} + +export type GetAuditLogAggregateType = { + [P in keyof T & keyof AggregateAuditLog]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type AuditLogGroupByArgs = { + where?: Prisma.AuditLogWhereInput + orderBy?: Prisma.AuditLogOrderByWithAggregationInput | Prisma.AuditLogOrderByWithAggregationInput[] + by: Prisma.AuditLogScalarFieldEnum[] | Prisma.AuditLogScalarFieldEnum + having?: Prisma.AuditLogScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: AuditLogCountAggregateInputType | true + _min?: AuditLogMinAggregateInputType + _max?: AuditLogMaxAggregateInputType +} + +export type AuditLogGroupByOutputType = { + id: string + actorId: string + action: string + targetType: string + targetId: string + eventJson: runtime.JsonValue + createdAt: Date + _count: AuditLogCountAggregateOutputType | null + _min: AuditLogMinAggregateOutputType | null + _max: AuditLogMaxAggregateOutputType | null +} + +export type GetAuditLogGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof AuditLogGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type AuditLogWhereInput = { + AND?: Prisma.AuditLogWhereInput | Prisma.AuditLogWhereInput[] + OR?: Prisma.AuditLogWhereInput[] + NOT?: Prisma.AuditLogWhereInput | Prisma.AuditLogWhereInput[] + id?: Prisma.StringFilter<"AuditLog"> | string + actorId?: Prisma.StringFilter<"AuditLog"> | string + action?: Prisma.StringFilter<"AuditLog"> | string + targetType?: Prisma.StringFilter<"AuditLog"> | string + targetId?: Prisma.StringFilter<"AuditLog"> | string + eventJson?: Prisma.JsonFilter<"AuditLog"> + createdAt?: Prisma.DateTimeFilter<"AuditLog"> | Date | string + actor?: Prisma.XOR +} + +export type AuditLogOrderByWithRelationInput = { + id?: Prisma.SortOrder + actorId?: Prisma.SortOrder + action?: Prisma.SortOrder + targetType?: Prisma.SortOrder + targetId?: Prisma.SortOrder + eventJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + actor?: Prisma.UserOrderByWithRelationInput +} + +export type AuditLogWhereUniqueInput = Prisma.AtLeast<{ + id?: string + AND?: Prisma.AuditLogWhereInput | Prisma.AuditLogWhereInput[] + OR?: Prisma.AuditLogWhereInput[] + NOT?: Prisma.AuditLogWhereInput | Prisma.AuditLogWhereInput[] + actorId?: Prisma.StringFilter<"AuditLog"> | string + action?: Prisma.StringFilter<"AuditLog"> | string + targetType?: Prisma.StringFilter<"AuditLog"> | string + targetId?: Prisma.StringFilter<"AuditLog"> | string + eventJson?: Prisma.JsonFilter<"AuditLog"> + createdAt?: Prisma.DateTimeFilter<"AuditLog"> | Date | string + actor?: Prisma.XOR +}, "id"> + +export type AuditLogOrderByWithAggregationInput = { + id?: Prisma.SortOrder + actorId?: Prisma.SortOrder + action?: Prisma.SortOrder + targetType?: Prisma.SortOrder + targetId?: Prisma.SortOrder + eventJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + _count?: Prisma.AuditLogCountOrderByAggregateInput + _max?: Prisma.AuditLogMaxOrderByAggregateInput + _min?: Prisma.AuditLogMinOrderByAggregateInput +} + +export type AuditLogScalarWhereWithAggregatesInput = { + AND?: Prisma.AuditLogScalarWhereWithAggregatesInput | Prisma.AuditLogScalarWhereWithAggregatesInput[] + OR?: Prisma.AuditLogScalarWhereWithAggregatesInput[] + NOT?: Prisma.AuditLogScalarWhereWithAggregatesInput | Prisma.AuditLogScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"AuditLog"> | string + actorId?: Prisma.StringWithAggregatesFilter<"AuditLog"> | string + action?: Prisma.StringWithAggregatesFilter<"AuditLog"> | string + targetType?: Prisma.StringWithAggregatesFilter<"AuditLog"> | string + targetId?: Prisma.StringWithAggregatesFilter<"AuditLog"> | string + eventJson?: Prisma.JsonWithAggregatesFilter<"AuditLog"> + createdAt?: Prisma.DateTimeWithAggregatesFilter<"AuditLog"> | Date | string +} + +export type AuditLogCreateInput = { + id: string + action: string + targetType: string + targetId: string + eventJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + actor: Prisma.UserCreateNestedOneWithoutAuditLogsInput +} + +export type AuditLogUncheckedCreateInput = { + id: string + actorId: string + action: string + targetType: string + targetId: string + eventJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string +} + +export type AuditLogUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + action?: Prisma.StringFieldUpdateOperationsInput | string + targetType?: Prisma.StringFieldUpdateOperationsInput | string + targetId?: Prisma.StringFieldUpdateOperationsInput | string + eventJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + actor?: Prisma.UserUpdateOneRequiredWithoutAuditLogsNestedInput +} + +export type AuditLogUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + actorId?: Prisma.StringFieldUpdateOperationsInput | string + action?: Prisma.StringFieldUpdateOperationsInput | string + targetType?: Prisma.StringFieldUpdateOperationsInput | string + targetId?: Prisma.StringFieldUpdateOperationsInput | string + eventJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AuditLogCreateManyInput = { + id: string + actorId: string + action: string + targetType: string + targetId: string + eventJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string +} + +export type AuditLogUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + action?: Prisma.StringFieldUpdateOperationsInput | string + targetType?: Prisma.StringFieldUpdateOperationsInput | string + targetId?: Prisma.StringFieldUpdateOperationsInput | string + eventJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AuditLogUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + actorId?: Prisma.StringFieldUpdateOperationsInput | string + action?: Prisma.StringFieldUpdateOperationsInput | string + targetType?: Prisma.StringFieldUpdateOperationsInput | string + targetId?: Prisma.StringFieldUpdateOperationsInput | string + eventJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AuditLogListRelationFilter = { + every?: Prisma.AuditLogWhereInput + some?: Prisma.AuditLogWhereInput + none?: Prisma.AuditLogWhereInput +} + +export type AuditLogOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type AuditLogCountOrderByAggregateInput = { + id?: Prisma.SortOrder + actorId?: Prisma.SortOrder + action?: Prisma.SortOrder + targetType?: Prisma.SortOrder + targetId?: Prisma.SortOrder + eventJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type AuditLogMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + actorId?: Prisma.SortOrder + action?: Prisma.SortOrder + targetType?: Prisma.SortOrder + targetId?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type AuditLogMinOrderByAggregateInput = { + id?: Prisma.SortOrder + actorId?: Prisma.SortOrder + action?: Prisma.SortOrder + targetType?: Prisma.SortOrder + targetId?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type AuditLogCreateNestedManyWithoutActorInput = { + create?: Prisma.XOR | Prisma.AuditLogCreateWithoutActorInput[] | Prisma.AuditLogUncheckedCreateWithoutActorInput[] + connectOrCreate?: Prisma.AuditLogCreateOrConnectWithoutActorInput | Prisma.AuditLogCreateOrConnectWithoutActorInput[] + createMany?: Prisma.AuditLogCreateManyActorInputEnvelope + connect?: Prisma.AuditLogWhereUniqueInput | Prisma.AuditLogWhereUniqueInput[] +} + +export type AuditLogUncheckedCreateNestedManyWithoutActorInput = { + create?: Prisma.XOR | Prisma.AuditLogCreateWithoutActorInput[] | Prisma.AuditLogUncheckedCreateWithoutActorInput[] + connectOrCreate?: Prisma.AuditLogCreateOrConnectWithoutActorInput | Prisma.AuditLogCreateOrConnectWithoutActorInput[] + createMany?: Prisma.AuditLogCreateManyActorInputEnvelope + connect?: Prisma.AuditLogWhereUniqueInput | Prisma.AuditLogWhereUniqueInput[] +} + +export type AuditLogUpdateManyWithoutActorNestedInput = { + create?: Prisma.XOR | Prisma.AuditLogCreateWithoutActorInput[] | Prisma.AuditLogUncheckedCreateWithoutActorInput[] + connectOrCreate?: Prisma.AuditLogCreateOrConnectWithoutActorInput | Prisma.AuditLogCreateOrConnectWithoutActorInput[] + upsert?: Prisma.AuditLogUpsertWithWhereUniqueWithoutActorInput | Prisma.AuditLogUpsertWithWhereUniqueWithoutActorInput[] + createMany?: Prisma.AuditLogCreateManyActorInputEnvelope + set?: Prisma.AuditLogWhereUniqueInput | Prisma.AuditLogWhereUniqueInput[] + disconnect?: Prisma.AuditLogWhereUniqueInput | Prisma.AuditLogWhereUniqueInput[] + delete?: Prisma.AuditLogWhereUniqueInput | Prisma.AuditLogWhereUniqueInput[] + connect?: Prisma.AuditLogWhereUniqueInput | Prisma.AuditLogWhereUniqueInput[] + update?: Prisma.AuditLogUpdateWithWhereUniqueWithoutActorInput | Prisma.AuditLogUpdateWithWhereUniqueWithoutActorInput[] + updateMany?: Prisma.AuditLogUpdateManyWithWhereWithoutActorInput | Prisma.AuditLogUpdateManyWithWhereWithoutActorInput[] + deleteMany?: Prisma.AuditLogScalarWhereInput | Prisma.AuditLogScalarWhereInput[] +} + +export type AuditLogUncheckedUpdateManyWithoutActorNestedInput = { + create?: Prisma.XOR | Prisma.AuditLogCreateWithoutActorInput[] | Prisma.AuditLogUncheckedCreateWithoutActorInput[] + connectOrCreate?: Prisma.AuditLogCreateOrConnectWithoutActorInput | Prisma.AuditLogCreateOrConnectWithoutActorInput[] + upsert?: Prisma.AuditLogUpsertWithWhereUniqueWithoutActorInput | Prisma.AuditLogUpsertWithWhereUniqueWithoutActorInput[] + createMany?: Prisma.AuditLogCreateManyActorInputEnvelope + set?: Prisma.AuditLogWhereUniqueInput | Prisma.AuditLogWhereUniqueInput[] + disconnect?: Prisma.AuditLogWhereUniqueInput | Prisma.AuditLogWhereUniqueInput[] + delete?: Prisma.AuditLogWhereUniqueInput | Prisma.AuditLogWhereUniqueInput[] + connect?: Prisma.AuditLogWhereUniqueInput | Prisma.AuditLogWhereUniqueInput[] + update?: Prisma.AuditLogUpdateWithWhereUniqueWithoutActorInput | Prisma.AuditLogUpdateWithWhereUniqueWithoutActorInput[] + updateMany?: Prisma.AuditLogUpdateManyWithWhereWithoutActorInput | Prisma.AuditLogUpdateManyWithWhereWithoutActorInput[] + deleteMany?: Prisma.AuditLogScalarWhereInput | Prisma.AuditLogScalarWhereInput[] +} + +export type AuditLogCreateWithoutActorInput = { + id: string + action: string + targetType: string + targetId: string + eventJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string +} + +export type AuditLogUncheckedCreateWithoutActorInput = { + id: string + action: string + targetType: string + targetId: string + eventJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string +} + +export type AuditLogCreateOrConnectWithoutActorInput = { + where: Prisma.AuditLogWhereUniqueInput + create: Prisma.XOR +} + +export type AuditLogCreateManyActorInputEnvelope = { + data: Prisma.AuditLogCreateManyActorInput | Prisma.AuditLogCreateManyActorInput[] + skipDuplicates?: boolean +} + +export type AuditLogUpsertWithWhereUniqueWithoutActorInput = { + where: Prisma.AuditLogWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type AuditLogUpdateWithWhereUniqueWithoutActorInput = { + where: Prisma.AuditLogWhereUniqueInput + data: Prisma.XOR +} + +export type AuditLogUpdateManyWithWhereWithoutActorInput = { + where: Prisma.AuditLogScalarWhereInput + data: Prisma.XOR +} + +export type AuditLogScalarWhereInput = { + AND?: Prisma.AuditLogScalarWhereInput | Prisma.AuditLogScalarWhereInput[] + OR?: Prisma.AuditLogScalarWhereInput[] + NOT?: Prisma.AuditLogScalarWhereInput | Prisma.AuditLogScalarWhereInput[] + id?: Prisma.StringFilter<"AuditLog"> | string + actorId?: Prisma.StringFilter<"AuditLog"> | string + action?: Prisma.StringFilter<"AuditLog"> | string + targetType?: Prisma.StringFilter<"AuditLog"> | string + targetId?: Prisma.StringFilter<"AuditLog"> | string + eventJson?: Prisma.JsonFilter<"AuditLog"> + createdAt?: Prisma.DateTimeFilter<"AuditLog"> | Date | string +} + +export type AuditLogCreateManyActorInput = { + id: string + action: string + targetType: string + targetId: string + eventJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string +} + +export type AuditLogUpdateWithoutActorInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + action?: Prisma.StringFieldUpdateOperationsInput | string + targetType?: Prisma.StringFieldUpdateOperationsInput | string + targetId?: Prisma.StringFieldUpdateOperationsInput | string + eventJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AuditLogUncheckedUpdateWithoutActorInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + action?: Prisma.StringFieldUpdateOperationsInput | string + targetType?: Prisma.StringFieldUpdateOperationsInput | string + targetId?: Prisma.StringFieldUpdateOperationsInput | string + eventJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type AuditLogUncheckedUpdateManyWithoutActorInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + action?: Prisma.StringFieldUpdateOperationsInput | string + targetType?: Prisma.StringFieldUpdateOperationsInput | string + targetId?: Prisma.StringFieldUpdateOperationsInput | string + eventJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + + +export type AuditLogSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + actorId?: boolean + action?: boolean + targetType?: boolean + targetId?: boolean + eventJson?: boolean + createdAt?: boolean + actor?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["auditLog"]> + +export type AuditLogSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + actorId?: boolean + action?: boolean + targetType?: boolean + targetId?: boolean + eventJson?: boolean + createdAt?: boolean + actor?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["auditLog"]> + +export type AuditLogSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + actorId?: boolean + action?: boolean + targetType?: boolean + targetId?: boolean + eventJson?: boolean + createdAt?: boolean + actor?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["auditLog"]> + +export type AuditLogSelectScalar = { + id?: boolean + actorId?: boolean + action?: boolean + targetType?: boolean + targetId?: boolean + eventJson?: boolean + createdAt?: boolean +} + +export type AuditLogOmit = runtime.Types.Extensions.GetOmit<"id" | "actorId" | "action" | "targetType" | "targetId" | "eventJson" | "createdAt", ExtArgs["result"]["auditLog"]> +export type AuditLogInclude = { + actor?: boolean | Prisma.UserDefaultArgs +} +export type AuditLogIncludeCreateManyAndReturn = { + actor?: boolean | Prisma.UserDefaultArgs +} +export type AuditLogIncludeUpdateManyAndReturn = { + actor?: boolean | Prisma.UserDefaultArgs +} + +export type $AuditLogPayload = { + name: "AuditLog" + objects: { + actor: Prisma.$UserPayload + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + actorId: string + action: string + targetType: string + targetId: string + eventJson: runtime.JsonValue + createdAt: Date + }, ExtArgs["result"]["auditLog"]> + composites: {} +} + +export type AuditLogGetPayload = runtime.Types.Result.GetResult + +export type AuditLogCountArgs = + Omit & { + select?: AuditLogCountAggregateInputType | true + } + +export interface AuditLogDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['AuditLog'], meta: { name: 'AuditLog' } } + /** + * Find zero or one AuditLog that matches the filter. + * @param {AuditLogFindUniqueArgs} args - Arguments to find a AuditLog + * @example + * // Get one AuditLog + * const auditLog = await prisma.auditLog.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__AuditLogClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one AuditLog that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {AuditLogFindUniqueOrThrowArgs} args - Arguments to find a AuditLog + * @example + * // Get one AuditLog + * const auditLog = await prisma.auditLog.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__AuditLogClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first AuditLog that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AuditLogFindFirstArgs} args - Arguments to find a AuditLog + * @example + * // Get one AuditLog + * const auditLog = await prisma.auditLog.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__AuditLogClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first AuditLog that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AuditLogFindFirstOrThrowArgs} args - Arguments to find a AuditLog + * @example + * // Get one AuditLog + * const auditLog = await prisma.auditLog.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__AuditLogClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more AuditLogs that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AuditLogFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all AuditLogs + * const auditLogs = await prisma.auditLog.findMany() + * + * // Get first 10 AuditLogs + * const auditLogs = await prisma.auditLog.findMany({ take: 10 }) + * + * // Only select the `id` + * const auditLogWithIdOnly = await prisma.auditLog.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a AuditLog. + * @param {AuditLogCreateArgs} args - Arguments to create a AuditLog. + * @example + * // Create one AuditLog + * const AuditLog = await prisma.auditLog.create({ + * data: { + * // ... data to create a AuditLog + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__AuditLogClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many AuditLogs. + * @param {AuditLogCreateManyArgs} args - Arguments to create many AuditLogs. + * @example + * // Create many AuditLogs + * const auditLog = await prisma.auditLog.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many AuditLogs and returns the data saved in the database. + * @param {AuditLogCreateManyAndReturnArgs} args - Arguments to create many AuditLogs. + * @example + * // Create many AuditLogs + * const auditLog = await prisma.auditLog.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many AuditLogs and only return the `id` + * const auditLogWithIdOnly = await prisma.auditLog.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a AuditLog. + * @param {AuditLogDeleteArgs} args - Arguments to delete one AuditLog. + * @example + * // Delete one AuditLog + * const AuditLog = await prisma.auditLog.delete({ + * where: { + * // ... filter to delete one AuditLog + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__AuditLogClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one AuditLog. + * @param {AuditLogUpdateArgs} args - Arguments to update one AuditLog. + * @example + * // Update one AuditLog + * const auditLog = await prisma.auditLog.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__AuditLogClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more AuditLogs. + * @param {AuditLogDeleteManyArgs} args - Arguments to filter AuditLogs to delete. + * @example + * // Delete a few AuditLogs + * const { count } = await prisma.auditLog.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more AuditLogs. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AuditLogUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many AuditLogs + * const auditLog = await prisma.auditLog.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more AuditLogs and returns the data updated in the database. + * @param {AuditLogUpdateManyAndReturnArgs} args - Arguments to update many AuditLogs. + * @example + * // Update many AuditLogs + * const auditLog = await prisma.auditLog.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more AuditLogs and only return the `id` + * const auditLogWithIdOnly = await prisma.auditLog.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one AuditLog. + * @param {AuditLogUpsertArgs} args - Arguments to update or create a AuditLog. + * @example + * // Update or create a AuditLog + * const auditLog = await prisma.auditLog.upsert({ + * create: { + * // ... data to create a AuditLog + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the AuditLog we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__AuditLogClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of AuditLogs. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AuditLogCountArgs} args - Arguments to filter AuditLogs to count. + * @example + * // Count the number of AuditLogs + * const count = await prisma.auditLog.count({ + * where: { + * // ... the filter for the AuditLogs we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a AuditLog. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AuditLogAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by AuditLog. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AuditLogGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends AuditLogGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: AuditLogGroupByArgs['orderBy'] } + : { orderBy?: AuditLogGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetAuditLogGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the AuditLog model + */ +readonly fields: AuditLogFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for AuditLog. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__AuditLogClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + actor = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the AuditLog model + */ +export interface AuditLogFieldRefs { + readonly id: Prisma.FieldRef<"AuditLog", 'String'> + readonly actorId: Prisma.FieldRef<"AuditLog", 'String'> + readonly action: Prisma.FieldRef<"AuditLog", 'String'> + readonly targetType: Prisma.FieldRef<"AuditLog", 'String'> + readonly targetId: Prisma.FieldRef<"AuditLog", 'String'> + readonly eventJson: Prisma.FieldRef<"AuditLog", 'Json'> + readonly createdAt: Prisma.FieldRef<"AuditLog", 'DateTime'> +} + + +// Custom InputTypes +/** + * AuditLog findUnique + */ +export type AuditLogFindUniqueArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null + /** + * Filter, which AuditLog to fetch. + */ + where: Prisma.AuditLogWhereUniqueInput +} + +/** + * AuditLog findUniqueOrThrow + */ +export type AuditLogFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null + /** + * Filter, which AuditLog to fetch. + */ + where: Prisma.AuditLogWhereUniqueInput +} + +/** + * AuditLog findFirst + */ +export type AuditLogFindFirstArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null + /** + * Filter, which AuditLog to fetch. + */ + where?: Prisma.AuditLogWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AuditLogs to fetch. + */ + orderBy?: Prisma.AuditLogOrderByWithRelationInput | Prisma.AuditLogOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for AuditLogs. + */ + cursor?: Prisma.AuditLogWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AuditLogs from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AuditLogs. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AuditLogs. + */ + distinct?: Prisma.AuditLogScalarFieldEnum | Prisma.AuditLogScalarFieldEnum[] +} + +/** + * AuditLog findFirstOrThrow + */ +export type AuditLogFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null + /** + * Filter, which AuditLog to fetch. + */ + where?: Prisma.AuditLogWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AuditLogs to fetch. + */ + orderBy?: Prisma.AuditLogOrderByWithRelationInput | Prisma.AuditLogOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for AuditLogs. + */ + cursor?: Prisma.AuditLogWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AuditLogs from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AuditLogs. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AuditLogs. + */ + distinct?: Prisma.AuditLogScalarFieldEnum | Prisma.AuditLogScalarFieldEnum[] +} + +/** + * AuditLog findMany + */ +export type AuditLogFindManyArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null + /** + * Filter, which AuditLogs to fetch. + */ + where?: Prisma.AuditLogWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AuditLogs to fetch. + */ + orderBy?: Prisma.AuditLogOrderByWithRelationInput | Prisma.AuditLogOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing AuditLogs. + */ + cursor?: Prisma.AuditLogWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AuditLogs from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AuditLogs. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AuditLogs. + */ + distinct?: Prisma.AuditLogScalarFieldEnum | Prisma.AuditLogScalarFieldEnum[] +} + +/** + * AuditLog create + */ +export type AuditLogCreateArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null + /** + * The data needed to create a AuditLog. + */ + data: Prisma.XOR +} + +/** + * AuditLog createMany + */ +export type AuditLogCreateManyArgs = { + /** + * The data used to create many AuditLogs. + */ + data: Prisma.AuditLogCreateManyInput | Prisma.AuditLogCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * AuditLog createManyAndReturn + */ +export type AuditLogCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelectCreateManyAndReturn | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * The data used to create many AuditLogs. + */ + data: Prisma.AuditLogCreateManyInput | Prisma.AuditLogCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogIncludeCreateManyAndReturn | null +} + +/** + * AuditLog update + */ +export type AuditLogUpdateArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null + /** + * The data needed to update a AuditLog. + */ + data: Prisma.XOR + /** + * Choose, which AuditLog to update. + */ + where: Prisma.AuditLogWhereUniqueInput +} + +/** + * AuditLog updateMany + */ +export type AuditLogUpdateManyArgs = { + /** + * The data used to update AuditLogs. + */ + data: Prisma.XOR + /** + * Filter which AuditLogs to update + */ + where?: Prisma.AuditLogWhereInput + /** + * Limit how many AuditLogs to update. + */ + limit?: number +} + +/** + * AuditLog updateManyAndReturn + */ +export type AuditLogUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * The data used to update AuditLogs. + */ + data: Prisma.XOR + /** + * Filter which AuditLogs to update + */ + where?: Prisma.AuditLogWhereInput + /** + * Limit how many AuditLogs to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogIncludeUpdateManyAndReturn | null +} + +/** + * AuditLog upsert + */ +export type AuditLogUpsertArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null + /** + * The filter to search for the AuditLog to update in case it exists. + */ + where: Prisma.AuditLogWhereUniqueInput + /** + * In case the AuditLog found by the `where` argument doesn't exist, create a new AuditLog with this data. + */ + create: Prisma.XOR + /** + * In case the AuditLog was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * AuditLog delete + */ +export type AuditLogDeleteArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null + /** + * Filter which AuditLog to delete. + */ + where: Prisma.AuditLogWhereUniqueInput +} + +/** + * AuditLog deleteMany + */ +export type AuditLogDeleteManyArgs = { + /** + * Filter which AuditLogs to delete + */ + where?: Prisma.AuditLogWhereInput + /** + * Limit how many AuditLogs to delete. + */ + limit?: number +} + +/** + * AuditLog without action + */ +export type AuditLogDefaultArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null +} diff --git a/apps/api/src/generated/prisma/models/GameProject.ts b/apps/api/src/generated/prisma/models/GameProject.ts new file mode 100644 index 00000000..b1d9c707 --- /dev/null +++ b/apps/api/src/generated/prisma/models/GameProject.ts @@ -0,0 +1,2123 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `GameProject` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model GameProject + * + */ +export type GameProjectModel = runtime.Types.Result.DefaultSelection + +export type AggregateGameProject = { + _count: GameProjectCountAggregateOutputType | null + _min: GameProjectMinAggregateOutputType | null + _max: GameProjectMaxAggregateOutputType | null +} + +export type GameProjectMinAggregateOutputType = { + id: string | null + ownerId: string | null + slug: string | null + title: string | null + status: $Enums.ProjectStatus | null + createdAt: Date | null + updatedAt: Date | null +} + +export type GameProjectMaxAggregateOutputType = { + id: string | null + ownerId: string | null + slug: string | null + title: string | null + status: $Enums.ProjectStatus | null + createdAt: Date | null + updatedAt: Date | null +} + +export type GameProjectCountAggregateOutputType = { + id: number + ownerId: number + slug: number + title: number + status: number + createdAt: number + updatedAt: number + _all: number +} + + +export type GameProjectMinAggregateInputType = { + id?: true + ownerId?: true + slug?: true + title?: true + status?: true + createdAt?: true + updatedAt?: true +} + +export type GameProjectMaxAggregateInputType = { + id?: true + ownerId?: true + slug?: true + title?: true + status?: true + createdAt?: true + updatedAt?: true +} + +export type GameProjectCountAggregateInputType = { + id?: true + ownerId?: true + slug?: true + title?: true + status?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type GameProjectAggregateArgs = { + /** + * Filter which GameProject to aggregate. + */ + where?: Prisma.GameProjectWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of GameProjects to fetch. + */ + orderBy?: Prisma.GameProjectOrderByWithRelationInput | Prisma.GameProjectOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.GameProjectWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` GameProjects from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` GameProjects. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned GameProjects + **/ + _count?: true | GameProjectCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: GameProjectMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: GameProjectMaxAggregateInputType +} + +export type GetGameProjectAggregateType = { + [P in keyof T & keyof AggregateGameProject]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type GameProjectGroupByArgs = { + where?: Prisma.GameProjectWhereInput + orderBy?: Prisma.GameProjectOrderByWithAggregationInput | Prisma.GameProjectOrderByWithAggregationInput[] + by: Prisma.GameProjectScalarFieldEnum[] | Prisma.GameProjectScalarFieldEnum + having?: Prisma.GameProjectScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: GameProjectCountAggregateInputType | true + _min?: GameProjectMinAggregateInputType + _max?: GameProjectMaxAggregateInputType +} + +export type GameProjectGroupByOutputType = { + id: string + ownerId: string + slug: string + title: string + status: $Enums.ProjectStatus + createdAt: Date + updatedAt: Date + _count: GameProjectCountAggregateOutputType | null + _min: GameProjectMinAggregateOutputType | null + _max: GameProjectMaxAggregateOutputType | null +} + +export type GetGameProjectGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof GameProjectGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type GameProjectWhereInput = { + AND?: Prisma.GameProjectWhereInput | Prisma.GameProjectWhereInput[] + OR?: Prisma.GameProjectWhereInput[] + NOT?: Prisma.GameProjectWhereInput | Prisma.GameProjectWhereInput[] + id?: Prisma.StringFilter<"GameProject"> | string + ownerId?: Prisma.StringFilter<"GameProject"> | string + slug?: Prisma.StringFilter<"GameProject"> | string + title?: Prisma.StringFilter<"GameProject"> | string + status?: Prisma.EnumProjectStatusFilter<"GameProject"> | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFilter<"GameProject"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"GameProject"> | Date | string + owner?: Prisma.XOR + versions?: Prisma.GameVersionListRelationFilter + assets?: Prisma.AssetListRelationFilter + jobs?: Prisma.JobListRelationFilter + projectTargetJobs?: Prisma.JobListRelationFilter + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionListRelationFilter +} + +export type GameProjectOrderByWithRelationInput = { + id?: Prisma.SortOrder + ownerId?: Prisma.SortOrder + slug?: Prisma.SortOrder + title?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + owner?: Prisma.UserOrderByWithRelationInput + versions?: Prisma.GameVersionOrderByRelationAggregateInput + assets?: Prisma.AssetOrderByRelationAggregateInput + jobs?: Prisma.JobOrderByRelationAggregateInput + projectTargetJobs?: Prisma.JobOrderByRelationAggregateInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionOrderByRelationAggregateInput +} + +export type GameProjectWhereUniqueInput = Prisma.AtLeast<{ + id?: string + slug?: string + AND?: Prisma.GameProjectWhereInput | Prisma.GameProjectWhereInput[] + OR?: Prisma.GameProjectWhereInput[] + NOT?: Prisma.GameProjectWhereInput | Prisma.GameProjectWhereInput[] + ownerId?: Prisma.StringFilter<"GameProject"> | string + title?: Prisma.StringFilter<"GameProject"> | string + status?: Prisma.EnumProjectStatusFilter<"GameProject"> | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFilter<"GameProject"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"GameProject"> | Date | string + owner?: Prisma.XOR + versions?: Prisma.GameVersionListRelationFilter + assets?: Prisma.AssetListRelationFilter + jobs?: Prisma.JobListRelationFilter + projectTargetJobs?: Prisma.JobListRelationFilter + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionListRelationFilter +}, "id" | "slug"> + +export type GameProjectOrderByWithAggregationInput = { + id?: Prisma.SortOrder + ownerId?: Prisma.SortOrder + slug?: Prisma.SortOrder + title?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.GameProjectCountOrderByAggregateInput + _max?: Prisma.GameProjectMaxOrderByAggregateInput + _min?: Prisma.GameProjectMinOrderByAggregateInput +} + +export type GameProjectScalarWhereWithAggregatesInput = { + AND?: Prisma.GameProjectScalarWhereWithAggregatesInput | Prisma.GameProjectScalarWhereWithAggregatesInput[] + OR?: Prisma.GameProjectScalarWhereWithAggregatesInput[] + NOT?: Prisma.GameProjectScalarWhereWithAggregatesInput | Prisma.GameProjectScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"GameProject"> | string + ownerId?: Prisma.StringWithAggregatesFilter<"GameProject"> | string + slug?: Prisma.StringWithAggregatesFilter<"GameProject"> | string + title?: Prisma.StringWithAggregatesFilter<"GameProject"> | string + status?: Prisma.EnumProjectStatusWithAggregatesFilter<"GameProject"> | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeWithAggregatesFilter<"GameProject"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"GameProject"> | Date | string +} + +export type GameProjectCreateInput = { + id: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + owner: Prisma.UserCreateNestedOneWithoutGameProjectsInput + versions?: Prisma.GameVersionCreateNestedManyWithoutProjectInput + assets?: Prisma.AssetCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobCreateNestedManyWithoutGameProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutProjectInput +} + +export type GameProjectUncheckedCreateInput = { + id: string + ownerId: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + versions?: Prisma.GameVersionUncheckedCreateNestedManyWithoutProjectInput + assets?: Prisma.AssetUncheckedCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutProjectInput +} + +export type GameProjectUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + owner?: Prisma.UserUpdateOneRequiredWithoutGameProjectsNestedInput + versions?: Prisma.GameVersionUpdateManyWithoutProjectNestedInput + assets?: Prisma.AssetUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUpdateManyWithoutGameProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutProjectNestedInput +} + +export type GameProjectUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + ownerId?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versions?: Prisma.GameVersionUncheckedUpdateManyWithoutProjectNestedInput + assets?: Prisma.AssetUncheckedUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutProjectNestedInput +} + +export type GameProjectCreateManyInput = { + id: string + ownerId: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string +} + +export type GameProjectUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type GameProjectUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + ownerId?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type GameProjectListRelationFilter = { + every?: Prisma.GameProjectWhereInput + some?: Prisma.GameProjectWhereInput + none?: Prisma.GameProjectWhereInput +} + +export type GameProjectOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type GameProjectCountOrderByAggregateInput = { + id?: Prisma.SortOrder + ownerId?: Prisma.SortOrder + slug?: Prisma.SortOrder + title?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type GameProjectMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + ownerId?: Prisma.SortOrder + slug?: Prisma.SortOrder + title?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type GameProjectMinOrderByAggregateInput = { + id?: Prisma.SortOrder + ownerId?: Prisma.SortOrder + slug?: Prisma.SortOrder + title?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type GameProjectScalarRelationFilter = { + is?: Prisma.GameProjectWhereInput + isNot?: Prisma.GameProjectWhereInput +} + +export type GameProjectNullableScalarRelationFilter = { + is?: Prisma.GameProjectWhereInput | null + isNot?: Prisma.GameProjectWhereInput | null +} + +export type GameProjectCreateNestedManyWithoutOwnerInput = { + create?: Prisma.XOR | Prisma.GameProjectCreateWithoutOwnerInput[] | Prisma.GameProjectUncheckedCreateWithoutOwnerInput[] + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutOwnerInput | Prisma.GameProjectCreateOrConnectWithoutOwnerInput[] + createMany?: Prisma.GameProjectCreateManyOwnerInputEnvelope + connect?: Prisma.GameProjectWhereUniqueInput | Prisma.GameProjectWhereUniqueInput[] +} + +export type GameProjectUncheckedCreateNestedManyWithoutOwnerInput = { + create?: Prisma.XOR | Prisma.GameProjectCreateWithoutOwnerInput[] | Prisma.GameProjectUncheckedCreateWithoutOwnerInput[] + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutOwnerInput | Prisma.GameProjectCreateOrConnectWithoutOwnerInput[] + createMany?: Prisma.GameProjectCreateManyOwnerInputEnvelope + connect?: Prisma.GameProjectWhereUniqueInput | Prisma.GameProjectWhereUniqueInput[] +} + +export type GameProjectUpdateManyWithoutOwnerNestedInput = { + create?: Prisma.XOR | Prisma.GameProjectCreateWithoutOwnerInput[] | Prisma.GameProjectUncheckedCreateWithoutOwnerInput[] + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutOwnerInput | Prisma.GameProjectCreateOrConnectWithoutOwnerInput[] + upsert?: Prisma.GameProjectUpsertWithWhereUniqueWithoutOwnerInput | Prisma.GameProjectUpsertWithWhereUniqueWithoutOwnerInput[] + createMany?: Prisma.GameProjectCreateManyOwnerInputEnvelope + set?: Prisma.GameProjectWhereUniqueInput | Prisma.GameProjectWhereUniqueInput[] + disconnect?: Prisma.GameProjectWhereUniqueInput | Prisma.GameProjectWhereUniqueInput[] + delete?: Prisma.GameProjectWhereUniqueInput | Prisma.GameProjectWhereUniqueInput[] + connect?: Prisma.GameProjectWhereUniqueInput | Prisma.GameProjectWhereUniqueInput[] + update?: Prisma.GameProjectUpdateWithWhereUniqueWithoutOwnerInput | Prisma.GameProjectUpdateWithWhereUniqueWithoutOwnerInput[] + updateMany?: Prisma.GameProjectUpdateManyWithWhereWithoutOwnerInput | Prisma.GameProjectUpdateManyWithWhereWithoutOwnerInput[] + deleteMany?: Prisma.GameProjectScalarWhereInput | Prisma.GameProjectScalarWhereInput[] +} + +export type GameProjectUncheckedUpdateManyWithoutOwnerNestedInput = { + create?: Prisma.XOR | Prisma.GameProjectCreateWithoutOwnerInput[] | Prisma.GameProjectUncheckedCreateWithoutOwnerInput[] + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutOwnerInput | Prisma.GameProjectCreateOrConnectWithoutOwnerInput[] + upsert?: Prisma.GameProjectUpsertWithWhereUniqueWithoutOwnerInput | Prisma.GameProjectUpsertWithWhereUniqueWithoutOwnerInput[] + createMany?: Prisma.GameProjectCreateManyOwnerInputEnvelope + set?: Prisma.GameProjectWhereUniqueInput | Prisma.GameProjectWhereUniqueInput[] + disconnect?: Prisma.GameProjectWhereUniqueInput | Prisma.GameProjectWhereUniqueInput[] + delete?: Prisma.GameProjectWhereUniqueInput | Prisma.GameProjectWhereUniqueInput[] + connect?: Prisma.GameProjectWhereUniqueInput | Prisma.GameProjectWhereUniqueInput[] + update?: Prisma.GameProjectUpdateWithWhereUniqueWithoutOwnerInput | Prisma.GameProjectUpdateWithWhereUniqueWithoutOwnerInput[] + updateMany?: Prisma.GameProjectUpdateManyWithWhereWithoutOwnerInput | Prisma.GameProjectUpdateManyWithWhereWithoutOwnerInput[] + deleteMany?: Prisma.GameProjectScalarWhereInput | Prisma.GameProjectScalarWhereInput[] +} + +export type EnumProjectStatusFieldUpdateOperationsInput = { + set?: $Enums.ProjectStatus +} + +export type GameProjectCreateNestedOneWithoutVersionsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutVersionsInput + connect?: Prisma.GameProjectWhereUniqueInput +} + +export type GameProjectUpdateOneRequiredWithoutVersionsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutVersionsInput + upsert?: Prisma.GameProjectUpsertWithoutVersionsInput + connect?: Prisma.GameProjectWhereUniqueInput + update?: Prisma.XOR, Prisma.GameProjectUncheckedUpdateWithoutVersionsInput> +} + +export type GameProjectCreateNestedOneWithoutAssetsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutAssetsInput + connect?: Prisma.GameProjectWhereUniqueInput +} + +export type GameProjectUpdateOneRequiredWithoutAssetsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutAssetsInput + upsert?: Prisma.GameProjectUpsertWithoutAssetsInput + connect?: Prisma.GameProjectWhereUniqueInput + update?: Prisma.XOR, Prisma.GameProjectUncheckedUpdateWithoutAssetsInput> +} + +export type GameProjectCreateNestedOneWithoutJobsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutJobsInput + connect?: Prisma.GameProjectWhereUniqueInput +} + +export type GameProjectCreateNestedOneWithoutProjectTargetJobsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutProjectTargetJobsInput + connect?: Prisma.GameProjectWhereUniqueInput +} + +export type GameProjectUpdateOneRequiredWithoutJobsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutJobsInput + upsert?: Prisma.GameProjectUpsertWithoutJobsInput + connect?: Prisma.GameProjectWhereUniqueInput + update?: Prisma.XOR, Prisma.GameProjectUncheckedUpdateWithoutJobsInput> +} + +export type GameProjectUpdateOneWithoutProjectTargetJobsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutProjectTargetJobsInput + upsert?: Prisma.GameProjectUpsertWithoutProjectTargetJobsInput + disconnect?: Prisma.GameProjectWhereInput | boolean + delete?: Prisma.GameProjectWhereInput | boolean + connect?: Prisma.GameProjectWhereUniqueInput + update?: Prisma.XOR, Prisma.GameProjectUncheckedUpdateWithoutProjectTargetJobsInput> +} + +export type GameProjectCreateNestedOneWithoutMainCreationAgentSessionScopesInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutMainCreationAgentSessionScopesInput + connect?: Prisma.GameProjectWhereUniqueInput +} + +export type GameProjectUpdateOneRequiredWithoutMainCreationAgentSessionScopesNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameProjectCreateOrConnectWithoutMainCreationAgentSessionScopesInput + upsert?: Prisma.GameProjectUpsertWithoutMainCreationAgentSessionScopesInput + connect?: Prisma.GameProjectWhereUniqueInput + update?: Prisma.XOR, Prisma.GameProjectUncheckedUpdateWithoutMainCreationAgentSessionScopesInput> +} + +export type GameProjectCreateWithoutOwnerInput = { + id: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + versions?: Prisma.GameVersionCreateNestedManyWithoutProjectInput + assets?: Prisma.AssetCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobCreateNestedManyWithoutGameProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutProjectInput +} + +export type GameProjectUncheckedCreateWithoutOwnerInput = { + id: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + versions?: Prisma.GameVersionUncheckedCreateNestedManyWithoutProjectInput + assets?: Prisma.AssetUncheckedCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutProjectInput +} + +export type GameProjectCreateOrConnectWithoutOwnerInput = { + where: Prisma.GameProjectWhereUniqueInput + create: Prisma.XOR +} + +export type GameProjectCreateManyOwnerInputEnvelope = { + data: Prisma.GameProjectCreateManyOwnerInput | Prisma.GameProjectCreateManyOwnerInput[] + skipDuplicates?: boolean +} + +export type GameProjectUpsertWithWhereUniqueWithoutOwnerInput = { + where: Prisma.GameProjectWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type GameProjectUpdateWithWhereUniqueWithoutOwnerInput = { + where: Prisma.GameProjectWhereUniqueInput + data: Prisma.XOR +} + +export type GameProjectUpdateManyWithWhereWithoutOwnerInput = { + where: Prisma.GameProjectScalarWhereInput + data: Prisma.XOR +} + +export type GameProjectScalarWhereInput = { + AND?: Prisma.GameProjectScalarWhereInput | Prisma.GameProjectScalarWhereInput[] + OR?: Prisma.GameProjectScalarWhereInput[] + NOT?: Prisma.GameProjectScalarWhereInput | Prisma.GameProjectScalarWhereInput[] + id?: Prisma.StringFilter<"GameProject"> | string + ownerId?: Prisma.StringFilter<"GameProject"> | string + slug?: Prisma.StringFilter<"GameProject"> | string + title?: Prisma.StringFilter<"GameProject"> | string + status?: Prisma.EnumProjectStatusFilter<"GameProject"> | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFilter<"GameProject"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"GameProject"> | Date | string +} + +export type GameProjectCreateWithoutVersionsInput = { + id: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + owner: Prisma.UserCreateNestedOneWithoutGameProjectsInput + assets?: Prisma.AssetCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobCreateNestedManyWithoutGameProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutProjectInput +} + +export type GameProjectUncheckedCreateWithoutVersionsInput = { + id: string + ownerId: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + assets?: Prisma.AssetUncheckedCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutProjectInput +} + +export type GameProjectCreateOrConnectWithoutVersionsInput = { + where: Prisma.GameProjectWhereUniqueInput + create: Prisma.XOR +} + +export type GameProjectUpsertWithoutVersionsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.GameProjectWhereInput +} + +export type GameProjectUpdateToOneWithWhereWithoutVersionsInput = { + where?: Prisma.GameProjectWhereInput + data: Prisma.XOR +} + +export type GameProjectUpdateWithoutVersionsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + owner?: Prisma.UserUpdateOneRequiredWithoutGameProjectsNestedInput + assets?: Prisma.AssetUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUpdateManyWithoutGameProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutProjectNestedInput +} + +export type GameProjectUncheckedUpdateWithoutVersionsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + ownerId?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + assets?: Prisma.AssetUncheckedUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutProjectNestedInput +} + +export type GameProjectCreateWithoutAssetsInput = { + id: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + owner: Prisma.UserCreateNestedOneWithoutGameProjectsInput + versions?: Prisma.GameVersionCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobCreateNestedManyWithoutGameProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutProjectInput +} + +export type GameProjectUncheckedCreateWithoutAssetsInput = { + id: string + ownerId: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + versions?: Prisma.GameVersionUncheckedCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutProjectInput +} + +export type GameProjectCreateOrConnectWithoutAssetsInput = { + where: Prisma.GameProjectWhereUniqueInput + create: Prisma.XOR +} + +export type GameProjectUpsertWithoutAssetsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.GameProjectWhereInput +} + +export type GameProjectUpdateToOneWithWhereWithoutAssetsInput = { + where?: Prisma.GameProjectWhereInput + data: Prisma.XOR +} + +export type GameProjectUpdateWithoutAssetsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + owner?: Prisma.UserUpdateOneRequiredWithoutGameProjectsNestedInput + versions?: Prisma.GameVersionUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUpdateManyWithoutGameProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutProjectNestedInput +} + +export type GameProjectUncheckedUpdateWithoutAssetsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + ownerId?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versions?: Prisma.GameVersionUncheckedUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutProjectNestedInput +} + +export type GameProjectCreateWithoutJobsInput = { + id: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + owner: Prisma.UserCreateNestedOneWithoutGameProjectsInput + versions?: Prisma.GameVersionCreateNestedManyWithoutProjectInput + assets?: Prisma.AssetCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobCreateNestedManyWithoutGameProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutProjectInput +} + +export type GameProjectUncheckedCreateWithoutJobsInput = { + id: string + ownerId: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + versions?: Prisma.GameVersionUncheckedCreateNestedManyWithoutProjectInput + assets?: Prisma.AssetUncheckedCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutProjectInput +} + +export type GameProjectCreateOrConnectWithoutJobsInput = { + where: Prisma.GameProjectWhereUniqueInput + create: Prisma.XOR +} + +export type GameProjectCreateWithoutProjectTargetJobsInput = { + id: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + owner: Prisma.UserCreateNestedOneWithoutGameProjectsInput + versions?: Prisma.GameVersionCreateNestedManyWithoutProjectInput + assets?: Prisma.AssetCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobCreateNestedManyWithoutProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutProjectInput +} + +export type GameProjectUncheckedCreateWithoutProjectTargetJobsInput = { + id: string + ownerId: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + versions?: Prisma.GameVersionUncheckedCreateNestedManyWithoutProjectInput + assets?: Prisma.AssetUncheckedCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutProjectInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutProjectInput +} + +export type GameProjectCreateOrConnectWithoutProjectTargetJobsInput = { + where: Prisma.GameProjectWhereUniqueInput + create: Prisma.XOR +} + +export type GameProjectUpsertWithoutJobsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.GameProjectWhereInput +} + +export type GameProjectUpdateToOneWithWhereWithoutJobsInput = { + where?: Prisma.GameProjectWhereInput + data: Prisma.XOR +} + +export type GameProjectUpdateWithoutJobsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + owner?: Prisma.UserUpdateOneRequiredWithoutGameProjectsNestedInput + versions?: Prisma.GameVersionUpdateManyWithoutProjectNestedInput + assets?: Prisma.AssetUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUpdateManyWithoutGameProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutProjectNestedInput +} + +export type GameProjectUncheckedUpdateWithoutJobsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + ownerId?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versions?: Prisma.GameVersionUncheckedUpdateManyWithoutProjectNestedInput + assets?: Prisma.AssetUncheckedUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutProjectNestedInput +} + +export type GameProjectUpsertWithoutProjectTargetJobsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.GameProjectWhereInput +} + +export type GameProjectUpdateToOneWithWhereWithoutProjectTargetJobsInput = { + where?: Prisma.GameProjectWhereInput + data: Prisma.XOR +} + +export type GameProjectUpdateWithoutProjectTargetJobsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + owner?: Prisma.UserUpdateOneRequiredWithoutGameProjectsNestedInput + versions?: Prisma.GameVersionUpdateManyWithoutProjectNestedInput + assets?: Prisma.AssetUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUpdateManyWithoutProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutProjectNestedInput +} + +export type GameProjectUncheckedUpdateWithoutProjectTargetJobsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + ownerId?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versions?: Prisma.GameVersionUncheckedUpdateManyWithoutProjectNestedInput + assets?: Prisma.AssetUncheckedUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutProjectNestedInput +} + +export type GameProjectCreateWithoutMainCreationAgentSessionScopesInput = { + id: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + owner: Prisma.UserCreateNestedOneWithoutGameProjectsInput + versions?: Prisma.GameVersionCreateNestedManyWithoutProjectInput + assets?: Prisma.AssetCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobCreateNestedManyWithoutGameProjectInput +} + +export type GameProjectUncheckedCreateWithoutMainCreationAgentSessionScopesInput = { + id: string + ownerId: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string + versions?: Prisma.GameVersionUncheckedCreateNestedManyWithoutProjectInput + assets?: Prisma.AssetUncheckedCreateNestedManyWithoutProjectInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutProjectInput + projectTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameProjectInput +} + +export type GameProjectCreateOrConnectWithoutMainCreationAgentSessionScopesInput = { + where: Prisma.GameProjectWhereUniqueInput + create: Prisma.XOR +} + +export type GameProjectUpsertWithoutMainCreationAgentSessionScopesInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.GameProjectWhereInput +} + +export type GameProjectUpdateToOneWithWhereWithoutMainCreationAgentSessionScopesInput = { + where?: Prisma.GameProjectWhereInput + data: Prisma.XOR +} + +export type GameProjectUpdateWithoutMainCreationAgentSessionScopesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + owner?: Prisma.UserUpdateOneRequiredWithoutGameProjectsNestedInput + versions?: Prisma.GameVersionUpdateManyWithoutProjectNestedInput + assets?: Prisma.AssetUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUpdateManyWithoutGameProjectNestedInput +} + +export type GameProjectUncheckedUpdateWithoutMainCreationAgentSessionScopesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + ownerId?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versions?: Prisma.GameVersionUncheckedUpdateManyWithoutProjectNestedInput + assets?: Prisma.AssetUncheckedUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameProjectNestedInput +} + +export type GameProjectCreateManyOwnerInput = { + id: string + slug: string + title: string + status?: $Enums.ProjectStatus + createdAt?: Date | string + updatedAt?: Date | string +} + +export type GameProjectUpdateWithoutOwnerInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versions?: Prisma.GameVersionUpdateManyWithoutProjectNestedInput + assets?: Prisma.AssetUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUpdateManyWithoutGameProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutProjectNestedInput +} + +export type GameProjectUncheckedUpdateWithoutOwnerInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versions?: Prisma.GameVersionUncheckedUpdateManyWithoutProjectNestedInput + assets?: Prisma.AssetUncheckedUpdateManyWithoutProjectNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutProjectNestedInput + projectTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameProjectNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutProjectNestedInput +} + +export type GameProjectUncheckedUpdateManyWithoutOwnerInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + slug?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumProjectStatusFieldUpdateOperationsInput | $Enums.ProjectStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + +/** + * Count Type GameProjectCountOutputType + */ + +export type GameProjectCountOutputType = { + versions: number + assets: number + jobs: number + projectTargetJobs: number + mainCreationAgentSessionScopes: number +} + +export type GameProjectCountOutputTypeSelect = { + versions?: boolean | GameProjectCountOutputTypeCountVersionsArgs + assets?: boolean | GameProjectCountOutputTypeCountAssetsArgs + jobs?: boolean | GameProjectCountOutputTypeCountJobsArgs + projectTargetJobs?: boolean | GameProjectCountOutputTypeCountProjectTargetJobsArgs + mainCreationAgentSessionScopes?: boolean | GameProjectCountOutputTypeCountMainCreationAgentSessionScopesArgs +} + +/** + * GameProjectCountOutputType without action + */ +export type GameProjectCountOutputTypeDefaultArgs = { + /** + * Select specific fields to fetch from the GameProjectCountOutputType + */ + select?: Prisma.GameProjectCountOutputTypeSelect | null +} + +/** + * GameProjectCountOutputType without action + */ +export type GameProjectCountOutputTypeCountVersionsArgs = { + where?: Prisma.GameVersionWhereInput +} + +/** + * GameProjectCountOutputType without action + */ +export type GameProjectCountOutputTypeCountAssetsArgs = { + where?: Prisma.AssetWhereInput +} + +/** + * GameProjectCountOutputType without action + */ +export type GameProjectCountOutputTypeCountJobsArgs = { + where?: Prisma.JobWhereInput +} + +/** + * GameProjectCountOutputType without action + */ +export type GameProjectCountOutputTypeCountProjectTargetJobsArgs = { + where?: Prisma.JobWhereInput +} + +/** + * GameProjectCountOutputType without action + */ +export type GameProjectCountOutputTypeCountMainCreationAgentSessionScopesArgs = { + where?: Prisma.MainCreationAgentSessionWhereInput +} + + +export type GameProjectSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + ownerId?: boolean + slug?: boolean + title?: boolean + status?: boolean + createdAt?: boolean + updatedAt?: boolean + owner?: boolean | Prisma.UserDefaultArgs + versions?: boolean | Prisma.GameProject$versionsArgs + assets?: boolean | Prisma.GameProject$assetsArgs + jobs?: boolean | Prisma.GameProject$jobsArgs + projectTargetJobs?: boolean | Prisma.GameProject$projectTargetJobsArgs + mainCreationAgentSessionScopes?: boolean | Prisma.GameProject$mainCreationAgentSessionScopesArgs + _count?: boolean | Prisma.GameProjectCountOutputTypeDefaultArgs +}, ExtArgs["result"]["gameProject"]> + +export type GameProjectSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + ownerId?: boolean + slug?: boolean + title?: boolean + status?: boolean + createdAt?: boolean + updatedAt?: boolean + owner?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["gameProject"]> + +export type GameProjectSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + ownerId?: boolean + slug?: boolean + title?: boolean + status?: boolean + createdAt?: boolean + updatedAt?: boolean + owner?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["gameProject"]> + +export type GameProjectSelectScalar = { + id?: boolean + ownerId?: boolean + slug?: boolean + title?: boolean + status?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type GameProjectOmit = runtime.Types.Extensions.GetOmit<"id" | "ownerId" | "slug" | "title" | "status" | "createdAt" | "updatedAt", ExtArgs["result"]["gameProject"]> +export type GameProjectInclude = { + owner?: boolean | Prisma.UserDefaultArgs + versions?: boolean | Prisma.GameProject$versionsArgs + assets?: boolean | Prisma.GameProject$assetsArgs + jobs?: boolean | Prisma.GameProject$jobsArgs + projectTargetJobs?: boolean | Prisma.GameProject$projectTargetJobsArgs + mainCreationAgentSessionScopes?: boolean | Prisma.GameProject$mainCreationAgentSessionScopesArgs + _count?: boolean | Prisma.GameProjectCountOutputTypeDefaultArgs +} +export type GameProjectIncludeCreateManyAndReturn = { + owner?: boolean | Prisma.UserDefaultArgs +} +export type GameProjectIncludeUpdateManyAndReturn = { + owner?: boolean | Prisma.UserDefaultArgs +} + +export type $GameProjectPayload = { + name: "GameProject" + objects: { + owner: Prisma.$UserPayload + versions: Prisma.$GameVersionPayload[] + assets: Prisma.$AssetPayload[] + jobs: Prisma.$JobPayload[] + projectTargetJobs: Prisma.$JobPayload[] + mainCreationAgentSessionScopes: Prisma.$MainCreationAgentSessionPayload[] + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + ownerId: string + slug: string + title: string + status: $Enums.ProjectStatus + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["gameProject"]> + composites: {} +} + +export type GameProjectGetPayload = runtime.Types.Result.GetResult + +export type GameProjectCountArgs = + Omit & { + select?: GameProjectCountAggregateInputType | true + } + +export interface GameProjectDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['GameProject'], meta: { name: 'GameProject' } } + /** + * Find zero or one GameProject that matches the filter. + * @param {GameProjectFindUniqueArgs} args - Arguments to find a GameProject + * @example + * // Get one GameProject + * const gameProject = await prisma.gameProject.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__GameProjectClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one GameProject that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {GameProjectFindUniqueOrThrowArgs} args - Arguments to find a GameProject + * @example + * // Get one GameProject + * const gameProject = await prisma.gameProject.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__GameProjectClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first GameProject that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameProjectFindFirstArgs} args - Arguments to find a GameProject + * @example + * // Get one GameProject + * const gameProject = await prisma.gameProject.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__GameProjectClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first GameProject that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameProjectFindFirstOrThrowArgs} args - Arguments to find a GameProject + * @example + * // Get one GameProject + * const gameProject = await prisma.gameProject.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__GameProjectClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more GameProjects that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameProjectFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all GameProjects + * const gameProjects = await prisma.gameProject.findMany() + * + * // Get first 10 GameProjects + * const gameProjects = await prisma.gameProject.findMany({ take: 10 }) + * + * // Only select the `id` + * const gameProjectWithIdOnly = await prisma.gameProject.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a GameProject. + * @param {GameProjectCreateArgs} args - Arguments to create a GameProject. + * @example + * // Create one GameProject + * const GameProject = await prisma.gameProject.create({ + * data: { + * // ... data to create a GameProject + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__GameProjectClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many GameProjects. + * @param {GameProjectCreateManyArgs} args - Arguments to create many GameProjects. + * @example + * // Create many GameProjects + * const gameProject = await prisma.gameProject.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many GameProjects and returns the data saved in the database. + * @param {GameProjectCreateManyAndReturnArgs} args - Arguments to create many GameProjects. + * @example + * // Create many GameProjects + * const gameProject = await prisma.gameProject.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many GameProjects and only return the `id` + * const gameProjectWithIdOnly = await prisma.gameProject.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a GameProject. + * @param {GameProjectDeleteArgs} args - Arguments to delete one GameProject. + * @example + * // Delete one GameProject + * const GameProject = await prisma.gameProject.delete({ + * where: { + * // ... filter to delete one GameProject + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__GameProjectClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one GameProject. + * @param {GameProjectUpdateArgs} args - Arguments to update one GameProject. + * @example + * // Update one GameProject + * const gameProject = await prisma.gameProject.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__GameProjectClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more GameProjects. + * @param {GameProjectDeleteManyArgs} args - Arguments to filter GameProjects to delete. + * @example + * // Delete a few GameProjects + * const { count } = await prisma.gameProject.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more GameProjects. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameProjectUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many GameProjects + * const gameProject = await prisma.gameProject.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more GameProjects and returns the data updated in the database. + * @param {GameProjectUpdateManyAndReturnArgs} args - Arguments to update many GameProjects. + * @example + * // Update many GameProjects + * const gameProject = await prisma.gameProject.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more GameProjects and only return the `id` + * const gameProjectWithIdOnly = await prisma.gameProject.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one GameProject. + * @param {GameProjectUpsertArgs} args - Arguments to update or create a GameProject. + * @example + * // Update or create a GameProject + * const gameProject = await prisma.gameProject.upsert({ + * create: { + * // ... data to create a GameProject + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the GameProject we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__GameProjectClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of GameProjects. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameProjectCountArgs} args - Arguments to filter GameProjects to count. + * @example + * // Count the number of GameProjects + * const count = await prisma.gameProject.count({ + * where: { + * // ... the filter for the GameProjects we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a GameProject. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameProjectAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by GameProject. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameProjectGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends GameProjectGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: GameProjectGroupByArgs['orderBy'] } + : { orderBy?: GameProjectGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetGameProjectGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the GameProject model + */ +readonly fields: GameProjectFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for GameProject. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__GameProjectClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + owner = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + versions = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + assets = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + jobs = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + projectTargetJobs = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + mainCreationAgentSessionScopes = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the GameProject model + */ +export interface GameProjectFieldRefs { + readonly id: Prisma.FieldRef<"GameProject", 'String'> + readonly ownerId: Prisma.FieldRef<"GameProject", 'String'> + readonly slug: Prisma.FieldRef<"GameProject", 'String'> + readonly title: Prisma.FieldRef<"GameProject", 'String'> + readonly status: Prisma.FieldRef<"GameProject", 'ProjectStatus'> + readonly createdAt: Prisma.FieldRef<"GameProject", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"GameProject", 'DateTime'> +} + + +// Custom InputTypes +/** + * GameProject findUnique + */ +export type GameProjectFindUniqueArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + /** + * Filter, which GameProject to fetch. + */ + where: Prisma.GameProjectWhereUniqueInput +} + +/** + * GameProject findUniqueOrThrow + */ +export type GameProjectFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + /** + * Filter, which GameProject to fetch. + */ + where: Prisma.GameProjectWhereUniqueInput +} + +/** + * GameProject findFirst + */ +export type GameProjectFindFirstArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + /** + * Filter, which GameProject to fetch. + */ + where?: Prisma.GameProjectWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of GameProjects to fetch. + */ + orderBy?: Prisma.GameProjectOrderByWithRelationInput | Prisma.GameProjectOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for GameProjects. + */ + cursor?: Prisma.GameProjectWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` GameProjects from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` GameProjects. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of GameProjects. + */ + distinct?: Prisma.GameProjectScalarFieldEnum | Prisma.GameProjectScalarFieldEnum[] +} + +/** + * GameProject findFirstOrThrow + */ +export type GameProjectFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + /** + * Filter, which GameProject to fetch. + */ + where?: Prisma.GameProjectWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of GameProjects to fetch. + */ + orderBy?: Prisma.GameProjectOrderByWithRelationInput | Prisma.GameProjectOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for GameProjects. + */ + cursor?: Prisma.GameProjectWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` GameProjects from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` GameProjects. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of GameProjects. + */ + distinct?: Prisma.GameProjectScalarFieldEnum | Prisma.GameProjectScalarFieldEnum[] +} + +/** + * GameProject findMany + */ +export type GameProjectFindManyArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + /** + * Filter, which GameProjects to fetch. + */ + where?: Prisma.GameProjectWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of GameProjects to fetch. + */ + orderBy?: Prisma.GameProjectOrderByWithRelationInput | Prisma.GameProjectOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing GameProjects. + */ + cursor?: Prisma.GameProjectWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` GameProjects from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` GameProjects. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of GameProjects. + */ + distinct?: Prisma.GameProjectScalarFieldEnum | Prisma.GameProjectScalarFieldEnum[] +} + +/** + * GameProject create + */ +export type GameProjectCreateArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + /** + * The data needed to create a GameProject. + */ + data: Prisma.XOR +} + +/** + * GameProject createMany + */ +export type GameProjectCreateManyArgs = { + /** + * The data used to create many GameProjects. + */ + data: Prisma.GameProjectCreateManyInput | Prisma.GameProjectCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * GameProject createManyAndReturn + */ +export type GameProjectCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelectCreateManyAndReturn | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * The data used to create many GameProjects. + */ + data: Prisma.GameProjectCreateManyInput | Prisma.GameProjectCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectIncludeCreateManyAndReturn | null +} + +/** + * GameProject update + */ +export type GameProjectUpdateArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + /** + * The data needed to update a GameProject. + */ + data: Prisma.XOR + /** + * Choose, which GameProject to update. + */ + where: Prisma.GameProjectWhereUniqueInput +} + +/** + * GameProject updateMany + */ +export type GameProjectUpdateManyArgs = { + /** + * The data used to update GameProjects. + */ + data: Prisma.XOR + /** + * Filter which GameProjects to update + */ + where?: Prisma.GameProjectWhereInput + /** + * Limit how many GameProjects to update. + */ + limit?: number +} + +/** + * GameProject updateManyAndReturn + */ +export type GameProjectUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * The data used to update GameProjects. + */ + data: Prisma.XOR + /** + * Filter which GameProjects to update + */ + where?: Prisma.GameProjectWhereInput + /** + * Limit how many GameProjects to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectIncludeUpdateManyAndReturn | null +} + +/** + * GameProject upsert + */ +export type GameProjectUpsertArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + /** + * The filter to search for the GameProject to update in case it exists. + */ + where: Prisma.GameProjectWhereUniqueInput + /** + * In case the GameProject found by the `where` argument doesn't exist, create a new GameProject with this data. + */ + create: Prisma.XOR + /** + * In case the GameProject was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * GameProject delete + */ +export type GameProjectDeleteArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + /** + * Filter which GameProject to delete. + */ + where: Prisma.GameProjectWhereUniqueInput +} + +/** + * GameProject deleteMany + */ +export type GameProjectDeleteManyArgs = { + /** + * Filter which GameProjects to delete + */ + where?: Prisma.GameProjectWhereInput + /** + * Limit how many GameProjects to delete. + */ + limit?: number +} + +/** + * GameProject.versions + */ +export type GameProject$versionsArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + where?: Prisma.GameVersionWhereInput + orderBy?: Prisma.GameVersionOrderByWithRelationInput | Prisma.GameVersionOrderByWithRelationInput[] + cursor?: Prisma.GameVersionWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.GameVersionScalarFieldEnum | Prisma.GameVersionScalarFieldEnum[] +} + +/** + * GameProject.assets + */ +export type GameProject$assetsArgs = { + /** + * Select specific fields to fetch from the Asset + */ + select?: Prisma.AssetSelect | null + /** + * Omit specific fields from the Asset + */ + omit?: Prisma.AssetOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AssetInclude | null + where?: Prisma.AssetWhereInput + orderBy?: Prisma.AssetOrderByWithRelationInput | Prisma.AssetOrderByWithRelationInput[] + cursor?: Prisma.AssetWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.AssetScalarFieldEnum | Prisma.AssetScalarFieldEnum[] +} + +/** + * GameProject.jobs + */ +export type GameProject$jobsArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + where?: Prisma.JobWhereInput + orderBy?: Prisma.JobOrderByWithRelationInput | Prisma.JobOrderByWithRelationInput[] + cursor?: Prisma.JobWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.JobScalarFieldEnum | Prisma.JobScalarFieldEnum[] +} + +/** + * GameProject.projectTargetJobs + */ +export type GameProject$projectTargetJobsArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + where?: Prisma.JobWhereInput + orderBy?: Prisma.JobOrderByWithRelationInput | Prisma.JobOrderByWithRelationInput[] + cursor?: Prisma.JobWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.JobScalarFieldEnum | Prisma.JobScalarFieldEnum[] +} + +/** + * GameProject.mainCreationAgentSessionScopes + */ +export type GameProject$mainCreationAgentSessionScopesArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + where?: Prisma.MainCreationAgentSessionWhereInput + orderBy?: Prisma.MainCreationAgentSessionOrderByWithRelationInput | Prisma.MainCreationAgentSessionOrderByWithRelationInput[] + cursor?: Prisma.MainCreationAgentSessionWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.MainCreationAgentSessionScalarFieldEnum | Prisma.MainCreationAgentSessionScalarFieldEnum[] +} + +/** + * GameProject without action + */ +export type GameProjectDefaultArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null +} diff --git a/apps/api/src/generated/prisma/models/GameVersion.ts b/apps/api/src/generated/prisma/models/GameVersion.ts new file mode 100644 index 00000000..f1815ec1 --- /dev/null +++ b/apps/api/src/generated/prisma/models/GameVersion.ts @@ -0,0 +1,2033 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `GameVersion` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model GameVersion + * + */ +export type GameVersionModel = runtime.Types.Result.DefaultSelection + +export type AggregateGameVersion = { + _count: GameVersionCountAggregateOutputType | null + _avg: GameVersionAvgAggregateOutputType | null + _sum: GameVersionSumAggregateOutputType | null + _min: GameVersionMinAggregateOutputType | null + _max: GameVersionMaxAggregateOutputType | null +} + +export type GameVersionAvgAggregateOutputType = { + versionNumber: number | null +} + +export type GameVersionSumAggregateOutputType = { + versionNumber: number | null +} + +export type GameVersionMinAggregateOutputType = { + id: string | null + projectId: string | null + versionNumber: number | null + status: $Enums.GameVersionStatus | null + createdAt: Date | null + updatedAt: Date | null +} + +export type GameVersionMaxAggregateOutputType = { + id: string | null + projectId: string | null + versionNumber: number | null + status: $Enums.GameVersionStatus | null + createdAt: Date | null + updatedAt: Date | null +} + +export type GameVersionCountAggregateOutputType = { + id: number + projectId: number + versionNumber: number + status: number + configJson: number + createdAt: number + updatedAt: number + _all: number +} + + +export type GameVersionAvgAggregateInputType = { + versionNumber?: true +} + +export type GameVersionSumAggregateInputType = { + versionNumber?: true +} + +export type GameVersionMinAggregateInputType = { + id?: true + projectId?: true + versionNumber?: true + status?: true + createdAt?: true + updatedAt?: true +} + +export type GameVersionMaxAggregateInputType = { + id?: true + projectId?: true + versionNumber?: true + status?: true + createdAt?: true + updatedAt?: true +} + +export type GameVersionCountAggregateInputType = { + id?: true + projectId?: true + versionNumber?: true + status?: true + configJson?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type GameVersionAggregateArgs = { + /** + * Filter which GameVersion to aggregate. + */ + where?: Prisma.GameVersionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of GameVersions to fetch. + */ + orderBy?: Prisma.GameVersionOrderByWithRelationInput | Prisma.GameVersionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.GameVersionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` GameVersions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` GameVersions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned GameVersions + **/ + _count?: true | GameVersionCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: GameVersionAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: GameVersionSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: GameVersionMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: GameVersionMaxAggregateInputType +} + +export type GetGameVersionAggregateType = { + [P in keyof T & keyof AggregateGameVersion]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type GameVersionGroupByArgs = { + where?: Prisma.GameVersionWhereInput + orderBy?: Prisma.GameVersionOrderByWithAggregationInput | Prisma.GameVersionOrderByWithAggregationInput[] + by: Prisma.GameVersionScalarFieldEnum[] | Prisma.GameVersionScalarFieldEnum + having?: Prisma.GameVersionScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: GameVersionCountAggregateInputType | true + _avg?: GameVersionAvgAggregateInputType + _sum?: GameVersionSumAggregateInputType + _min?: GameVersionMinAggregateInputType + _max?: GameVersionMaxAggregateInputType +} + +export type GameVersionGroupByOutputType = { + id: string + projectId: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: runtime.JsonValue + createdAt: Date + updatedAt: Date + _count: GameVersionCountAggregateOutputType | null + _avg: GameVersionAvgAggregateOutputType | null + _sum: GameVersionSumAggregateOutputType | null + _min: GameVersionMinAggregateOutputType | null + _max: GameVersionMaxAggregateOutputType | null +} + +export type GetGameVersionGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof GameVersionGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type GameVersionWhereInput = { + AND?: Prisma.GameVersionWhereInput | Prisma.GameVersionWhereInput[] + OR?: Prisma.GameVersionWhereInput[] + NOT?: Prisma.GameVersionWhereInput | Prisma.GameVersionWhereInput[] + id?: Prisma.StringFilter<"GameVersion"> | string + projectId?: Prisma.StringFilter<"GameVersion"> | string + versionNumber?: Prisma.IntFilter<"GameVersion"> | number + status?: Prisma.EnumGameVersionStatusFilter<"GameVersion"> | $Enums.GameVersionStatus + configJson?: Prisma.JsonFilter<"GameVersion"> + createdAt?: Prisma.DateTimeFilter<"GameVersion"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"GameVersion"> | Date | string + project?: Prisma.XOR + versionTargetJobs?: Prisma.JobListRelationFilter + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionListRelationFilter + reviewRecords?: Prisma.ReviewRecordListRelationFilter + lifecycleEvents?: Prisma.LifecycleEventListRelationFilter +} + +export type GameVersionOrderByWithRelationInput = { + id?: Prisma.SortOrder + projectId?: Prisma.SortOrder + versionNumber?: Prisma.SortOrder + status?: Prisma.SortOrder + configJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + project?: Prisma.GameProjectOrderByWithRelationInput + versionTargetJobs?: Prisma.JobOrderByRelationAggregateInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionOrderByRelationAggregateInput + reviewRecords?: Prisma.ReviewRecordOrderByRelationAggregateInput + lifecycleEvents?: Prisma.LifecycleEventOrderByRelationAggregateInput +} + +export type GameVersionWhereUniqueInput = Prisma.AtLeast<{ + id?: string + projectId_versionNumber?: Prisma.GameVersionProjectIdVersionNumberCompoundUniqueInput + id_projectId?: Prisma.GameVersionIdProjectIdCompoundUniqueInput + AND?: Prisma.GameVersionWhereInput | Prisma.GameVersionWhereInput[] + OR?: Prisma.GameVersionWhereInput[] + NOT?: Prisma.GameVersionWhereInput | Prisma.GameVersionWhereInput[] + projectId?: Prisma.StringFilter<"GameVersion"> | string + versionNumber?: Prisma.IntFilter<"GameVersion"> | number + status?: Prisma.EnumGameVersionStatusFilter<"GameVersion"> | $Enums.GameVersionStatus + configJson?: Prisma.JsonFilter<"GameVersion"> + createdAt?: Prisma.DateTimeFilter<"GameVersion"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"GameVersion"> | Date | string + project?: Prisma.XOR + versionTargetJobs?: Prisma.JobListRelationFilter + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionListRelationFilter + reviewRecords?: Prisma.ReviewRecordListRelationFilter + lifecycleEvents?: Prisma.LifecycleEventListRelationFilter +}, "id" | "projectId_versionNumber" | "id_projectId"> + +export type GameVersionOrderByWithAggregationInput = { + id?: Prisma.SortOrder + projectId?: Prisma.SortOrder + versionNumber?: Prisma.SortOrder + status?: Prisma.SortOrder + configJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.GameVersionCountOrderByAggregateInput + _avg?: Prisma.GameVersionAvgOrderByAggregateInput + _max?: Prisma.GameVersionMaxOrderByAggregateInput + _min?: Prisma.GameVersionMinOrderByAggregateInput + _sum?: Prisma.GameVersionSumOrderByAggregateInput +} + +export type GameVersionScalarWhereWithAggregatesInput = { + AND?: Prisma.GameVersionScalarWhereWithAggregatesInput | Prisma.GameVersionScalarWhereWithAggregatesInput[] + OR?: Prisma.GameVersionScalarWhereWithAggregatesInput[] + NOT?: Prisma.GameVersionScalarWhereWithAggregatesInput | Prisma.GameVersionScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"GameVersion"> | string + projectId?: Prisma.StringWithAggregatesFilter<"GameVersion"> | string + versionNumber?: Prisma.IntWithAggregatesFilter<"GameVersion"> | number + status?: Prisma.EnumGameVersionStatusWithAggregatesFilter<"GameVersion"> | $Enums.GameVersionStatus + configJson?: Prisma.JsonWithAggregatesFilter<"GameVersion"> + createdAt?: Prisma.DateTimeWithAggregatesFilter<"GameVersion"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"GameVersion"> | Date | string +} + +export type GameVersionCreateInput = { + id: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + project: Prisma.GameProjectCreateNestedOneWithoutVersionsInput + versionTargetJobs?: Prisma.JobCreateNestedManyWithoutGameVersionInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutVersionInput + reviewRecords?: Prisma.ReviewRecordCreateNestedManyWithoutGameVersionInput + lifecycleEvents?: Prisma.LifecycleEventCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionUncheckedCreateInput = { + id: string + projectId: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + versionTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameVersionInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutVersionInput + reviewRecords?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutGameVersionInput + lifecycleEvents?: Prisma.LifecycleEventUncheckedCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + project?: Prisma.GameProjectUpdateOneRequiredWithoutVersionsNestedInput + versionTargetJobs?: Prisma.JobUpdateManyWithoutGameVersionNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutVersionNestedInput + reviewRecords?: Prisma.ReviewRecordUpdateManyWithoutGameVersionNestedInput + lifecycleEvents?: Prisma.LifecycleEventUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versionTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameVersionNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutVersionNestedInput + reviewRecords?: Prisma.ReviewRecordUncheckedUpdateManyWithoutGameVersionNestedInput + lifecycleEvents?: Prisma.LifecycleEventUncheckedUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionCreateManyInput = { + id: string + projectId: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type GameVersionUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type GameVersionUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type GameVersionListRelationFilter = { + every?: Prisma.GameVersionWhereInput + some?: Prisma.GameVersionWhereInput + none?: Prisma.GameVersionWhereInput +} + +export type GameVersionOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type GameVersionProjectIdVersionNumberCompoundUniqueInput = { + projectId: string + versionNumber: number +} + +export type GameVersionIdProjectIdCompoundUniqueInput = { + id: string + projectId: string +} + +export type GameVersionCountOrderByAggregateInput = { + id?: Prisma.SortOrder + projectId?: Prisma.SortOrder + versionNumber?: Prisma.SortOrder + status?: Prisma.SortOrder + configJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type GameVersionAvgOrderByAggregateInput = { + versionNumber?: Prisma.SortOrder +} + +export type GameVersionMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + projectId?: Prisma.SortOrder + versionNumber?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type GameVersionMinOrderByAggregateInput = { + id?: Prisma.SortOrder + projectId?: Prisma.SortOrder + versionNumber?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type GameVersionSumOrderByAggregateInput = { + versionNumber?: Prisma.SortOrder +} + +export type GameVersionNullableScalarRelationFilter = { + is?: Prisma.GameVersionWhereInput | null + isNot?: Prisma.GameVersionWhereInput | null +} + +export type GameVersionScalarRelationFilter = { + is?: Prisma.GameVersionWhereInput + isNot?: Prisma.GameVersionWhereInput +} + +export type GameVersionCreateNestedManyWithoutProjectInput = { + create?: Prisma.XOR | Prisma.GameVersionCreateWithoutProjectInput[] | Prisma.GameVersionUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutProjectInput | Prisma.GameVersionCreateOrConnectWithoutProjectInput[] + createMany?: Prisma.GameVersionCreateManyProjectInputEnvelope + connect?: Prisma.GameVersionWhereUniqueInput | Prisma.GameVersionWhereUniqueInput[] +} + +export type GameVersionUncheckedCreateNestedManyWithoutProjectInput = { + create?: Prisma.XOR | Prisma.GameVersionCreateWithoutProjectInput[] | Prisma.GameVersionUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutProjectInput | Prisma.GameVersionCreateOrConnectWithoutProjectInput[] + createMany?: Prisma.GameVersionCreateManyProjectInputEnvelope + connect?: Prisma.GameVersionWhereUniqueInput | Prisma.GameVersionWhereUniqueInput[] +} + +export type GameVersionUpdateManyWithoutProjectNestedInput = { + create?: Prisma.XOR | Prisma.GameVersionCreateWithoutProjectInput[] | Prisma.GameVersionUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutProjectInput | Prisma.GameVersionCreateOrConnectWithoutProjectInput[] + upsert?: Prisma.GameVersionUpsertWithWhereUniqueWithoutProjectInput | Prisma.GameVersionUpsertWithWhereUniqueWithoutProjectInput[] + createMany?: Prisma.GameVersionCreateManyProjectInputEnvelope + set?: Prisma.GameVersionWhereUniqueInput | Prisma.GameVersionWhereUniqueInput[] + disconnect?: Prisma.GameVersionWhereUniqueInput | Prisma.GameVersionWhereUniqueInput[] + delete?: Prisma.GameVersionWhereUniqueInput | Prisma.GameVersionWhereUniqueInput[] + connect?: Prisma.GameVersionWhereUniqueInput | Prisma.GameVersionWhereUniqueInput[] + update?: Prisma.GameVersionUpdateWithWhereUniqueWithoutProjectInput | Prisma.GameVersionUpdateWithWhereUniqueWithoutProjectInput[] + updateMany?: Prisma.GameVersionUpdateManyWithWhereWithoutProjectInput | Prisma.GameVersionUpdateManyWithWhereWithoutProjectInput[] + deleteMany?: Prisma.GameVersionScalarWhereInput | Prisma.GameVersionScalarWhereInput[] +} + +export type GameVersionUncheckedUpdateManyWithoutProjectNestedInput = { + create?: Prisma.XOR | Prisma.GameVersionCreateWithoutProjectInput[] | Prisma.GameVersionUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutProjectInput | Prisma.GameVersionCreateOrConnectWithoutProjectInput[] + upsert?: Prisma.GameVersionUpsertWithWhereUniqueWithoutProjectInput | Prisma.GameVersionUpsertWithWhereUniqueWithoutProjectInput[] + createMany?: Prisma.GameVersionCreateManyProjectInputEnvelope + set?: Prisma.GameVersionWhereUniqueInput | Prisma.GameVersionWhereUniqueInput[] + disconnect?: Prisma.GameVersionWhereUniqueInput | Prisma.GameVersionWhereUniqueInput[] + delete?: Prisma.GameVersionWhereUniqueInput | Prisma.GameVersionWhereUniqueInput[] + connect?: Prisma.GameVersionWhereUniqueInput | Prisma.GameVersionWhereUniqueInput[] + update?: Prisma.GameVersionUpdateWithWhereUniqueWithoutProjectInput | Prisma.GameVersionUpdateWithWhereUniqueWithoutProjectInput[] + updateMany?: Prisma.GameVersionUpdateManyWithWhereWithoutProjectInput | Prisma.GameVersionUpdateManyWithWhereWithoutProjectInput[] + deleteMany?: Prisma.GameVersionScalarWhereInput | Prisma.GameVersionScalarWhereInput[] +} + +export type IntFieldUpdateOperationsInput = { + set?: number + increment?: number + decrement?: number + multiply?: number + divide?: number +} + +export type EnumGameVersionStatusFieldUpdateOperationsInput = { + set?: $Enums.GameVersionStatus +} + +export type GameVersionCreateNestedOneWithoutVersionTargetJobsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutVersionTargetJobsInput + connect?: Prisma.GameVersionWhereUniqueInput +} + +export type GameVersionUpdateOneWithoutVersionTargetJobsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutVersionTargetJobsInput + upsert?: Prisma.GameVersionUpsertWithoutVersionTargetJobsInput + disconnect?: Prisma.GameVersionWhereInput | boolean + delete?: Prisma.GameVersionWhereInput | boolean + connect?: Prisma.GameVersionWhereUniqueInput + update?: Prisma.XOR, Prisma.GameVersionUncheckedUpdateWithoutVersionTargetJobsInput> +} + +export type GameVersionCreateNestedOneWithoutMainCreationAgentSessionScopesInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutMainCreationAgentSessionScopesInput + connect?: Prisma.GameVersionWhereUniqueInput +} + +export type GameVersionUpdateOneRequiredWithoutMainCreationAgentSessionScopesNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutMainCreationAgentSessionScopesInput + upsert?: Prisma.GameVersionUpsertWithoutMainCreationAgentSessionScopesInput + connect?: Prisma.GameVersionWhereUniqueInput + update?: Prisma.XOR, Prisma.GameVersionUncheckedUpdateWithoutMainCreationAgentSessionScopesInput> +} + +export type GameVersionCreateNestedOneWithoutReviewRecordsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutReviewRecordsInput + connect?: Prisma.GameVersionWhereUniqueInput +} + +export type GameVersionUpdateOneRequiredWithoutReviewRecordsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutReviewRecordsInput + upsert?: Prisma.GameVersionUpsertWithoutReviewRecordsInput + connect?: Prisma.GameVersionWhereUniqueInput + update?: Prisma.XOR, Prisma.GameVersionUncheckedUpdateWithoutReviewRecordsInput> +} + +export type GameVersionCreateNestedOneWithoutLifecycleEventsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutLifecycleEventsInput + connect?: Prisma.GameVersionWhereUniqueInput +} + +export type GameVersionUpdateOneWithoutLifecycleEventsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.GameVersionCreateOrConnectWithoutLifecycleEventsInput + upsert?: Prisma.GameVersionUpsertWithoutLifecycleEventsInput + disconnect?: Prisma.GameVersionWhereInput | boolean + delete?: Prisma.GameVersionWhereInput | boolean + connect?: Prisma.GameVersionWhereUniqueInput + update?: Prisma.XOR, Prisma.GameVersionUncheckedUpdateWithoutLifecycleEventsInput> +} + +export type GameVersionCreateWithoutProjectInput = { + id: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + versionTargetJobs?: Prisma.JobCreateNestedManyWithoutGameVersionInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutVersionInput + reviewRecords?: Prisma.ReviewRecordCreateNestedManyWithoutGameVersionInput + lifecycleEvents?: Prisma.LifecycleEventCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionUncheckedCreateWithoutProjectInput = { + id: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + versionTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameVersionInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutVersionInput + reviewRecords?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutGameVersionInput + lifecycleEvents?: Prisma.LifecycleEventUncheckedCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionCreateOrConnectWithoutProjectInput = { + where: Prisma.GameVersionWhereUniqueInput + create: Prisma.XOR +} + +export type GameVersionCreateManyProjectInputEnvelope = { + data: Prisma.GameVersionCreateManyProjectInput | Prisma.GameVersionCreateManyProjectInput[] + skipDuplicates?: boolean +} + +export type GameVersionUpsertWithWhereUniqueWithoutProjectInput = { + where: Prisma.GameVersionWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type GameVersionUpdateWithWhereUniqueWithoutProjectInput = { + where: Prisma.GameVersionWhereUniqueInput + data: Prisma.XOR +} + +export type GameVersionUpdateManyWithWhereWithoutProjectInput = { + where: Prisma.GameVersionScalarWhereInput + data: Prisma.XOR +} + +export type GameVersionScalarWhereInput = { + AND?: Prisma.GameVersionScalarWhereInput | Prisma.GameVersionScalarWhereInput[] + OR?: Prisma.GameVersionScalarWhereInput[] + NOT?: Prisma.GameVersionScalarWhereInput | Prisma.GameVersionScalarWhereInput[] + id?: Prisma.StringFilter<"GameVersion"> | string + projectId?: Prisma.StringFilter<"GameVersion"> | string + versionNumber?: Prisma.IntFilter<"GameVersion"> | number + status?: Prisma.EnumGameVersionStatusFilter<"GameVersion"> | $Enums.GameVersionStatus + configJson?: Prisma.JsonFilter<"GameVersion"> + createdAt?: Prisma.DateTimeFilter<"GameVersion"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"GameVersion"> | Date | string +} + +export type GameVersionCreateWithoutVersionTargetJobsInput = { + id: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + project: Prisma.GameProjectCreateNestedOneWithoutVersionsInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutVersionInput + reviewRecords?: Prisma.ReviewRecordCreateNestedManyWithoutGameVersionInput + lifecycleEvents?: Prisma.LifecycleEventCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionUncheckedCreateWithoutVersionTargetJobsInput = { + id: string + projectId: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutVersionInput + reviewRecords?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutGameVersionInput + lifecycleEvents?: Prisma.LifecycleEventUncheckedCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionCreateOrConnectWithoutVersionTargetJobsInput = { + where: Prisma.GameVersionWhereUniqueInput + create: Prisma.XOR +} + +export type GameVersionUpsertWithoutVersionTargetJobsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.GameVersionWhereInput +} + +export type GameVersionUpdateToOneWithWhereWithoutVersionTargetJobsInput = { + where?: Prisma.GameVersionWhereInput + data: Prisma.XOR +} + +export type GameVersionUpdateWithoutVersionTargetJobsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + project?: Prisma.GameProjectUpdateOneRequiredWithoutVersionsNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutVersionNestedInput + reviewRecords?: Prisma.ReviewRecordUpdateManyWithoutGameVersionNestedInput + lifecycleEvents?: Prisma.LifecycleEventUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionUncheckedUpdateWithoutVersionTargetJobsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutVersionNestedInput + reviewRecords?: Prisma.ReviewRecordUncheckedUpdateManyWithoutGameVersionNestedInput + lifecycleEvents?: Prisma.LifecycleEventUncheckedUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionCreateWithoutMainCreationAgentSessionScopesInput = { + id: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + project: Prisma.GameProjectCreateNestedOneWithoutVersionsInput + versionTargetJobs?: Prisma.JobCreateNestedManyWithoutGameVersionInput + reviewRecords?: Prisma.ReviewRecordCreateNestedManyWithoutGameVersionInput + lifecycleEvents?: Prisma.LifecycleEventCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionUncheckedCreateWithoutMainCreationAgentSessionScopesInput = { + id: string + projectId: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + versionTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameVersionInput + reviewRecords?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutGameVersionInput + lifecycleEvents?: Prisma.LifecycleEventUncheckedCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionCreateOrConnectWithoutMainCreationAgentSessionScopesInput = { + where: Prisma.GameVersionWhereUniqueInput + create: Prisma.XOR +} + +export type GameVersionUpsertWithoutMainCreationAgentSessionScopesInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.GameVersionWhereInput +} + +export type GameVersionUpdateToOneWithWhereWithoutMainCreationAgentSessionScopesInput = { + where?: Prisma.GameVersionWhereInput + data: Prisma.XOR +} + +export type GameVersionUpdateWithoutMainCreationAgentSessionScopesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + project?: Prisma.GameProjectUpdateOneRequiredWithoutVersionsNestedInput + versionTargetJobs?: Prisma.JobUpdateManyWithoutGameVersionNestedInput + reviewRecords?: Prisma.ReviewRecordUpdateManyWithoutGameVersionNestedInput + lifecycleEvents?: Prisma.LifecycleEventUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionUncheckedUpdateWithoutMainCreationAgentSessionScopesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versionTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameVersionNestedInput + reviewRecords?: Prisma.ReviewRecordUncheckedUpdateManyWithoutGameVersionNestedInput + lifecycleEvents?: Prisma.LifecycleEventUncheckedUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionCreateWithoutReviewRecordsInput = { + id: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + project: Prisma.GameProjectCreateNestedOneWithoutVersionsInput + versionTargetJobs?: Prisma.JobCreateNestedManyWithoutGameVersionInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutVersionInput + lifecycleEvents?: Prisma.LifecycleEventCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionUncheckedCreateWithoutReviewRecordsInput = { + id: string + projectId: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + versionTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameVersionInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutVersionInput + lifecycleEvents?: Prisma.LifecycleEventUncheckedCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionCreateOrConnectWithoutReviewRecordsInput = { + where: Prisma.GameVersionWhereUniqueInput + create: Prisma.XOR +} + +export type GameVersionUpsertWithoutReviewRecordsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.GameVersionWhereInput +} + +export type GameVersionUpdateToOneWithWhereWithoutReviewRecordsInput = { + where?: Prisma.GameVersionWhereInput + data: Prisma.XOR +} + +export type GameVersionUpdateWithoutReviewRecordsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + project?: Prisma.GameProjectUpdateOneRequiredWithoutVersionsNestedInput + versionTargetJobs?: Prisma.JobUpdateManyWithoutGameVersionNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutVersionNestedInput + lifecycleEvents?: Prisma.LifecycleEventUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionUncheckedUpdateWithoutReviewRecordsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versionTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameVersionNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutVersionNestedInput + lifecycleEvents?: Prisma.LifecycleEventUncheckedUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionCreateWithoutLifecycleEventsInput = { + id: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + project: Prisma.GameProjectCreateNestedOneWithoutVersionsInput + versionTargetJobs?: Prisma.JobCreateNestedManyWithoutGameVersionInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutVersionInput + reviewRecords?: Prisma.ReviewRecordCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionUncheckedCreateWithoutLifecycleEventsInput = { + id: string + projectId: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + versionTargetJobs?: Prisma.JobUncheckedCreateNestedManyWithoutGameVersionInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutVersionInput + reviewRecords?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutGameVersionInput +} + +export type GameVersionCreateOrConnectWithoutLifecycleEventsInput = { + where: Prisma.GameVersionWhereUniqueInput + create: Prisma.XOR +} + +export type GameVersionUpsertWithoutLifecycleEventsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.GameVersionWhereInput +} + +export type GameVersionUpdateToOneWithWhereWithoutLifecycleEventsInput = { + where?: Prisma.GameVersionWhereInput + data: Prisma.XOR +} + +export type GameVersionUpdateWithoutLifecycleEventsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + project?: Prisma.GameProjectUpdateOneRequiredWithoutVersionsNestedInput + versionTargetJobs?: Prisma.JobUpdateManyWithoutGameVersionNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutVersionNestedInput + reviewRecords?: Prisma.ReviewRecordUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionUncheckedUpdateWithoutLifecycleEventsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versionTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameVersionNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutVersionNestedInput + reviewRecords?: Prisma.ReviewRecordUncheckedUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionCreateManyProjectInput = { + id: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type GameVersionUpdateWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versionTargetJobs?: Prisma.JobUpdateManyWithoutGameVersionNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUpdateManyWithoutVersionNestedInput + reviewRecords?: Prisma.ReviewRecordUpdateManyWithoutGameVersionNestedInput + lifecycleEvents?: Prisma.LifecycleEventUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionUncheckedUpdateWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + versionTargetJobs?: Prisma.JobUncheckedUpdateManyWithoutGameVersionNestedInput + mainCreationAgentSessionScopes?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutVersionNestedInput + reviewRecords?: Prisma.ReviewRecordUncheckedUpdateManyWithoutGameVersionNestedInput + lifecycleEvents?: Prisma.LifecycleEventUncheckedUpdateManyWithoutGameVersionNestedInput +} + +export type GameVersionUncheckedUpdateManyWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + versionNumber?: Prisma.IntFieldUpdateOperationsInput | number + status?: Prisma.EnumGameVersionStatusFieldUpdateOperationsInput | $Enums.GameVersionStatus + configJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + +/** + * Count Type GameVersionCountOutputType + */ + +export type GameVersionCountOutputType = { + versionTargetJobs: number + mainCreationAgentSessionScopes: number + reviewRecords: number + lifecycleEvents: number +} + +export type GameVersionCountOutputTypeSelect = { + versionTargetJobs?: boolean | GameVersionCountOutputTypeCountVersionTargetJobsArgs + mainCreationAgentSessionScopes?: boolean | GameVersionCountOutputTypeCountMainCreationAgentSessionScopesArgs + reviewRecords?: boolean | GameVersionCountOutputTypeCountReviewRecordsArgs + lifecycleEvents?: boolean | GameVersionCountOutputTypeCountLifecycleEventsArgs +} + +/** + * GameVersionCountOutputType without action + */ +export type GameVersionCountOutputTypeDefaultArgs = { + /** + * Select specific fields to fetch from the GameVersionCountOutputType + */ + select?: Prisma.GameVersionCountOutputTypeSelect | null +} + +/** + * GameVersionCountOutputType without action + */ +export type GameVersionCountOutputTypeCountVersionTargetJobsArgs = { + where?: Prisma.JobWhereInput +} + +/** + * GameVersionCountOutputType without action + */ +export type GameVersionCountOutputTypeCountMainCreationAgentSessionScopesArgs = { + where?: Prisma.MainCreationAgentSessionWhereInput +} + +/** + * GameVersionCountOutputType without action + */ +export type GameVersionCountOutputTypeCountReviewRecordsArgs = { + where?: Prisma.ReviewRecordWhereInput +} + +/** + * GameVersionCountOutputType without action + */ +export type GameVersionCountOutputTypeCountLifecycleEventsArgs = { + where?: Prisma.LifecycleEventWhereInput +} + + +export type GameVersionSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + projectId?: boolean + versionNumber?: boolean + status?: boolean + configJson?: boolean + createdAt?: boolean + updatedAt?: boolean + project?: boolean | Prisma.GameProjectDefaultArgs + versionTargetJobs?: boolean | Prisma.GameVersion$versionTargetJobsArgs + mainCreationAgentSessionScopes?: boolean | Prisma.GameVersion$mainCreationAgentSessionScopesArgs + reviewRecords?: boolean | Prisma.GameVersion$reviewRecordsArgs + lifecycleEvents?: boolean | Prisma.GameVersion$lifecycleEventsArgs + _count?: boolean | Prisma.GameVersionCountOutputTypeDefaultArgs +}, ExtArgs["result"]["gameVersion"]> + +export type GameVersionSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + projectId?: boolean + versionNumber?: boolean + status?: boolean + configJson?: boolean + createdAt?: boolean + updatedAt?: boolean + project?: boolean | Prisma.GameProjectDefaultArgs +}, ExtArgs["result"]["gameVersion"]> + +export type GameVersionSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + projectId?: boolean + versionNumber?: boolean + status?: boolean + configJson?: boolean + createdAt?: boolean + updatedAt?: boolean + project?: boolean | Prisma.GameProjectDefaultArgs +}, ExtArgs["result"]["gameVersion"]> + +export type GameVersionSelectScalar = { + id?: boolean + projectId?: boolean + versionNumber?: boolean + status?: boolean + configJson?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type GameVersionOmit = runtime.Types.Extensions.GetOmit<"id" | "projectId" | "versionNumber" | "status" | "configJson" | "createdAt" | "updatedAt", ExtArgs["result"]["gameVersion"]> +export type GameVersionInclude = { + project?: boolean | Prisma.GameProjectDefaultArgs + versionTargetJobs?: boolean | Prisma.GameVersion$versionTargetJobsArgs + mainCreationAgentSessionScopes?: boolean | Prisma.GameVersion$mainCreationAgentSessionScopesArgs + reviewRecords?: boolean | Prisma.GameVersion$reviewRecordsArgs + lifecycleEvents?: boolean | Prisma.GameVersion$lifecycleEventsArgs + _count?: boolean | Prisma.GameVersionCountOutputTypeDefaultArgs +} +export type GameVersionIncludeCreateManyAndReturn = { + project?: boolean | Prisma.GameProjectDefaultArgs +} +export type GameVersionIncludeUpdateManyAndReturn = { + project?: boolean | Prisma.GameProjectDefaultArgs +} + +export type $GameVersionPayload = { + name: "GameVersion" + objects: { + project: Prisma.$GameProjectPayload + versionTargetJobs: Prisma.$JobPayload[] + mainCreationAgentSessionScopes: Prisma.$MainCreationAgentSessionPayload[] + reviewRecords: Prisma.$ReviewRecordPayload[] + lifecycleEvents: Prisma.$LifecycleEventPayload[] + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + projectId: string + versionNumber: number + status: $Enums.GameVersionStatus + configJson: runtime.JsonValue + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["gameVersion"]> + composites: {} +} + +export type GameVersionGetPayload = runtime.Types.Result.GetResult + +export type GameVersionCountArgs = + Omit & { + select?: GameVersionCountAggregateInputType | true + } + +export interface GameVersionDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['GameVersion'], meta: { name: 'GameVersion' } } + /** + * Find zero or one GameVersion that matches the filter. + * @param {GameVersionFindUniqueArgs} args - Arguments to find a GameVersion + * @example + * // Get one GameVersion + * const gameVersion = await prisma.gameVersion.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__GameVersionClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one GameVersion that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {GameVersionFindUniqueOrThrowArgs} args - Arguments to find a GameVersion + * @example + * // Get one GameVersion + * const gameVersion = await prisma.gameVersion.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__GameVersionClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first GameVersion that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameVersionFindFirstArgs} args - Arguments to find a GameVersion + * @example + * // Get one GameVersion + * const gameVersion = await prisma.gameVersion.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__GameVersionClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first GameVersion that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameVersionFindFirstOrThrowArgs} args - Arguments to find a GameVersion + * @example + * // Get one GameVersion + * const gameVersion = await prisma.gameVersion.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__GameVersionClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more GameVersions that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameVersionFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all GameVersions + * const gameVersions = await prisma.gameVersion.findMany() + * + * // Get first 10 GameVersions + * const gameVersions = await prisma.gameVersion.findMany({ take: 10 }) + * + * // Only select the `id` + * const gameVersionWithIdOnly = await prisma.gameVersion.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a GameVersion. + * @param {GameVersionCreateArgs} args - Arguments to create a GameVersion. + * @example + * // Create one GameVersion + * const GameVersion = await prisma.gameVersion.create({ + * data: { + * // ... data to create a GameVersion + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__GameVersionClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many GameVersions. + * @param {GameVersionCreateManyArgs} args - Arguments to create many GameVersions. + * @example + * // Create many GameVersions + * const gameVersion = await prisma.gameVersion.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many GameVersions and returns the data saved in the database. + * @param {GameVersionCreateManyAndReturnArgs} args - Arguments to create many GameVersions. + * @example + * // Create many GameVersions + * const gameVersion = await prisma.gameVersion.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many GameVersions and only return the `id` + * const gameVersionWithIdOnly = await prisma.gameVersion.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a GameVersion. + * @param {GameVersionDeleteArgs} args - Arguments to delete one GameVersion. + * @example + * // Delete one GameVersion + * const GameVersion = await prisma.gameVersion.delete({ + * where: { + * // ... filter to delete one GameVersion + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__GameVersionClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one GameVersion. + * @param {GameVersionUpdateArgs} args - Arguments to update one GameVersion. + * @example + * // Update one GameVersion + * const gameVersion = await prisma.gameVersion.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__GameVersionClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more GameVersions. + * @param {GameVersionDeleteManyArgs} args - Arguments to filter GameVersions to delete. + * @example + * // Delete a few GameVersions + * const { count } = await prisma.gameVersion.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more GameVersions. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameVersionUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many GameVersions + * const gameVersion = await prisma.gameVersion.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more GameVersions and returns the data updated in the database. + * @param {GameVersionUpdateManyAndReturnArgs} args - Arguments to update many GameVersions. + * @example + * // Update many GameVersions + * const gameVersion = await prisma.gameVersion.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more GameVersions and only return the `id` + * const gameVersionWithIdOnly = await prisma.gameVersion.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one GameVersion. + * @param {GameVersionUpsertArgs} args - Arguments to update or create a GameVersion. + * @example + * // Update or create a GameVersion + * const gameVersion = await prisma.gameVersion.upsert({ + * create: { + * // ... data to create a GameVersion + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the GameVersion we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__GameVersionClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of GameVersions. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameVersionCountArgs} args - Arguments to filter GameVersions to count. + * @example + * // Count the number of GameVersions + * const count = await prisma.gameVersion.count({ + * where: { + * // ... the filter for the GameVersions we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a GameVersion. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameVersionAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by GameVersion. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {GameVersionGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends GameVersionGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: GameVersionGroupByArgs['orderBy'] } + : { orderBy?: GameVersionGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetGameVersionGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the GameVersion model + */ +readonly fields: GameVersionFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for GameVersion. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__GameVersionClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + project = {}>(args?: Prisma.Subset>): Prisma.Prisma__GameProjectClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + versionTargetJobs = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + mainCreationAgentSessionScopes = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + reviewRecords = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + lifecycleEvents = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the GameVersion model + */ +export interface GameVersionFieldRefs { + readonly id: Prisma.FieldRef<"GameVersion", 'String'> + readonly projectId: Prisma.FieldRef<"GameVersion", 'String'> + readonly versionNumber: Prisma.FieldRef<"GameVersion", 'Int'> + readonly status: Prisma.FieldRef<"GameVersion", 'GameVersionStatus'> + readonly configJson: Prisma.FieldRef<"GameVersion", 'Json'> + readonly createdAt: Prisma.FieldRef<"GameVersion", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"GameVersion", 'DateTime'> +} + + +// Custom InputTypes +/** + * GameVersion findUnique + */ +export type GameVersionFindUniqueArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + /** + * Filter, which GameVersion to fetch. + */ + where: Prisma.GameVersionWhereUniqueInput +} + +/** + * GameVersion findUniqueOrThrow + */ +export type GameVersionFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + /** + * Filter, which GameVersion to fetch. + */ + where: Prisma.GameVersionWhereUniqueInput +} + +/** + * GameVersion findFirst + */ +export type GameVersionFindFirstArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + /** + * Filter, which GameVersion to fetch. + */ + where?: Prisma.GameVersionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of GameVersions to fetch. + */ + orderBy?: Prisma.GameVersionOrderByWithRelationInput | Prisma.GameVersionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for GameVersions. + */ + cursor?: Prisma.GameVersionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` GameVersions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` GameVersions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of GameVersions. + */ + distinct?: Prisma.GameVersionScalarFieldEnum | Prisma.GameVersionScalarFieldEnum[] +} + +/** + * GameVersion findFirstOrThrow + */ +export type GameVersionFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + /** + * Filter, which GameVersion to fetch. + */ + where?: Prisma.GameVersionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of GameVersions to fetch. + */ + orderBy?: Prisma.GameVersionOrderByWithRelationInput | Prisma.GameVersionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for GameVersions. + */ + cursor?: Prisma.GameVersionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` GameVersions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` GameVersions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of GameVersions. + */ + distinct?: Prisma.GameVersionScalarFieldEnum | Prisma.GameVersionScalarFieldEnum[] +} + +/** + * GameVersion findMany + */ +export type GameVersionFindManyArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + /** + * Filter, which GameVersions to fetch. + */ + where?: Prisma.GameVersionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of GameVersions to fetch. + */ + orderBy?: Prisma.GameVersionOrderByWithRelationInput | Prisma.GameVersionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing GameVersions. + */ + cursor?: Prisma.GameVersionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` GameVersions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` GameVersions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of GameVersions. + */ + distinct?: Prisma.GameVersionScalarFieldEnum | Prisma.GameVersionScalarFieldEnum[] +} + +/** + * GameVersion create + */ +export type GameVersionCreateArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + /** + * The data needed to create a GameVersion. + */ + data: Prisma.XOR +} + +/** + * GameVersion createMany + */ +export type GameVersionCreateManyArgs = { + /** + * The data used to create many GameVersions. + */ + data: Prisma.GameVersionCreateManyInput | Prisma.GameVersionCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * GameVersion createManyAndReturn + */ +export type GameVersionCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelectCreateManyAndReturn | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * The data used to create many GameVersions. + */ + data: Prisma.GameVersionCreateManyInput | Prisma.GameVersionCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionIncludeCreateManyAndReturn | null +} + +/** + * GameVersion update + */ +export type GameVersionUpdateArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + /** + * The data needed to update a GameVersion. + */ + data: Prisma.XOR + /** + * Choose, which GameVersion to update. + */ + where: Prisma.GameVersionWhereUniqueInput +} + +/** + * GameVersion updateMany + */ +export type GameVersionUpdateManyArgs = { + /** + * The data used to update GameVersions. + */ + data: Prisma.XOR + /** + * Filter which GameVersions to update + */ + where?: Prisma.GameVersionWhereInput + /** + * Limit how many GameVersions to update. + */ + limit?: number +} + +/** + * GameVersion updateManyAndReturn + */ +export type GameVersionUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * The data used to update GameVersions. + */ + data: Prisma.XOR + /** + * Filter which GameVersions to update + */ + where?: Prisma.GameVersionWhereInput + /** + * Limit how many GameVersions to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionIncludeUpdateManyAndReturn | null +} + +/** + * GameVersion upsert + */ +export type GameVersionUpsertArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + /** + * The filter to search for the GameVersion to update in case it exists. + */ + where: Prisma.GameVersionWhereUniqueInput + /** + * In case the GameVersion found by the `where` argument doesn't exist, create a new GameVersion with this data. + */ + create: Prisma.XOR + /** + * In case the GameVersion was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * GameVersion delete + */ +export type GameVersionDeleteArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + /** + * Filter which GameVersion to delete. + */ + where: Prisma.GameVersionWhereUniqueInput +} + +/** + * GameVersion deleteMany + */ +export type GameVersionDeleteManyArgs = { + /** + * Filter which GameVersions to delete + */ + where?: Prisma.GameVersionWhereInput + /** + * Limit how many GameVersions to delete. + */ + limit?: number +} + +/** + * GameVersion.versionTargetJobs + */ +export type GameVersion$versionTargetJobsArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + where?: Prisma.JobWhereInput + orderBy?: Prisma.JobOrderByWithRelationInput | Prisma.JobOrderByWithRelationInput[] + cursor?: Prisma.JobWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.JobScalarFieldEnum | Prisma.JobScalarFieldEnum[] +} + +/** + * GameVersion.mainCreationAgentSessionScopes + */ +export type GameVersion$mainCreationAgentSessionScopesArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + where?: Prisma.MainCreationAgentSessionWhereInput + orderBy?: Prisma.MainCreationAgentSessionOrderByWithRelationInput | Prisma.MainCreationAgentSessionOrderByWithRelationInput[] + cursor?: Prisma.MainCreationAgentSessionWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.MainCreationAgentSessionScalarFieldEnum | Prisma.MainCreationAgentSessionScalarFieldEnum[] +} + +/** + * GameVersion.reviewRecords + */ +export type GameVersion$reviewRecordsArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + where?: Prisma.ReviewRecordWhereInput + orderBy?: Prisma.ReviewRecordOrderByWithRelationInput | Prisma.ReviewRecordOrderByWithRelationInput[] + cursor?: Prisma.ReviewRecordWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.ReviewRecordScalarFieldEnum | Prisma.ReviewRecordScalarFieldEnum[] +} + +/** + * GameVersion.lifecycleEvents + */ +export type GameVersion$lifecycleEventsArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null + where?: Prisma.LifecycleEventWhereInput + orderBy?: Prisma.LifecycleEventOrderByWithRelationInput | Prisma.LifecycleEventOrderByWithRelationInput[] + cursor?: Prisma.LifecycleEventWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.LifecycleEventScalarFieldEnum | Prisma.LifecycleEventScalarFieldEnum[] +} + +/** + * GameVersion without action + */ +export type GameVersionDefaultArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null +} diff --git a/apps/api/src/generated/prisma/models/Job.ts b/apps/api/src/generated/prisma/models/Job.ts new file mode 100644 index 00000000..22319866 --- /dev/null +++ b/apps/api/src/generated/prisma/models/Job.ts @@ -0,0 +1,2764 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `Job` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model Job + * + */ +export type JobModel = runtime.Types.Result.DefaultSelection + +export type AggregateJob = { + _count: JobCountAggregateOutputType | null + _avg: JobAvgAggregateOutputType | null + _sum: JobSumAggregateOutputType | null + _min: JobMinAggregateOutputType | null + _max: JobMaxAggregateOutputType | null +} + +export type JobAvgAggregateOutputType = { + attempts: number | null + maxAttempts: number | null + lockVersion: number | null +} + +export type JobSumAggregateOutputType = { + attempts: number | null + maxAttempts: number | null + lockVersion: number | null +} + +export type JobMinAggregateOutputType = { + id: string | null + actorId: string | null + projectId: string | null + type: string | null + idempotencyKey: string | null + status: $Enums.JobStatus | null + attempts: number | null + maxAttempts: number | null + timeoutAt: Date | null + nextRetryAt: Date | null + errorCode: string | null + leaseToken: string | null + leasedBy: string | null + leaseExpiresAt: Date | null + lockVersion: number | null + targetType: $Enums.JobTargetType | null + targetId: string | null + targetScopeKey: string | null + gameProjectId: string | null + gameVersionId: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type JobMaxAggregateOutputType = { + id: string | null + actorId: string | null + projectId: string | null + type: string | null + idempotencyKey: string | null + status: $Enums.JobStatus | null + attempts: number | null + maxAttempts: number | null + timeoutAt: Date | null + nextRetryAt: Date | null + errorCode: string | null + leaseToken: string | null + leasedBy: string | null + leaseExpiresAt: Date | null + lockVersion: number | null + targetType: $Enums.JobTargetType | null + targetId: string | null + targetScopeKey: string | null + gameProjectId: string | null + gameVersionId: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type JobCountAggregateOutputType = { + id: number + actorId: number + projectId: number + type: number + idempotencyKey: number + status: number + attempts: number + maxAttempts: number + timeoutAt: number + nextRetryAt: number + errorCode: number + leaseToken: number + leasedBy: number + leaseExpiresAt: number + lockVersion: number + targetType: number + targetId: number + targetScopeKey: number + gameProjectId: number + gameVersionId: number + payloadJson: number + createdAt: number + updatedAt: number + _all: number +} + + +export type JobAvgAggregateInputType = { + attempts?: true + maxAttempts?: true + lockVersion?: true +} + +export type JobSumAggregateInputType = { + attempts?: true + maxAttempts?: true + lockVersion?: true +} + +export type JobMinAggregateInputType = { + id?: true + actorId?: true + projectId?: true + type?: true + idempotencyKey?: true + status?: true + attempts?: true + maxAttempts?: true + timeoutAt?: true + nextRetryAt?: true + errorCode?: true + leaseToken?: true + leasedBy?: true + leaseExpiresAt?: true + lockVersion?: true + targetType?: true + targetId?: true + targetScopeKey?: true + gameProjectId?: true + gameVersionId?: true + createdAt?: true + updatedAt?: true +} + +export type JobMaxAggregateInputType = { + id?: true + actorId?: true + projectId?: true + type?: true + idempotencyKey?: true + status?: true + attempts?: true + maxAttempts?: true + timeoutAt?: true + nextRetryAt?: true + errorCode?: true + leaseToken?: true + leasedBy?: true + leaseExpiresAt?: true + lockVersion?: true + targetType?: true + targetId?: true + targetScopeKey?: true + gameProjectId?: true + gameVersionId?: true + createdAt?: true + updatedAt?: true +} + +export type JobCountAggregateInputType = { + id?: true + actorId?: true + projectId?: true + type?: true + idempotencyKey?: true + status?: true + attempts?: true + maxAttempts?: true + timeoutAt?: true + nextRetryAt?: true + errorCode?: true + leaseToken?: true + leasedBy?: true + leaseExpiresAt?: true + lockVersion?: true + targetType?: true + targetId?: true + targetScopeKey?: true + gameProjectId?: true + gameVersionId?: true + payloadJson?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type JobAggregateArgs = { + /** + * Filter which Job to aggregate. + */ + where?: Prisma.JobWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Jobs to fetch. + */ + orderBy?: Prisma.JobOrderByWithRelationInput | Prisma.JobOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.JobWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Jobs from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Jobs. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Jobs + **/ + _count?: true | JobCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: JobAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: JobSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: JobMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: JobMaxAggregateInputType +} + +export type GetJobAggregateType = { + [P in keyof T & keyof AggregateJob]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type JobGroupByArgs = { + where?: Prisma.JobWhereInput + orderBy?: Prisma.JobOrderByWithAggregationInput | Prisma.JobOrderByWithAggregationInput[] + by: Prisma.JobScalarFieldEnum[] | Prisma.JobScalarFieldEnum + having?: Prisma.JobScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: JobCountAggregateInputType | true + _avg?: JobAvgAggregateInputType + _sum?: JobSumAggregateInputType + _min?: JobMinAggregateInputType + _max?: JobMaxAggregateInputType +} + +export type JobGroupByOutputType = { + id: string + actorId: string + projectId: string + type: string + idempotencyKey: string + status: $Enums.JobStatus + attempts: number + maxAttempts: number + timeoutAt: Date | null + nextRetryAt: Date | null + errorCode: string | null + leaseToken: string | null + leasedBy: string | null + leaseExpiresAt: Date | null + lockVersion: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameProjectId: string | null + gameVersionId: string | null + payloadJson: runtime.JsonValue + createdAt: Date + updatedAt: Date + _count: JobCountAggregateOutputType | null + _avg: JobAvgAggregateOutputType | null + _sum: JobSumAggregateOutputType | null + _min: JobMinAggregateOutputType | null + _max: JobMaxAggregateOutputType | null +} + +export type GetJobGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof JobGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type JobWhereInput = { + AND?: Prisma.JobWhereInput | Prisma.JobWhereInput[] + OR?: Prisma.JobWhereInput[] + NOT?: Prisma.JobWhereInput | Prisma.JobWhereInput[] + id?: Prisma.StringFilter<"Job"> | string + actorId?: Prisma.StringFilter<"Job"> | string + projectId?: Prisma.StringFilter<"Job"> | string + type?: Prisma.StringFilter<"Job"> | string + idempotencyKey?: Prisma.StringFilter<"Job"> | string + status?: Prisma.EnumJobStatusFilter<"Job"> | $Enums.JobStatus + attempts?: Prisma.IntFilter<"Job"> | number + maxAttempts?: Prisma.IntFilter<"Job"> | number + timeoutAt?: Prisma.DateTimeNullableFilter<"Job"> | Date | string | null + nextRetryAt?: Prisma.DateTimeNullableFilter<"Job"> | Date | string | null + errorCode?: Prisma.StringNullableFilter<"Job"> | string | null + leaseToken?: Prisma.StringNullableFilter<"Job"> | string | null + leasedBy?: Prisma.StringNullableFilter<"Job"> | string | null + leaseExpiresAt?: Prisma.DateTimeNullableFilter<"Job"> | Date | string | null + lockVersion?: Prisma.IntFilter<"Job"> | number + targetType?: Prisma.EnumJobTargetTypeFilter<"Job"> | $Enums.JobTargetType + targetId?: Prisma.StringFilter<"Job"> | string + targetScopeKey?: Prisma.StringFilter<"Job"> | string + gameProjectId?: Prisma.StringNullableFilter<"Job"> | string | null + gameVersionId?: Prisma.StringNullableFilter<"Job"> | string | null + payloadJson?: Prisma.JsonFilter<"Job"> + createdAt?: Prisma.DateTimeFilter<"Job"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Job"> | Date | string + actor?: Prisma.XOR + project?: Prisma.XOR + gameProject?: Prisma.XOR | null + gameVersion?: Prisma.XOR | null +} + +export type JobOrderByWithRelationInput = { + id?: Prisma.SortOrder + actorId?: Prisma.SortOrder + projectId?: Prisma.SortOrder + type?: Prisma.SortOrder + idempotencyKey?: Prisma.SortOrder + status?: Prisma.SortOrder + attempts?: Prisma.SortOrder + maxAttempts?: Prisma.SortOrder + timeoutAt?: Prisma.SortOrderInput | Prisma.SortOrder + nextRetryAt?: Prisma.SortOrderInput | Prisma.SortOrder + errorCode?: Prisma.SortOrderInput | Prisma.SortOrder + leaseToken?: Prisma.SortOrderInput | Prisma.SortOrder + leasedBy?: Prisma.SortOrderInput | Prisma.SortOrder + leaseExpiresAt?: Prisma.SortOrderInput | Prisma.SortOrder + lockVersion?: Prisma.SortOrder + targetType?: Prisma.SortOrder + targetId?: Prisma.SortOrder + targetScopeKey?: Prisma.SortOrder + gameProjectId?: Prisma.SortOrderInput | Prisma.SortOrder + gameVersionId?: Prisma.SortOrderInput | Prisma.SortOrder + payloadJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + actor?: Prisma.UserOrderByWithRelationInput + project?: Prisma.GameProjectOrderByWithRelationInput + gameProject?: Prisma.GameProjectOrderByWithRelationInput + gameVersion?: Prisma.GameVersionOrderByWithRelationInput +} + +export type JobWhereUniqueInput = Prisma.AtLeast<{ + id?: string + actorId_projectId_type_targetScopeKey_idempotencyKey?: Prisma.JobActorIdProjectIdTypeTargetScopeKeyIdempotencyKeyCompoundUniqueInput + AND?: Prisma.JobWhereInput | Prisma.JobWhereInput[] + OR?: Prisma.JobWhereInput[] + NOT?: Prisma.JobWhereInput | Prisma.JobWhereInput[] + actorId?: Prisma.StringFilter<"Job"> | string + projectId?: Prisma.StringFilter<"Job"> | string + type?: Prisma.StringFilter<"Job"> | string + idempotencyKey?: Prisma.StringFilter<"Job"> | string + status?: Prisma.EnumJobStatusFilter<"Job"> | $Enums.JobStatus + attempts?: Prisma.IntFilter<"Job"> | number + maxAttempts?: Prisma.IntFilter<"Job"> | number + timeoutAt?: Prisma.DateTimeNullableFilter<"Job"> | Date | string | null + nextRetryAt?: Prisma.DateTimeNullableFilter<"Job"> | Date | string | null + errorCode?: Prisma.StringNullableFilter<"Job"> | string | null + leaseToken?: Prisma.StringNullableFilter<"Job"> | string | null + leasedBy?: Prisma.StringNullableFilter<"Job"> | string | null + leaseExpiresAt?: Prisma.DateTimeNullableFilter<"Job"> | Date | string | null + lockVersion?: Prisma.IntFilter<"Job"> | number + targetType?: Prisma.EnumJobTargetTypeFilter<"Job"> | $Enums.JobTargetType + targetId?: Prisma.StringFilter<"Job"> | string + targetScopeKey?: Prisma.StringFilter<"Job"> | string + gameProjectId?: Prisma.StringNullableFilter<"Job"> | string | null + gameVersionId?: Prisma.StringNullableFilter<"Job"> | string | null + payloadJson?: Prisma.JsonFilter<"Job"> + createdAt?: Prisma.DateTimeFilter<"Job"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Job"> | Date | string + actor?: Prisma.XOR + project?: Prisma.XOR + gameProject?: Prisma.XOR | null + gameVersion?: Prisma.XOR | null +}, "id" | "actorId_projectId_type_targetScopeKey_idempotencyKey"> + +export type JobOrderByWithAggregationInput = { + id?: Prisma.SortOrder + actorId?: Prisma.SortOrder + projectId?: Prisma.SortOrder + type?: Prisma.SortOrder + idempotencyKey?: Prisma.SortOrder + status?: Prisma.SortOrder + attempts?: Prisma.SortOrder + maxAttempts?: Prisma.SortOrder + timeoutAt?: Prisma.SortOrderInput | Prisma.SortOrder + nextRetryAt?: Prisma.SortOrderInput | Prisma.SortOrder + errorCode?: Prisma.SortOrderInput | Prisma.SortOrder + leaseToken?: Prisma.SortOrderInput | Prisma.SortOrder + leasedBy?: Prisma.SortOrderInput | Prisma.SortOrder + leaseExpiresAt?: Prisma.SortOrderInput | Prisma.SortOrder + lockVersion?: Prisma.SortOrder + targetType?: Prisma.SortOrder + targetId?: Prisma.SortOrder + targetScopeKey?: Prisma.SortOrder + gameProjectId?: Prisma.SortOrderInput | Prisma.SortOrder + gameVersionId?: Prisma.SortOrderInput | Prisma.SortOrder + payloadJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.JobCountOrderByAggregateInput + _avg?: Prisma.JobAvgOrderByAggregateInput + _max?: Prisma.JobMaxOrderByAggregateInput + _min?: Prisma.JobMinOrderByAggregateInput + _sum?: Prisma.JobSumOrderByAggregateInput +} + +export type JobScalarWhereWithAggregatesInput = { + AND?: Prisma.JobScalarWhereWithAggregatesInput | Prisma.JobScalarWhereWithAggregatesInput[] + OR?: Prisma.JobScalarWhereWithAggregatesInput[] + NOT?: Prisma.JobScalarWhereWithAggregatesInput | Prisma.JobScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"Job"> | string + actorId?: Prisma.StringWithAggregatesFilter<"Job"> | string + projectId?: Prisma.StringWithAggregatesFilter<"Job"> | string + type?: Prisma.StringWithAggregatesFilter<"Job"> | string + idempotencyKey?: Prisma.StringWithAggregatesFilter<"Job"> | string + status?: Prisma.EnumJobStatusWithAggregatesFilter<"Job"> | $Enums.JobStatus + attempts?: Prisma.IntWithAggregatesFilter<"Job"> | number + maxAttempts?: Prisma.IntWithAggregatesFilter<"Job"> | number + timeoutAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Job"> | Date | string | null + nextRetryAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Job"> | Date | string | null + errorCode?: Prisma.StringNullableWithAggregatesFilter<"Job"> | string | null + leaseToken?: Prisma.StringNullableWithAggregatesFilter<"Job"> | string | null + leasedBy?: Prisma.StringNullableWithAggregatesFilter<"Job"> | string | null + leaseExpiresAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Job"> | Date | string | null + lockVersion?: Prisma.IntWithAggregatesFilter<"Job"> | number + targetType?: Prisma.EnumJobTargetTypeWithAggregatesFilter<"Job"> | $Enums.JobTargetType + targetId?: Prisma.StringWithAggregatesFilter<"Job"> | string + targetScopeKey?: Prisma.StringWithAggregatesFilter<"Job"> | string + gameProjectId?: Prisma.StringNullableWithAggregatesFilter<"Job"> | string | null + gameVersionId?: Prisma.StringNullableWithAggregatesFilter<"Job"> | string | null + payloadJson?: Prisma.JsonWithAggregatesFilter<"Job"> + createdAt?: Prisma.DateTimeWithAggregatesFilter<"Job"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Job"> | Date | string +} + +export type JobCreateInput = { + id: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + actor: Prisma.UserCreateNestedOneWithoutJobsInput + project: Prisma.GameProjectCreateNestedOneWithoutJobsInput + gameProject?: Prisma.GameProjectCreateNestedOneWithoutProjectTargetJobsInput + gameVersion?: Prisma.GameVersionCreateNestedOneWithoutVersionTargetJobsInput +} + +export type JobUncheckedCreateInput = { + id: string + actorId: string + projectId: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameProjectId?: string | null + gameVersionId?: string | null + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type JobUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + actor?: Prisma.UserUpdateOneRequiredWithoutJobsNestedInput + project?: Prisma.GameProjectUpdateOneRequiredWithoutJobsNestedInput + gameProject?: Prisma.GameProjectUpdateOneWithoutProjectTargetJobsNestedInput + gameVersion?: Prisma.GameVersionUpdateOneWithoutVersionTargetJobsNestedInput +} + +export type JobUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + actorId?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + gameProjectId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + gameVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type JobCreateManyInput = { + id: string + actorId: string + projectId: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameProjectId?: string | null + gameVersionId?: string | null + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type JobUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type JobUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + actorId?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + gameProjectId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + gameVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type JobListRelationFilter = { + every?: Prisma.JobWhereInput + some?: Prisma.JobWhereInput + none?: Prisma.JobWhereInput +} + +export type JobOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type JobActorIdProjectIdTypeTargetScopeKeyIdempotencyKeyCompoundUniqueInput = { + actorId: string + projectId: string + type: string + targetScopeKey: string + idempotencyKey: string +} + +export type JobCountOrderByAggregateInput = { + id?: Prisma.SortOrder + actorId?: Prisma.SortOrder + projectId?: Prisma.SortOrder + type?: Prisma.SortOrder + idempotencyKey?: Prisma.SortOrder + status?: Prisma.SortOrder + attempts?: Prisma.SortOrder + maxAttempts?: Prisma.SortOrder + timeoutAt?: Prisma.SortOrder + nextRetryAt?: Prisma.SortOrder + errorCode?: Prisma.SortOrder + leaseToken?: Prisma.SortOrder + leasedBy?: Prisma.SortOrder + leaseExpiresAt?: Prisma.SortOrder + lockVersion?: Prisma.SortOrder + targetType?: Prisma.SortOrder + targetId?: Prisma.SortOrder + targetScopeKey?: Prisma.SortOrder + gameProjectId?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + payloadJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type JobAvgOrderByAggregateInput = { + attempts?: Prisma.SortOrder + maxAttempts?: Prisma.SortOrder + lockVersion?: Prisma.SortOrder +} + +export type JobMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + actorId?: Prisma.SortOrder + projectId?: Prisma.SortOrder + type?: Prisma.SortOrder + idempotencyKey?: Prisma.SortOrder + status?: Prisma.SortOrder + attempts?: Prisma.SortOrder + maxAttempts?: Prisma.SortOrder + timeoutAt?: Prisma.SortOrder + nextRetryAt?: Prisma.SortOrder + errorCode?: Prisma.SortOrder + leaseToken?: Prisma.SortOrder + leasedBy?: Prisma.SortOrder + leaseExpiresAt?: Prisma.SortOrder + lockVersion?: Prisma.SortOrder + targetType?: Prisma.SortOrder + targetId?: Prisma.SortOrder + targetScopeKey?: Prisma.SortOrder + gameProjectId?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type JobMinOrderByAggregateInput = { + id?: Prisma.SortOrder + actorId?: Prisma.SortOrder + projectId?: Prisma.SortOrder + type?: Prisma.SortOrder + idempotencyKey?: Prisma.SortOrder + status?: Prisma.SortOrder + attempts?: Prisma.SortOrder + maxAttempts?: Prisma.SortOrder + timeoutAt?: Prisma.SortOrder + nextRetryAt?: Prisma.SortOrder + errorCode?: Prisma.SortOrder + leaseToken?: Prisma.SortOrder + leasedBy?: Prisma.SortOrder + leaseExpiresAt?: Prisma.SortOrder + lockVersion?: Prisma.SortOrder + targetType?: Prisma.SortOrder + targetId?: Prisma.SortOrder + targetScopeKey?: Prisma.SortOrder + gameProjectId?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type JobSumOrderByAggregateInput = { + attempts?: Prisma.SortOrder + maxAttempts?: Prisma.SortOrder + lockVersion?: Prisma.SortOrder +} + +export type JobCreateNestedManyWithoutActorInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutActorInput[] | Prisma.JobUncheckedCreateWithoutActorInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutActorInput | Prisma.JobCreateOrConnectWithoutActorInput[] + createMany?: Prisma.JobCreateManyActorInputEnvelope + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] +} + +export type JobUncheckedCreateNestedManyWithoutActorInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutActorInput[] | Prisma.JobUncheckedCreateWithoutActorInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutActorInput | Prisma.JobCreateOrConnectWithoutActorInput[] + createMany?: Prisma.JobCreateManyActorInputEnvelope + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] +} + +export type JobUpdateManyWithoutActorNestedInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutActorInput[] | Prisma.JobUncheckedCreateWithoutActorInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutActorInput | Prisma.JobCreateOrConnectWithoutActorInput[] + upsert?: Prisma.JobUpsertWithWhereUniqueWithoutActorInput | Prisma.JobUpsertWithWhereUniqueWithoutActorInput[] + createMany?: Prisma.JobCreateManyActorInputEnvelope + set?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + disconnect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + delete?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + update?: Prisma.JobUpdateWithWhereUniqueWithoutActorInput | Prisma.JobUpdateWithWhereUniqueWithoutActorInput[] + updateMany?: Prisma.JobUpdateManyWithWhereWithoutActorInput | Prisma.JobUpdateManyWithWhereWithoutActorInput[] + deleteMany?: Prisma.JobScalarWhereInput | Prisma.JobScalarWhereInput[] +} + +export type JobUncheckedUpdateManyWithoutActorNestedInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutActorInput[] | Prisma.JobUncheckedCreateWithoutActorInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutActorInput | Prisma.JobCreateOrConnectWithoutActorInput[] + upsert?: Prisma.JobUpsertWithWhereUniqueWithoutActorInput | Prisma.JobUpsertWithWhereUniqueWithoutActorInput[] + createMany?: Prisma.JobCreateManyActorInputEnvelope + set?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + disconnect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + delete?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + update?: Prisma.JobUpdateWithWhereUniqueWithoutActorInput | Prisma.JobUpdateWithWhereUniqueWithoutActorInput[] + updateMany?: Prisma.JobUpdateManyWithWhereWithoutActorInput | Prisma.JobUpdateManyWithWhereWithoutActorInput[] + deleteMany?: Prisma.JobScalarWhereInput | Prisma.JobScalarWhereInput[] +} + +export type JobCreateNestedManyWithoutProjectInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutProjectInput[] | Prisma.JobUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutProjectInput | Prisma.JobCreateOrConnectWithoutProjectInput[] + createMany?: Prisma.JobCreateManyProjectInputEnvelope + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] +} + +export type JobCreateNestedManyWithoutGameProjectInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutGameProjectInput[] | Prisma.JobUncheckedCreateWithoutGameProjectInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutGameProjectInput | Prisma.JobCreateOrConnectWithoutGameProjectInput[] + createMany?: Prisma.JobCreateManyGameProjectInputEnvelope + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] +} + +export type JobUncheckedCreateNestedManyWithoutProjectInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutProjectInput[] | Prisma.JobUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutProjectInput | Prisma.JobCreateOrConnectWithoutProjectInput[] + createMany?: Prisma.JobCreateManyProjectInputEnvelope + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] +} + +export type JobUncheckedCreateNestedManyWithoutGameProjectInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutGameProjectInput[] | Prisma.JobUncheckedCreateWithoutGameProjectInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutGameProjectInput | Prisma.JobCreateOrConnectWithoutGameProjectInput[] + createMany?: Prisma.JobCreateManyGameProjectInputEnvelope + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] +} + +export type JobUpdateManyWithoutProjectNestedInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutProjectInput[] | Prisma.JobUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutProjectInput | Prisma.JobCreateOrConnectWithoutProjectInput[] + upsert?: Prisma.JobUpsertWithWhereUniqueWithoutProjectInput | Prisma.JobUpsertWithWhereUniqueWithoutProjectInput[] + createMany?: Prisma.JobCreateManyProjectInputEnvelope + set?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + disconnect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + delete?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + update?: Prisma.JobUpdateWithWhereUniqueWithoutProjectInput | Prisma.JobUpdateWithWhereUniqueWithoutProjectInput[] + updateMany?: Prisma.JobUpdateManyWithWhereWithoutProjectInput | Prisma.JobUpdateManyWithWhereWithoutProjectInput[] + deleteMany?: Prisma.JobScalarWhereInput | Prisma.JobScalarWhereInput[] +} + +export type JobUpdateManyWithoutGameProjectNestedInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutGameProjectInput[] | Prisma.JobUncheckedCreateWithoutGameProjectInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutGameProjectInput | Prisma.JobCreateOrConnectWithoutGameProjectInput[] + upsert?: Prisma.JobUpsertWithWhereUniqueWithoutGameProjectInput | Prisma.JobUpsertWithWhereUniqueWithoutGameProjectInput[] + createMany?: Prisma.JobCreateManyGameProjectInputEnvelope + set?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + disconnect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + delete?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + update?: Prisma.JobUpdateWithWhereUniqueWithoutGameProjectInput | Prisma.JobUpdateWithWhereUniqueWithoutGameProjectInput[] + updateMany?: Prisma.JobUpdateManyWithWhereWithoutGameProjectInput | Prisma.JobUpdateManyWithWhereWithoutGameProjectInput[] + deleteMany?: Prisma.JobScalarWhereInput | Prisma.JobScalarWhereInput[] +} + +export type JobUncheckedUpdateManyWithoutProjectNestedInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutProjectInput[] | Prisma.JobUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutProjectInput | Prisma.JobCreateOrConnectWithoutProjectInput[] + upsert?: Prisma.JobUpsertWithWhereUniqueWithoutProjectInput | Prisma.JobUpsertWithWhereUniqueWithoutProjectInput[] + createMany?: Prisma.JobCreateManyProjectInputEnvelope + set?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + disconnect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + delete?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + update?: Prisma.JobUpdateWithWhereUniqueWithoutProjectInput | Prisma.JobUpdateWithWhereUniqueWithoutProjectInput[] + updateMany?: Prisma.JobUpdateManyWithWhereWithoutProjectInput | Prisma.JobUpdateManyWithWhereWithoutProjectInput[] + deleteMany?: Prisma.JobScalarWhereInput | Prisma.JobScalarWhereInput[] +} + +export type JobUncheckedUpdateManyWithoutGameProjectNestedInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutGameProjectInput[] | Prisma.JobUncheckedCreateWithoutGameProjectInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutGameProjectInput | Prisma.JobCreateOrConnectWithoutGameProjectInput[] + upsert?: Prisma.JobUpsertWithWhereUniqueWithoutGameProjectInput | Prisma.JobUpsertWithWhereUniqueWithoutGameProjectInput[] + createMany?: Prisma.JobCreateManyGameProjectInputEnvelope + set?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + disconnect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + delete?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + update?: Prisma.JobUpdateWithWhereUniqueWithoutGameProjectInput | Prisma.JobUpdateWithWhereUniqueWithoutGameProjectInput[] + updateMany?: Prisma.JobUpdateManyWithWhereWithoutGameProjectInput | Prisma.JobUpdateManyWithWhereWithoutGameProjectInput[] + deleteMany?: Prisma.JobScalarWhereInput | Prisma.JobScalarWhereInput[] +} + +export type JobCreateNestedManyWithoutGameVersionInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutGameVersionInput[] | Prisma.JobUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutGameVersionInput | Prisma.JobCreateOrConnectWithoutGameVersionInput[] + createMany?: Prisma.JobCreateManyGameVersionInputEnvelope + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] +} + +export type JobUncheckedCreateNestedManyWithoutGameVersionInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutGameVersionInput[] | Prisma.JobUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutGameVersionInput | Prisma.JobCreateOrConnectWithoutGameVersionInput[] + createMany?: Prisma.JobCreateManyGameVersionInputEnvelope + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] +} + +export type JobUpdateManyWithoutGameVersionNestedInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutGameVersionInput[] | Prisma.JobUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutGameVersionInput | Prisma.JobCreateOrConnectWithoutGameVersionInput[] + upsert?: Prisma.JobUpsertWithWhereUniqueWithoutGameVersionInput | Prisma.JobUpsertWithWhereUniqueWithoutGameVersionInput[] + createMany?: Prisma.JobCreateManyGameVersionInputEnvelope + set?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + disconnect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + delete?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + update?: Prisma.JobUpdateWithWhereUniqueWithoutGameVersionInput | Prisma.JobUpdateWithWhereUniqueWithoutGameVersionInput[] + updateMany?: Prisma.JobUpdateManyWithWhereWithoutGameVersionInput | Prisma.JobUpdateManyWithWhereWithoutGameVersionInput[] + deleteMany?: Prisma.JobScalarWhereInput | Prisma.JobScalarWhereInput[] +} + +export type JobUncheckedUpdateManyWithoutGameVersionNestedInput = { + create?: Prisma.XOR | Prisma.JobCreateWithoutGameVersionInput[] | Prisma.JobUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.JobCreateOrConnectWithoutGameVersionInput | Prisma.JobCreateOrConnectWithoutGameVersionInput[] + upsert?: Prisma.JobUpsertWithWhereUniqueWithoutGameVersionInput | Prisma.JobUpsertWithWhereUniqueWithoutGameVersionInput[] + createMany?: Prisma.JobCreateManyGameVersionInputEnvelope + set?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + disconnect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + delete?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + connect?: Prisma.JobWhereUniqueInput | Prisma.JobWhereUniqueInput[] + update?: Prisma.JobUpdateWithWhereUniqueWithoutGameVersionInput | Prisma.JobUpdateWithWhereUniqueWithoutGameVersionInput[] + updateMany?: Prisma.JobUpdateManyWithWhereWithoutGameVersionInput | Prisma.JobUpdateManyWithWhereWithoutGameVersionInput[] + deleteMany?: Prisma.JobScalarWhereInput | Prisma.JobScalarWhereInput[] +} + +export type EnumJobStatusFieldUpdateOperationsInput = { + set?: $Enums.JobStatus +} + +export type NullableDateTimeFieldUpdateOperationsInput = { + set?: Date | string | null +} + +export type EnumJobTargetTypeFieldUpdateOperationsInput = { + set?: $Enums.JobTargetType +} + +export type JobCreateWithoutActorInput = { + id: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + project: Prisma.GameProjectCreateNestedOneWithoutJobsInput + gameProject?: Prisma.GameProjectCreateNestedOneWithoutProjectTargetJobsInput + gameVersion?: Prisma.GameVersionCreateNestedOneWithoutVersionTargetJobsInput +} + +export type JobUncheckedCreateWithoutActorInput = { + id: string + projectId: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameProjectId?: string | null + gameVersionId?: string | null + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type JobCreateOrConnectWithoutActorInput = { + where: Prisma.JobWhereUniqueInput + create: Prisma.XOR +} + +export type JobCreateManyActorInputEnvelope = { + data: Prisma.JobCreateManyActorInput | Prisma.JobCreateManyActorInput[] + skipDuplicates?: boolean +} + +export type JobUpsertWithWhereUniqueWithoutActorInput = { + where: Prisma.JobWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type JobUpdateWithWhereUniqueWithoutActorInput = { + where: Prisma.JobWhereUniqueInput + data: Prisma.XOR +} + +export type JobUpdateManyWithWhereWithoutActorInput = { + where: Prisma.JobScalarWhereInput + data: Prisma.XOR +} + +export type JobScalarWhereInput = { + AND?: Prisma.JobScalarWhereInput | Prisma.JobScalarWhereInput[] + OR?: Prisma.JobScalarWhereInput[] + NOT?: Prisma.JobScalarWhereInput | Prisma.JobScalarWhereInput[] + id?: Prisma.StringFilter<"Job"> | string + actorId?: Prisma.StringFilter<"Job"> | string + projectId?: Prisma.StringFilter<"Job"> | string + type?: Prisma.StringFilter<"Job"> | string + idempotencyKey?: Prisma.StringFilter<"Job"> | string + status?: Prisma.EnumJobStatusFilter<"Job"> | $Enums.JobStatus + attempts?: Prisma.IntFilter<"Job"> | number + maxAttempts?: Prisma.IntFilter<"Job"> | number + timeoutAt?: Prisma.DateTimeNullableFilter<"Job"> | Date | string | null + nextRetryAt?: Prisma.DateTimeNullableFilter<"Job"> | Date | string | null + errorCode?: Prisma.StringNullableFilter<"Job"> | string | null + leaseToken?: Prisma.StringNullableFilter<"Job"> | string | null + leasedBy?: Prisma.StringNullableFilter<"Job"> | string | null + leaseExpiresAt?: Prisma.DateTimeNullableFilter<"Job"> | Date | string | null + lockVersion?: Prisma.IntFilter<"Job"> | number + targetType?: Prisma.EnumJobTargetTypeFilter<"Job"> | $Enums.JobTargetType + targetId?: Prisma.StringFilter<"Job"> | string + targetScopeKey?: Prisma.StringFilter<"Job"> | string + gameProjectId?: Prisma.StringNullableFilter<"Job"> | string | null + gameVersionId?: Prisma.StringNullableFilter<"Job"> | string | null + payloadJson?: Prisma.JsonFilter<"Job"> + createdAt?: Prisma.DateTimeFilter<"Job"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Job"> | Date | string +} + +export type JobCreateWithoutProjectInput = { + id: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + actor: Prisma.UserCreateNestedOneWithoutJobsInput + gameProject?: Prisma.GameProjectCreateNestedOneWithoutProjectTargetJobsInput + gameVersion?: Prisma.GameVersionCreateNestedOneWithoutVersionTargetJobsInput +} + +export type JobUncheckedCreateWithoutProjectInput = { + id: string + actorId: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameProjectId?: string | null + gameVersionId?: string | null + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type JobCreateOrConnectWithoutProjectInput = { + where: Prisma.JobWhereUniqueInput + create: Prisma.XOR +} + +export type JobCreateManyProjectInputEnvelope = { + data: Prisma.JobCreateManyProjectInput | Prisma.JobCreateManyProjectInput[] + skipDuplicates?: boolean +} + +export type JobCreateWithoutGameProjectInput = { + id: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + actor: Prisma.UserCreateNestedOneWithoutJobsInput + project: Prisma.GameProjectCreateNestedOneWithoutJobsInput + gameVersion?: Prisma.GameVersionCreateNestedOneWithoutVersionTargetJobsInput +} + +export type JobUncheckedCreateWithoutGameProjectInput = { + id: string + actorId: string + projectId: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameVersionId?: string | null + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type JobCreateOrConnectWithoutGameProjectInput = { + where: Prisma.JobWhereUniqueInput + create: Prisma.XOR +} + +export type JobCreateManyGameProjectInputEnvelope = { + data: Prisma.JobCreateManyGameProjectInput | Prisma.JobCreateManyGameProjectInput[] + skipDuplicates?: boolean +} + +export type JobUpsertWithWhereUniqueWithoutProjectInput = { + where: Prisma.JobWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type JobUpdateWithWhereUniqueWithoutProjectInput = { + where: Prisma.JobWhereUniqueInput + data: Prisma.XOR +} + +export type JobUpdateManyWithWhereWithoutProjectInput = { + where: Prisma.JobScalarWhereInput + data: Prisma.XOR +} + +export type JobUpsertWithWhereUniqueWithoutGameProjectInput = { + where: Prisma.JobWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type JobUpdateWithWhereUniqueWithoutGameProjectInput = { + where: Prisma.JobWhereUniqueInput + data: Prisma.XOR +} + +export type JobUpdateManyWithWhereWithoutGameProjectInput = { + where: Prisma.JobScalarWhereInput + data: Prisma.XOR +} + +export type JobCreateWithoutGameVersionInput = { + id: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string + actor: Prisma.UserCreateNestedOneWithoutJobsInput + project: Prisma.GameProjectCreateNestedOneWithoutJobsInput + gameProject?: Prisma.GameProjectCreateNestedOneWithoutProjectTargetJobsInput +} + +export type JobUncheckedCreateWithoutGameVersionInput = { + id: string + actorId: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameProjectId?: string | null + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type JobCreateOrConnectWithoutGameVersionInput = { + where: Prisma.JobWhereUniqueInput + create: Prisma.XOR +} + +export type JobCreateManyGameVersionInputEnvelope = { + data: Prisma.JobCreateManyGameVersionInput | Prisma.JobCreateManyGameVersionInput[] + skipDuplicates?: boolean +} + +export type JobUpsertWithWhereUniqueWithoutGameVersionInput = { + where: Prisma.JobWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type JobUpdateWithWhereUniqueWithoutGameVersionInput = { + where: Prisma.JobWhereUniqueInput + data: Prisma.XOR +} + +export type JobUpdateManyWithWhereWithoutGameVersionInput = { + where: Prisma.JobScalarWhereInput + data: Prisma.XOR +} + +export type JobCreateManyActorInput = { + id: string + projectId: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameProjectId?: string | null + gameVersionId?: string | null + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type JobUpdateWithoutActorInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + project?: Prisma.GameProjectUpdateOneRequiredWithoutJobsNestedInput + gameProject?: Prisma.GameProjectUpdateOneWithoutProjectTargetJobsNestedInput + gameVersion?: Prisma.GameVersionUpdateOneWithoutVersionTargetJobsNestedInput +} + +export type JobUncheckedUpdateWithoutActorInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + gameProjectId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + gameVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type JobUncheckedUpdateManyWithoutActorInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + gameProjectId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + gameVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type JobCreateManyProjectInput = { + id: string + actorId: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameProjectId?: string | null + gameVersionId?: string | null + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type JobCreateManyGameProjectInput = { + id: string + actorId: string + projectId: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameVersionId?: string | null + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type JobUpdateWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + actor?: Prisma.UserUpdateOneRequiredWithoutJobsNestedInput + gameProject?: Prisma.GameProjectUpdateOneWithoutProjectTargetJobsNestedInput + gameVersion?: Prisma.GameVersionUpdateOneWithoutVersionTargetJobsNestedInput +} + +export type JobUncheckedUpdateWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + actorId?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + gameProjectId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + gameVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type JobUncheckedUpdateManyWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + actorId?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + gameProjectId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + gameVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type JobUpdateWithoutGameProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + actor?: Prisma.UserUpdateOneRequiredWithoutJobsNestedInput + project?: Prisma.GameProjectUpdateOneRequiredWithoutJobsNestedInput + gameVersion?: Prisma.GameVersionUpdateOneWithoutVersionTargetJobsNestedInput +} + +export type JobUncheckedUpdateWithoutGameProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + actorId?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + gameVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type JobUncheckedUpdateManyWithoutGameProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + actorId?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + gameVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type JobCreateManyGameVersionInput = { + id: string + actorId: string + type: string + idempotencyKey: string + status?: $Enums.JobStatus + attempts?: number + maxAttempts?: number + timeoutAt?: Date | string | null + nextRetryAt?: Date | string | null + errorCode?: string | null + leaseToken?: string | null + leasedBy?: string | null + leaseExpiresAt?: Date | string | null + lockVersion?: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameProjectId?: string | null + payloadJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + updatedAt?: Date | string +} + +export type JobUpdateWithoutGameVersionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + actor?: Prisma.UserUpdateOneRequiredWithoutJobsNestedInput + project?: Prisma.GameProjectUpdateOneRequiredWithoutJobsNestedInput + gameProject?: Prisma.GameProjectUpdateOneWithoutProjectTargetJobsNestedInput +} + +export type JobUncheckedUpdateWithoutGameVersionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + actorId?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + gameProjectId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type JobUncheckedUpdateManyWithoutGameVersionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + actorId?: Prisma.StringFieldUpdateOperationsInput | string + type?: Prisma.StringFieldUpdateOperationsInput | string + idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumJobStatusFieldUpdateOperationsInput | $Enums.JobStatus + attempts?: Prisma.IntFieldUpdateOperationsInput | number + maxAttempts?: Prisma.IntFieldUpdateOperationsInput | number + timeoutAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + nextRetryAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseToken?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leasedBy?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + leaseExpiresAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lockVersion?: Prisma.IntFieldUpdateOperationsInput | number + targetType?: Prisma.EnumJobTargetTypeFieldUpdateOperationsInput | $Enums.JobTargetType + targetId?: Prisma.StringFieldUpdateOperationsInput | string + targetScopeKey?: Prisma.StringFieldUpdateOperationsInput | string + gameProjectId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + payloadJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + + +export type JobSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + actorId?: boolean + projectId?: boolean + type?: boolean + idempotencyKey?: boolean + status?: boolean + attempts?: boolean + maxAttempts?: boolean + timeoutAt?: boolean + nextRetryAt?: boolean + errorCode?: boolean + leaseToken?: boolean + leasedBy?: boolean + leaseExpiresAt?: boolean + lockVersion?: boolean + targetType?: boolean + targetId?: boolean + targetScopeKey?: boolean + gameProjectId?: boolean + gameVersionId?: boolean + payloadJson?: boolean + createdAt?: boolean + updatedAt?: boolean + actor?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + gameProject?: boolean | Prisma.Job$gameProjectArgs + gameVersion?: boolean | Prisma.Job$gameVersionArgs +}, ExtArgs["result"]["job"]> + +export type JobSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + actorId?: boolean + projectId?: boolean + type?: boolean + idempotencyKey?: boolean + status?: boolean + attempts?: boolean + maxAttempts?: boolean + timeoutAt?: boolean + nextRetryAt?: boolean + errorCode?: boolean + leaseToken?: boolean + leasedBy?: boolean + leaseExpiresAt?: boolean + lockVersion?: boolean + targetType?: boolean + targetId?: boolean + targetScopeKey?: boolean + gameProjectId?: boolean + gameVersionId?: boolean + payloadJson?: boolean + createdAt?: boolean + updatedAt?: boolean + actor?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + gameProject?: boolean | Prisma.Job$gameProjectArgs + gameVersion?: boolean | Prisma.Job$gameVersionArgs +}, ExtArgs["result"]["job"]> + +export type JobSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + actorId?: boolean + projectId?: boolean + type?: boolean + idempotencyKey?: boolean + status?: boolean + attempts?: boolean + maxAttempts?: boolean + timeoutAt?: boolean + nextRetryAt?: boolean + errorCode?: boolean + leaseToken?: boolean + leasedBy?: boolean + leaseExpiresAt?: boolean + lockVersion?: boolean + targetType?: boolean + targetId?: boolean + targetScopeKey?: boolean + gameProjectId?: boolean + gameVersionId?: boolean + payloadJson?: boolean + createdAt?: boolean + updatedAt?: boolean + actor?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + gameProject?: boolean | Prisma.Job$gameProjectArgs + gameVersion?: boolean | Prisma.Job$gameVersionArgs +}, ExtArgs["result"]["job"]> + +export type JobSelectScalar = { + id?: boolean + actorId?: boolean + projectId?: boolean + type?: boolean + idempotencyKey?: boolean + status?: boolean + attempts?: boolean + maxAttempts?: boolean + timeoutAt?: boolean + nextRetryAt?: boolean + errorCode?: boolean + leaseToken?: boolean + leasedBy?: boolean + leaseExpiresAt?: boolean + lockVersion?: boolean + targetType?: boolean + targetId?: boolean + targetScopeKey?: boolean + gameProjectId?: boolean + gameVersionId?: boolean + payloadJson?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type JobOmit = runtime.Types.Extensions.GetOmit<"id" | "actorId" | "projectId" | "type" | "idempotencyKey" | "status" | "attempts" | "maxAttempts" | "timeoutAt" | "nextRetryAt" | "errorCode" | "leaseToken" | "leasedBy" | "leaseExpiresAt" | "lockVersion" | "targetType" | "targetId" | "targetScopeKey" | "gameProjectId" | "gameVersionId" | "payloadJson" | "createdAt" | "updatedAt", ExtArgs["result"]["job"]> +export type JobInclude = { + actor?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + gameProject?: boolean | Prisma.Job$gameProjectArgs + gameVersion?: boolean | Prisma.Job$gameVersionArgs +} +export type JobIncludeCreateManyAndReturn = { + actor?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + gameProject?: boolean | Prisma.Job$gameProjectArgs + gameVersion?: boolean | Prisma.Job$gameVersionArgs +} +export type JobIncludeUpdateManyAndReturn = { + actor?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + gameProject?: boolean | Prisma.Job$gameProjectArgs + gameVersion?: boolean | Prisma.Job$gameVersionArgs +} + +export type $JobPayload = { + name: "Job" + objects: { + actor: Prisma.$UserPayload + project: Prisma.$GameProjectPayload + gameProject: Prisma.$GameProjectPayload | null + gameVersion: Prisma.$GameVersionPayload | null + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + actorId: string + projectId: string + type: string + idempotencyKey: string + status: $Enums.JobStatus + attempts: number + maxAttempts: number + timeoutAt: Date | null + nextRetryAt: Date | null + errorCode: string | null + leaseToken: string | null + leasedBy: string | null + leaseExpiresAt: Date | null + lockVersion: number + targetType: $Enums.JobTargetType + targetId: string + targetScopeKey: string + gameProjectId: string | null + gameVersionId: string | null + payloadJson: runtime.JsonValue + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["job"]> + composites: {} +} + +export type JobGetPayload = runtime.Types.Result.GetResult + +export type JobCountArgs = + Omit & { + select?: JobCountAggregateInputType | true + } + +export interface JobDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['Job'], meta: { name: 'Job' } } + /** + * Find zero or one Job that matches the filter. + * @param {JobFindUniqueArgs} args - Arguments to find a Job + * @example + * // Get one Job + * const job = await prisma.job.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__JobClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one Job that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {JobFindUniqueOrThrowArgs} args - Arguments to find a Job + * @example + * // Get one Job + * const job = await prisma.job.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__JobClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Job that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {JobFindFirstArgs} args - Arguments to find a Job + * @example + * // Get one Job + * const job = await prisma.job.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__JobClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Job that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {JobFindFirstOrThrowArgs} args - Arguments to find a Job + * @example + * // Get one Job + * const job = await prisma.job.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__JobClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Jobs that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {JobFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Jobs + * const jobs = await prisma.job.findMany() + * + * // Get first 10 Jobs + * const jobs = await prisma.job.findMany({ take: 10 }) + * + * // Only select the `id` + * const jobWithIdOnly = await prisma.job.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a Job. + * @param {JobCreateArgs} args - Arguments to create a Job. + * @example + * // Create one Job + * const Job = await prisma.job.create({ + * data: { + * // ... data to create a Job + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__JobClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Jobs. + * @param {JobCreateManyArgs} args - Arguments to create many Jobs. + * @example + * // Create many Jobs + * const job = await prisma.job.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Jobs and returns the data saved in the database. + * @param {JobCreateManyAndReturnArgs} args - Arguments to create many Jobs. + * @example + * // Create many Jobs + * const job = await prisma.job.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Jobs and only return the `id` + * const jobWithIdOnly = await prisma.job.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a Job. + * @param {JobDeleteArgs} args - Arguments to delete one Job. + * @example + * // Delete one Job + * const Job = await prisma.job.delete({ + * where: { + * // ... filter to delete one Job + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__JobClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one Job. + * @param {JobUpdateArgs} args - Arguments to update one Job. + * @example + * // Update one Job + * const job = await prisma.job.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__JobClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Jobs. + * @param {JobDeleteManyArgs} args - Arguments to filter Jobs to delete. + * @example + * // Delete a few Jobs + * const { count } = await prisma.job.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Jobs. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {JobUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Jobs + * const job = await prisma.job.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Jobs and returns the data updated in the database. + * @param {JobUpdateManyAndReturnArgs} args - Arguments to update many Jobs. + * @example + * // Update many Jobs + * const job = await prisma.job.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Jobs and only return the `id` + * const jobWithIdOnly = await prisma.job.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one Job. + * @param {JobUpsertArgs} args - Arguments to update or create a Job. + * @example + * // Update or create a Job + * const job = await prisma.job.upsert({ + * create: { + * // ... data to create a Job + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the Job we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__JobClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Jobs. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {JobCountArgs} args - Arguments to filter Jobs to count. + * @example + * // Count the number of Jobs + * const count = await prisma.job.count({ + * where: { + * // ... the filter for the Jobs we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a Job. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {JobAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by Job. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {JobGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends JobGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: JobGroupByArgs['orderBy'] } + : { orderBy?: JobGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetJobGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the Job model + */ +readonly fields: JobFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for Job. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__JobClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + actor = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + project = {}>(args?: Prisma.Subset>): Prisma.Prisma__GameProjectClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + gameProject = {}>(args?: Prisma.Subset>): Prisma.Prisma__GameProjectClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + gameVersion = {}>(args?: Prisma.Subset>): Prisma.Prisma__GameVersionClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the Job model + */ +export interface JobFieldRefs { + readonly id: Prisma.FieldRef<"Job", 'String'> + readonly actorId: Prisma.FieldRef<"Job", 'String'> + readonly projectId: Prisma.FieldRef<"Job", 'String'> + readonly type: Prisma.FieldRef<"Job", 'String'> + readonly idempotencyKey: Prisma.FieldRef<"Job", 'String'> + readonly status: Prisma.FieldRef<"Job", 'JobStatus'> + readonly attempts: Prisma.FieldRef<"Job", 'Int'> + readonly maxAttempts: Prisma.FieldRef<"Job", 'Int'> + readonly timeoutAt: Prisma.FieldRef<"Job", 'DateTime'> + readonly nextRetryAt: Prisma.FieldRef<"Job", 'DateTime'> + readonly errorCode: Prisma.FieldRef<"Job", 'String'> + readonly leaseToken: Prisma.FieldRef<"Job", 'String'> + readonly leasedBy: Prisma.FieldRef<"Job", 'String'> + readonly leaseExpiresAt: Prisma.FieldRef<"Job", 'DateTime'> + readonly lockVersion: Prisma.FieldRef<"Job", 'Int'> + readonly targetType: Prisma.FieldRef<"Job", 'JobTargetType'> + readonly targetId: Prisma.FieldRef<"Job", 'String'> + readonly targetScopeKey: Prisma.FieldRef<"Job", 'String'> + readonly gameProjectId: Prisma.FieldRef<"Job", 'String'> + readonly gameVersionId: Prisma.FieldRef<"Job", 'String'> + readonly payloadJson: Prisma.FieldRef<"Job", 'Json'> + readonly createdAt: Prisma.FieldRef<"Job", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"Job", 'DateTime'> +} + + +// Custom InputTypes +/** + * Job findUnique + */ +export type JobFindUniqueArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + /** + * Filter, which Job to fetch. + */ + where: Prisma.JobWhereUniqueInput +} + +/** + * Job findUniqueOrThrow + */ +export type JobFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + /** + * Filter, which Job to fetch. + */ + where: Prisma.JobWhereUniqueInput +} + +/** + * Job findFirst + */ +export type JobFindFirstArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + /** + * Filter, which Job to fetch. + */ + where?: Prisma.JobWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Jobs to fetch. + */ + orderBy?: Prisma.JobOrderByWithRelationInput | Prisma.JobOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Jobs. + */ + cursor?: Prisma.JobWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Jobs from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Jobs. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Jobs. + */ + distinct?: Prisma.JobScalarFieldEnum | Prisma.JobScalarFieldEnum[] +} + +/** + * Job findFirstOrThrow + */ +export type JobFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + /** + * Filter, which Job to fetch. + */ + where?: Prisma.JobWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Jobs to fetch. + */ + orderBy?: Prisma.JobOrderByWithRelationInput | Prisma.JobOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Jobs. + */ + cursor?: Prisma.JobWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Jobs from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Jobs. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Jobs. + */ + distinct?: Prisma.JobScalarFieldEnum | Prisma.JobScalarFieldEnum[] +} + +/** + * Job findMany + */ +export type JobFindManyArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + /** + * Filter, which Jobs to fetch. + */ + where?: Prisma.JobWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Jobs to fetch. + */ + orderBy?: Prisma.JobOrderByWithRelationInput | Prisma.JobOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Jobs. + */ + cursor?: Prisma.JobWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Jobs from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Jobs. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Jobs. + */ + distinct?: Prisma.JobScalarFieldEnum | Prisma.JobScalarFieldEnum[] +} + +/** + * Job create + */ +export type JobCreateArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + /** + * The data needed to create a Job. + */ + data: Prisma.XOR +} + +/** + * Job createMany + */ +export type JobCreateManyArgs = { + /** + * The data used to create many Jobs. + */ + data: Prisma.JobCreateManyInput | Prisma.JobCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * Job createManyAndReturn + */ +export type JobCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelectCreateManyAndReturn | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * The data used to create many Jobs. + */ + data: Prisma.JobCreateManyInput | Prisma.JobCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobIncludeCreateManyAndReturn | null +} + +/** + * Job update + */ +export type JobUpdateArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + /** + * The data needed to update a Job. + */ + data: Prisma.XOR + /** + * Choose, which Job to update. + */ + where: Prisma.JobWhereUniqueInput +} + +/** + * Job updateMany + */ +export type JobUpdateManyArgs = { + /** + * The data used to update Jobs. + */ + data: Prisma.XOR + /** + * Filter which Jobs to update + */ + where?: Prisma.JobWhereInput + /** + * Limit how many Jobs to update. + */ + limit?: number +} + +/** + * Job updateManyAndReturn + */ +export type JobUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * The data used to update Jobs. + */ + data: Prisma.XOR + /** + * Filter which Jobs to update + */ + where?: Prisma.JobWhereInput + /** + * Limit how many Jobs to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobIncludeUpdateManyAndReturn | null +} + +/** + * Job upsert + */ +export type JobUpsertArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + /** + * The filter to search for the Job to update in case it exists. + */ + where: Prisma.JobWhereUniqueInput + /** + * In case the Job found by the `where` argument doesn't exist, create a new Job with this data. + */ + create: Prisma.XOR + /** + * In case the Job was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * Job delete + */ +export type JobDeleteArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + /** + * Filter which Job to delete. + */ + where: Prisma.JobWhereUniqueInput +} + +/** + * Job deleteMany + */ +export type JobDeleteManyArgs = { + /** + * Filter which Jobs to delete + */ + where?: Prisma.JobWhereInput + /** + * Limit how many Jobs to delete. + */ + limit?: number +} + +/** + * Job.gameProject + */ +export type Job$gameProjectArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + where?: Prisma.GameProjectWhereInput +} + +/** + * Job.gameVersion + */ +export type Job$gameVersionArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + where?: Prisma.GameVersionWhereInput +} + +/** + * Job without action + */ +export type JobDefaultArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null +} diff --git a/apps/api/src/generated/prisma/models/LifecycleEvent.ts b/apps/api/src/generated/prisma/models/LifecycleEvent.ts new file mode 100644 index 00000000..fe9db5c8 --- /dev/null +++ b/apps/api/src/generated/prisma/models/LifecycleEvent.ts @@ -0,0 +1,1661 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `LifecycleEvent` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model LifecycleEvent + * + */ +export type LifecycleEventModel = runtime.Types.Result.DefaultSelection + +export type AggregateLifecycleEvent = { + _count: LifecycleEventCountAggregateOutputType | null + _min: LifecycleEventMinAggregateOutputType | null + _max: LifecycleEventMaxAggregateOutputType | null +} + +export type LifecycleEventMinAggregateOutputType = { + eventId: string | null + gameVersionId: string | null + event: string | null + from: string | null + to: string | null + requiredRole: string | null + auditEvent: string | null + reasonCode: string | null + occurredAt: Date | null + approval: string | null + createdAt: Date | null +} + +export type LifecycleEventMaxAggregateOutputType = { + eventId: string | null + gameVersionId: string | null + event: string | null + from: string | null + to: string | null + requiredRole: string | null + auditEvent: string | null + reasonCode: string | null + occurredAt: Date | null + approval: string | null + createdAt: Date | null +} + +export type LifecycleEventCountAggregateOutputType = { + eventId: number + gameVersionId: number + event: number + from: number + to: number + actorJson: number + requiredRole: number + requiredRecordRefsJson: number + auditEvent: number + reasonCode: number + occurredAt: number + approval: number + requiredRecordsJson: number + createdAt: number + _all: number +} + + +export type LifecycleEventMinAggregateInputType = { + eventId?: true + gameVersionId?: true + event?: true + from?: true + to?: true + requiredRole?: true + auditEvent?: true + reasonCode?: true + occurredAt?: true + approval?: true + createdAt?: true +} + +export type LifecycleEventMaxAggregateInputType = { + eventId?: true + gameVersionId?: true + event?: true + from?: true + to?: true + requiredRole?: true + auditEvent?: true + reasonCode?: true + occurredAt?: true + approval?: true + createdAt?: true +} + +export type LifecycleEventCountAggregateInputType = { + eventId?: true + gameVersionId?: true + event?: true + from?: true + to?: true + actorJson?: true + requiredRole?: true + requiredRecordRefsJson?: true + auditEvent?: true + reasonCode?: true + occurredAt?: true + approval?: true + requiredRecordsJson?: true + createdAt?: true + _all?: true +} + +export type LifecycleEventAggregateArgs = { + /** + * Filter which LifecycleEvent to aggregate. + */ + where?: Prisma.LifecycleEventWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of LifecycleEvents to fetch. + */ + orderBy?: Prisma.LifecycleEventOrderByWithRelationInput | Prisma.LifecycleEventOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.LifecycleEventWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` LifecycleEvents from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` LifecycleEvents. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned LifecycleEvents + **/ + _count?: true | LifecycleEventCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: LifecycleEventMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: LifecycleEventMaxAggregateInputType +} + +export type GetLifecycleEventAggregateType = { + [P in keyof T & keyof AggregateLifecycleEvent]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type LifecycleEventGroupByArgs = { + where?: Prisma.LifecycleEventWhereInput + orderBy?: Prisma.LifecycleEventOrderByWithAggregationInput | Prisma.LifecycleEventOrderByWithAggregationInput[] + by: Prisma.LifecycleEventScalarFieldEnum[] | Prisma.LifecycleEventScalarFieldEnum + having?: Prisma.LifecycleEventScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: LifecycleEventCountAggregateInputType | true + _min?: LifecycleEventMinAggregateInputType + _max?: LifecycleEventMaxAggregateInputType +} + +export type LifecycleEventGroupByOutputType = { + eventId: string + gameVersionId: string | null + event: string + from: string + to: string + actorJson: runtime.JsonValue + requiredRole: string + requiredRecordRefsJson: runtime.JsonValue + auditEvent: string + reasonCode: string + occurredAt: Date + approval: string + requiredRecordsJson: runtime.JsonValue + createdAt: Date + _count: LifecycleEventCountAggregateOutputType | null + _min: LifecycleEventMinAggregateOutputType | null + _max: LifecycleEventMaxAggregateOutputType | null +} + +export type GetLifecycleEventGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof LifecycleEventGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type LifecycleEventWhereInput = { + AND?: Prisma.LifecycleEventWhereInput | Prisma.LifecycleEventWhereInput[] + OR?: Prisma.LifecycleEventWhereInput[] + NOT?: Prisma.LifecycleEventWhereInput | Prisma.LifecycleEventWhereInput[] + eventId?: Prisma.StringFilter<"LifecycleEvent"> | string + gameVersionId?: Prisma.StringNullableFilter<"LifecycleEvent"> | string | null + event?: Prisma.StringFilter<"LifecycleEvent"> | string + from?: Prisma.StringFilter<"LifecycleEvent"> | string + to?: Prisma.StringFilter<"LifecycleEvent"> | string + actorJson?: Prisma.JsonFilter<"LifecycleEvent"> + requiredRole?: Prisma.StringFilter<"LifecycleEvent"> | string + requiredRecordRefsJson?: Prisma.JsonFilter<"LifecycleEvent"> + auditEvent?: Prisma.StringFilter<"LifecycleEvent"> | string + reasonCode?: Prisma.StringFilter<"LifecycleEvent"> | string + occurredAt?: Prisma.DateTimeFilter<"LifecycleEvent"> | Date | string + approval?: Prisma.StringFilter<"LifecycleEvent"> | string + requiredRecordsJson?: Prisma.JsonFilter<"LifecycleEvent"> + createdAt?: Prisma.DateTimeFilter<"LifecycleEvent"> | Date | string + gameVersion?: Prisma.XOR | null +} + +export type LifecycleEventOrderByWithRelationInput = { + eventId?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrderInput | Prisma.SortOrder + event?: Prisma.SortOrder + from?: Prisma.SortOrder + to?: Prisma.SortOrder + actorJson?: Prisma.SortOrder + requiredRole?: Prisma.SortOrder + requiredRecordRefsJson?: Prisma.SortOrder + auditEvent?: Prisma.SortOrder + reasonCode?: Prisma.SortOrder + occurredAt?: Prisma.SortOrder + approval?: Prisma.SortOrder + requiredRecordsJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + gameVersion?: Prisma.GameVersionOrderByWithRelationInput +} + +export type LifecycleEventWhereUniqueInput = Prisma.AtLeast<{ + eventId?: string + AND?: Prisma.LifecycleEventWhereInput | Prisma.LifecycleEventWhereInput[] + OR?: Prisma.LifecycleEventWhereInput[] + NOT?: Prisma.LifecycleEventWhereInput | Prisma.LifecycleEventWhereInput[] + gameVersionId?: Prisma.StringNullableFilter<"LifecycleEvent"> | string | null + event?: Prisma.StringFilter<"LifecycleEvent"> | string + from?: Prisma.StringFilter<"LifecycleEvent"> | string + to?: Prisma.StringFilter<"LifecycleEvent"> | string + actorJson?: Prisma.JsonFilter<"LifecycleEvent"> + requiredRole?: Prisma.StringFilter<"LifecycleEvent"> | string + requiredRecordRefsJson?: Prisma.JsonFilter<"LifecycleEvent"> + auditEvent?: Prisma.StringFilter<"LifecycleEvent"> | string + reasonCode?: Prisma.StringFilter<"LifecycleEvent"> | string + occurredAt?: Prisma.DateTimeFilter<"LifecycleEvent"> | Date | string + approval?: Prisma.StringFilter<"LifecycleEvent"> | string + requiredRecordsJson?: Prisma.JsonFilter<"LifecycleEvent"> + createdAt?: Prisma.DateTimeFilter<"LifecycleEvent"> | Date | string + gameVersion?: Prisma.XOR | null +}, "eventId"> + +export type LifecycleEventOrderByWithAggregationInput = { + eventId?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrderInput | Prisma.SortOrder + event?: Prisma.SortOrder + from?: Prisma.SortOrder + to?: Prisma.SortOrder + actorJson?: Prisma.SortOrder + requiredRole?: Prisma.SortOrder + requiredRecordRefsJson?: Prisma.SortOrder + auditEvent?: Prisma.SortOrder + reasonCode?: Prisma.SortOrder + occurredAt?: Prisma.SortOrder + approval?: Prisma.SortOrder + requiredRecordsJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + _count?: Prisma.LifecycleEventCountOrderByAggregateInput + _max?: Prisma.LifecycleEventMaxOrderByAggregateInput + _min?: Prisma.LifecycleEventMinOrderByAggregateInput +} + +export type LifecycleEventScalarWhereWithAggregatesInput = { + AND?: Prisma.LifecycleEventScalarWhereWithAggregatesInput | Prisma.LifecycleEventScalarWhereWithAggregatesInput[] + OR?: Prisma.LifecycleEventScalarWhereWithAggregatesInput[] + NOT?: Prisma.LifecycleEventScalarWhereWithAggregatesInput | Prisma.LifecycleEventScalarWhereWithAggregatesInput[] + eventId?: Prisma.StringWithAggregatesFilter<"LifecycleEvent"> | string + gameVersionId?: Prisma.StringNullableWithAggregatesFilter<"LifecycleEvent"> | string | null + event?: Prisma.StringWithAggregatesFilter<"LifecycleEvent"> | string + from?: Prisma.StringWithAggregatesFilter<"LifecycleEvent"> | string + to?: Prisma.StringWithAggregatesFilter<"LifecycleEvent"> | string + actorJson?: Prisma.JsonWithAggregatesFilter<"LifecycleEvent"> + requiredRole?: Prisma.StringWithAggregatesFilter<"LifecycleEvent"> | string + requiredRecordRefsJson?: Prisma.JsonWithAggregatesFilter<"LifecycleEvent"> + auditEvent?: Prisma.StringWithAggregatesFilter<"LifecycleEvent"> | string + reasonCode?: Prisma.StringWithAggregatesFilter<"LifecycleEvent"> | string + occurredAt?: Prisma.DateTimeWithAggregatesFilter<"LifecycleEvent"> | Date | string + approval?: Prisma.StringWithAggregatesFilter<"LifecycleEvent"> | string + requiredRecordsJson?: Prisma.JsonWithAggregatesFilter<"LifecycleEvent"> + createdAt?: Prisma.DateTimeWithAggregatesFilter<"LifecycleEvent"> | Date | string +} + +export type LifecycleEventCreateInput = { + eventId: string + event: string + from: string + to: string + actorJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole: string + requiredRecordRefsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent: string + reasonCode: string + occurredAt: Date | string + approval: string + requiredRecordsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string + gameVersion?: Prisma.GameVersionCreateNestedOneWithoutLifecycleEventsInput +} + +export type LifecycleEventUncheckedCreateInput = { + eventId: string + gameVersionId?: string | null + event: string + from: string + to: string + actorJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole: string + requiredRecordRefsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent: string + reasonCode: string + occurredAt: Date | string + approval: string + requiredRecordsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string +} + +export type LifecycleEventUpdateInput = { + eventId?: Prisma.StringFieldUpdateOperationsInput | string + event?: Prisma.StringFieldUpdateOperationsInput | string + from?: Prisma.StringFieldUpdateOperationsInput | string + to?: Prisma.StringFieldUpdateOperationsInput | string + actorJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordRefsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent?: Prisma.StringFieldUpdateOperationsInput | string + reasonCode?: Prisma.StringFieldUpdateOperationsInput | string + occurredAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + approval?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + gameVersion?: Prisma.GameVersionUpdateOneWithoutLifecycleEventsNestedInput +} + +export type LifecycleEventUncheckedUpdateInput = { + eventId?: Prisma.StringFieldUpdateOperationsInput | string + gameVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + event?: Prisma.StringFieldUpdateOperationsInput | string + from?: Prisma.StringFieldUpdateOperationsInput | string + to?: Prisma.StringFieldUpdateOperationsInput | string + actorJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordRefsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent?: Prisma.StringFieldUpdateOperationsInput | string + reasonCode?: Prisma.StringFieldUpdateOperationsInput | string + occurredAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + approval?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type LifecycleEventCreateManyInput = { + eventId: string + gameVersionId?: string | null + event: string + from: string + to: string + actorJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole: string + requiredRecordRefsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent: string + reasonCode: string + occurredAt: Date | string + approval: string + requiredRecordsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string +} + +export type LifecycleEventUpdateManyMutationInput = { + eventId?: Prisma.StringFieldUpdateOperationsInput | string + event?: Prisma.StringFieldUpdateOperationsInput | string + from?: Prisma.StringFieldUpdateOperationsInput | string + to?: Prisma.StringFieldUpdateOperationsInput | string + actorJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordRefsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent?: Prisma.StringFieldUpdateOperationsInput | string + reasonCode?: Prisma.StringFieldUpdateOperationsInput | string + occurredAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + approval?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type LifecycleEventUncheckedUpdateManyInput = { + eventId?: Prisma.StringFieldUpdateOperationsInput | string + gameVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + event?: Prisma.StringFieldUpdateOperationsInput | string + from?: Prisma.StringFieldUpdateOperationsInput | string + to?: Prisma.StringFieldUpdateOperationsInput | string + actorJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordRefsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent?: Prisma.StringFieldUpdateOperationsInput | string + reasonCode?: Prisma.StringFieldUpdateOperationsInput | string + occurredAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + approval?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type LifecycleEventListRelationFilter = { + every?: Prisma.LifecycleEventWhereInput + some?: Prisma.LifecycleEventWhereInput + none?: Prisma.LifecycleEventWhereInput +} + +export type LifecycleEventOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type LifecycleEventCountOrderByAggregateInput = { + eventId?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + event?: Prisma.SortOrder + from?: Prisma.SortOrder + to?: Prisma.SortOrder + actorJson?: Prisma.SortOrder + requiredRole?: Prisma.SortOrder + requiredRecordRefsJson?: Prisma.SortOrder + auditEvent?: Prisma.SortOrder + reasonCode?: Prisma.SortOrder + occurredAt?: Prisma.SortOrder + approval?: Prisma.SortOrder + requiredRecordsJson?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type LifecycleEventMaxOrderByAggregateInput = { + eventId?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + event?: Prisma.SortOrder + from?: Prisma.SortOrder + to?: Prisma.SortOrder + requiredRole?: Prisma.SortOrder + auditEvent?: Prisma.SortOrder + reasonCode?: Prisma.SortOrder + occurredAt?: Prisma.SortOrder + approval?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type LifecycleEventMinOrderByAggregateInput = { + eventId?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + event?: Prisma.SortOrder + from?: Prisma.SortOrder + to?: Prisma.SortOrder + requiredRole?: Prisma.SortOrder + auditEvent?: Prisma.SortOrder + reasonCode?: Prisma.SortOrder + occurredAt?: Prisma.SortOrder + approval?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type LifecycleEventCreateNestedManyWithoutGameVersionInput = { + create?: Prisma.XOR | Prisma.LifecycleEventCreateWithoutGameVersionInput[] | Prisma.LifecycleEventUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.LifecycleEventCreateOrConnectWithoutGameVersionInput | Prisma.LifecycleEventCreateOrConnectWithoutGameVersionInput[] + createMany?: Prisma.LifecycleEventCreateManyGameVersionInputEnvelope + connect?: Prisma.LifecycleEventWhereUniqueInput | Prisma.LifecycleEventWhereUniqueInput[] +} + +export type LifecycleEventUncheckedCreateNestedManyWithoutGameVersionInput = { + create?: Prisma.XOR | Prisma.LifecycleEventCreateWithoutGameVersionInput[] | Prisma.LifecycleEventUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.LifecycleEventCreateOrConnectWithoutGameVersionInput | Prisma.LifecycleEventCreateOrConnectWithoutGameVersionInput[] + createMany?: Prisma.LifecycleEventCreateManyGameVersionInputEnvelope + connect?: Prisma.LifecycleEventWhereUniqueInput | Prisma.LifecycleEventWhereUniqueInput[] +} + +export type LifecycleEventUpdateManyWithoutGameVersionNestedInput = { + create?: Prisma.XOR | Prisma.LifecycleEventCreateWithoutGameVersionInput[] | Prisma.LifecycleEventUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.LifecycleEventCreateOrConnectWithoutGameVersionInput | Prisma.LifecycleEventCreateOrConnectWithoutGameVersionInput[] + upsert?: Prisma.LifecycleEventUpsertWithWhereUniqueWithoutGameVersionInput | Prisma.LifecycleEventUpsertWithWhereUniqueWithoutGameVersionInput[] + createMany?: Prisma.LifecycleEventCreateManyGameVersionInputEnvelope + set?: Prisma.LifecycleEventWhereUniqueInput | Prisma.LifecycleEventWhereUniqueInput[] + disconnect?: Prisma.LifecycleEventWhereUniqueInput | Prisma.LifecycleEventWhereUniqueInput[] + delete?: Prisma.LifecycleEventWhereUniqueInput | Prisma.LifecycleEventWhereUniqueInput[] + connect?: Prisma.LifecycleEventWhereUniqueInput | Prisma.LifecycleEventWhereUniqueInput[] + update?: Prisma.LifecycleEventUpdateWithWhereUniqueWithoutGameVersionInput | Prisma.LifecycleEventUpdateWithWhereUniqueWithoutGameVersionInput[] + updateMany?: Prisma.LifecycleEventUpdateManyWithWhereWithoutGameVersionInput | Prisma.LifecycleEventUpdateManyWithWhereWithoutGameVersionInput[] + deleteMany?: Prisma.LifecycleEventScalarWhereInput | Prisma.LifecycleEventScalarWhereInput[] +} + +export type LifecycleEventUncheckedUpdateManyWithoutGameVersionNestedInput = { + create?: Prisma.XOR | Prisma.LifecycleEventCreateWithoutGameVersionInput[] | Prisma.LifecycleEventUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.LifecycleEventCreateOrConnectWithoutGameVersionInput | Prisma.LifecycleEventCreateOrConnectWithoutGameVersionInput[] + upsert?: Prisma.LifecycleEventUpsertWithWhereUniqueWithoutGameVersionInput | Prisma.LifecycleEventUpsertWithWhereUniqueWithoutGameVersionInput[] + createMany?: Prisma.LifecycleEventCreateManyGameVersionInputEnvelope + set?: Prisma.LifecycleEventWhereUniqueInput | Prisma.LifecycleEventWhereUniqueInput[] + disconnect?: Prisma.LifecycleEventWhereUniqueInput | Prisma.LifecycleEventWhereUniqueInput[] + delete?: Prisma.LifecycleEventWhereUniqueInput | Prisma.LifecycleEventWhereUniqueInput[] + connect?: Prisma.LifecycleEventWhereUniqueInput | Prisma.LifecycleEventWhereUniqueInput[] + update?: Prisma.LifecycleEventUpdateWithWhereUniqueWithoutGameVersionInput | Prisma.LifecycleEventUpdateWithWhereUniqueWithoutGameVersionInput[] + updateMany?: Prisma.LifecycleEventUpdateManyWithWhereWithoutGameVersionInput | Prisma.LifecycleEventUpdateManyWithWhereWithoutGameVersionInput[] + deleteMany?: Prisma.LifecycleEventScalarWhereInput | Prisma.LifecycleEventScalarWhereInput[] +} + +export type LifecycleEventCreateWithoutGameVersionInput = { + eventId: string + event: string + from: string + to: string + actorJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole: string + requiredRecordRefsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent: string + reasonCode: string + occurredAt: Date | string + approval: string + requiredRecordsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string +} + +export type LifecycleEventUncheckedCreateWithoutGameVersionInput = { + eventId: string + event: string + from: string + to: string + actorJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole: string + requiredRecordRefsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent: string + reasonCode: string + occurredAt: Date | string + approval: string + requiredRecordsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string +} + +export type LifecycleEventCreateOrConnectWithoutGameVersionInput = { + where: Prisma.LifecycleEventWhereUniqueInput + create: Prisma.XOR +} + +export type LifecycleEventCreateManyGameVersionInputEnvelope = { + data: Prisma.LifecycleEventCreateManyGameVersionInput | Prisma.LifecycleEventCreateManyGameVersionInput[] + skipDuplicates?: boolean +} + +export type LifecycleEventUpsertWithWhereUniqueWithoutGameVersionInput = { + where: Prisma.LifecycleEventWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type LifecycleEventUpdateWithWhereUniqueWithoutGameVersionInput = { + where: Prisma.LifecycleEventWhereUniqueInput + data: Prisma.XOR +} + +export type LifecycleEventUpdateManyWithWhereWithoutGameVersionInput = { + where: Prisma.LifecycleEventScalarWhereInput + data: Prisma.XOR +} + +export type LifecycleEventScalarWhereInput = { + AND?: Prisma.LifecycleEventScalarWhereInput | Prisma.LifecycleEventScalarWhereInput[] + OR?: Prisma.LifecycleEventScalarWhereInput[] + NOT?: Prisma.LifecycleEventScalarWhereInput | Prisma.LifecycleEventScalarWhereInput[] + eventId?: Prisma.StringFilter<"LifecycleEvent"> | string + gameVersionId?: Prisma.StringNullableFilter<"LifecycleEvent"> | string | null + event?: Prisma.StringFilter<"LifecycleEvent"> | string + from?: Prisma.StringFilter<"LifecycleEvent"> | string + to?: Prisma.StringFilter<"LifecycleEvent"> | string + actorJson?: Prisma.JsonFilter<"LifecycleEvent"> + requiredRole?: Prisma.StringFilter<"LifecycleEvent"> | string + requiredRecordRefsJson?: Prisma.JsonFilter<"LifecycleEvent"> + auditEvent?: Prisma.StringFilter<"LifecycleEvent"> | string + reasonCode?: Prisma.StringFilter<"LifecycleEvent"> | string + occurredAt?: Prisma.DateTimeFilter<"LifecycleEvent"> | Date | string + approval?: Prisma.StringFilter<"LifecycleEvent"> | string + requiredRecordsJson?: Prisma.JsonFilter<"LifecycleEvent"> + createdAt?: Prisma.DateTimeFilter<"LifecycleEvent"> | Date | string +} + +export type LifecycleEventCreateManyGameVersionInput = { + eventId: string + event: string + from: string + to: string + actorJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole: string + requiredRecordRefsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent: string + reasonCode: string + occurredAt: Date | string + approval: string + requiredRecordsJson: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Date | string +} + +export type LifecycleEventUpdateWithoutGameVersionInput = { + eventId?: Prisma.StringFieldUpdateOperationsInput | string + event?: Prisma.StringFieldUpdateOperationsInput | string + from?: Prisma.StringFieldUpdateOperationsInput | string + to?: Prisma.StringFieldUpdateOperationsInput | string + actorJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordRefsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent?: Prisma.StringFieldUpdateOperationsInput | string + reasonCode?: Prisma.StringFieldUpdateOperationsInput | string + occurredAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + approval?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type LifecycleEventUncheckedUpdateWithoutGameVersionInput = { + eventId?: Prisma.StringFieldUpdateOperationsInput | string + event?: Prisma.StringFieldUpdateOperationsInput | string + from?: Prisma.StringFieldUpdateOperationsInput | string + to?: Prisma.StringFieldUpdateOperationsInput | string + actorJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordRefsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent?: Prisma.StringFieldUpdateOperationsInput | string + reasonCode?: Prisma.StringFieldUpdateOperationsInput | string + occurredAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + approval?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type LifecycleEventUncheckedUpdateManyWithoutGameVersionInput = { + eventId?: Prisma.StringFieldUpdateOperationsInput | string + event?: Prisma.StringFieldUpdateOperationsInput | string + from?: Prisma.StringFieldUpdateOperationsInput | string + to?: Prisma.StringFieldUpdateOperationsInput | string + actorJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + requiredRole?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordRefsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + auditEvent?: Prisma.StringFieldUpdateOperationsInput | string + reasonCode?: Prisma.StringFieldUpdateOperationsInput | string + occurredAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + approval?: Prisma.StringFieldUpdateOperationsInput | string + requiredRecordsJson?: Prisma.JsonNullValueInput | runtime.InputJsonValue + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + + +export type LifecycleEventSelect = runtime.Types.Extensions.GetSelect<{ + eventId?: boolean + gameVersionId?: boolean + event?: boolean + from?: boolean + to?: boolean + actorJson?: boolean + requiredRole?: boolean + requiredRecordRefsJson?: boolean + auditEvent?: boolean + reasonCode?: boolean + occurredAt?: boolean + approval?: boolean + requiredRecordsJson?: boolean + createdAt?: boolean + gameVersion?: boolean | Prisma.LifecycleEvent$gameVersionArgs +}, ExtArgs["result"]["lifecycleEvent"]> + +export type LifecycleEventSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + eventId?: boolean + gameVersionId?: boolean + event?: boolean + from?: boolean + to?: boolean + actorJson?: boolean + requiredRole?: boolean + requiredRecordRefsJson?: boolean + auditEvent?: boolean + reasonCode?: boolean + occurredAt?: boolean + approval?: boolean + requiredRecordsJson?: boolean + createdAt?: boolean + gameVersion?: boolean | Prisma.LifecycleEvent$gameVersionArgs +}, ExtArgs["result"]["lifecycleEvent"]> + +export type LifecycleEventSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + eventId?: boolean + gameVersionId?: boolean + event?: boolean + from?: boolean + to?: boolean + actorJson?: boolean + requiredRole?: boolean + requiredRecordRefsJson?: boolean + auditEvent?: boolean + reasonCode?: boolean + occurredAt?: boolean + approval?: boolean + requiredRecordsJson?: boolean + createdAt?: boolean + gameVersion?: boolean | Prisma.LifecycleEvent$gameVersionArgs +}, ExtArgs["result"]["lifecycleEvent"]> + +export type LifecycleEventSelectScalar = { + eventId?: boolean + gameVersionId?: boolean + event?: boolean + from?: boolean + to?: boolean + actorJson?: boolean + requiredRole?: boolean + requiredRecordRefsJson?: boolean + auditEvent?: boolean + reasonCode?: boolean + occurredAt?: boolean + approval?: boolean + requiredRecordsJson?: boolean + createdAt?: boolean +} + +export type LifecycleEventOmit = runtime.Types.Extensions.GetOmit<"eventId" | "gameVersionId" | "event" | "from" | "to" | "actorJson" | "requiredRole" | "requiredRecordRefsJson" | "auditEvent" | "reasonCode" | "occurredAt" | "approval" | "requiredRecordsJson" | "createdAt", ExtArgs["result"]["lifecycleEvent"]> +export type LifecycleEventInclude = { + gameVersion?: boolean | Prisma.LifecycleEvent$gameVersionArgs +} +export type LifecycleEventIncludeCreateManyAndReturn = { + gameVersion?: boolean | Prisma.LifecycleEvent$gameVersionArgs +} +export type LifecycleEventIncludeUpdateManyAndReturn = { + gameVersion?: boolean | Prisma.LifecycleEvent$gameVersionArgs +} + +export type $LifecycleEventPayload = { + name: "LifecycleEvent" + objects: { + gameVersion: Prisma.$GameVersionPayload | null + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + eventId: string + gameVersionId: string | null + event: string + from: string + to: string + actorJson: runtime.JsonValue + requiredRole: string + requiredRecordRefsJson: runtime.JsonValue + auditEvent: string + reasonCode: string + occurredAt: Date + approval: string + requiredRecordsJson: runtime.JsonValue + createdAt: Date + }, ExtArgs["result"]["lifecycleEvent"]> + composites: {} +} + +export type LifecycleEventGetPayload = runtime.Types.Result.GetResult + +export type LifecycleEventCountArgs = + Omit & { + select?: LifecycleEventCountAggregateInputType | true + } + +export interface LifecycleEventDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['LifecycleEvent'], meta: { name: 'LifecycleEvent' } } + /** + * Find zero or one LifecycleEvent that matches the filter. + * @param {LifecycleEventFindUniqueArgs} args - Arguments to find a LifecycleEvent + * @example + * // Get one LifecycleEvent + * const lifecycleEvent = await prisma.lifecycleEvent.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__LifecycleEventClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one LifecycleEvent that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {LifecycleEventFindUniqueOrThrowArgs} args - Arguments to find a LifecycleEvent + * @example + * // Get one LifecycleEvent + * const lifecycleEvent = await prisma.lifecycleEvent.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__LifecycleEventClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first LifecycleEvent that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {LifecycleEventFindFirstArgs} args - Arguments to find a LifecycleEvent + * @example + * // Get one LifecycleEvent + * const lifecycleEvent = await prisma.lifecycleEvent.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__LifecycleEventClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first LifecycleEvent that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {LifecycleEventFindFirstOrThrowArgs} args - Arguments to find a LifecycleEvent + * @example + * // Get one LifecycleEvent + * const lifecycleEvent = await prisma.lifecycleEvent.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__LifecycleEventClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more LifecycleEvents that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {LifecycleEventFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all LifecycleEvents + * const lifecycleEvents = await prisma.lifecycleEvent.findMany() + * + * // Get first 10 LifecycleEvents + * const lifecycleEvents = await prisma.lifecycleEvent.findMany({ take: 10 }) + * + * // Only select the `eventId` + * const lifecycleEventWithEventIdOnly = await prisma.lifecycleEvent.findMany({ select: { eventId: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a LifecycleEvent. + * @param {LifecycleEventCreateArgs} args - Arguments to create a LifecycleEvent. + * @example + * // Create one LifecycleEvent + * const LifecycleEvent = await prisma.lifecycleEvent.create({ + * data: { + * // ... data to create a LifecycleEvent + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__LifecycleEventClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many LifecycleEvents. + * @param {LifecycleEventCreateManyArgs} args - Arguments to create many LifecycleEvents. + * @example + * // Create many LifecycleEvents + * const lifecycleEvent = await prisma.lifecycleEvent.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many LifecycleEvents and returns the data saved in the database. + * @param {LifecycleEventCreateManyAndReturnArgs} args - Arguments to create many LifecycleEvents. + * @example + * // Create many LifecycleEvents + * const lifecycleEvent = await prisma.lifecycleEvent.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many LifecycleEvents and only return the `eventId` + * const lifecycleEventWithEventIdOnly = await prisma.lifecycleEvent.createManyAndReturn({ + * select: { eventId: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a LifecycleEvent. + * @param {LifecycleEventDeleteArgs} args - Arguments to delete one LifecycleEvent. + * @example + * // Delete one LifecycleEvent + * const LifecycleEvent = await prisma.lifecycleEvent.delete({ + * where: { + * // ... filter to delete one LifecycleEvent + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__LifecycleEventClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one LifecycleEvent. + * @param {LifecycleEventUpdateArgs} args - Arguments to update one LifecycleEvent. + * @example + * // Update one LifecycleEvent + * const lifecycleEvent = await prisma.lifecycleEvent.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__LifecycleEventClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more LifecycleEvents. + * @param {LifecycleEventDeleteManyArgs} args - Arguments to filter LifecycleEvents to delete. + * @example + * // Delete a few LifecycleEvents + * const { count } = await prisma.lifecycleEvent.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more LifecycleEvents. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {LifecycleEventUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many LifecycleEvents + * const lifecycleEvent = await prisma.lifecycleEvent.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more LifecycleEvents and returns the data updated in the database. + * @param {LifecycleEventUpdateManyAndReturnArgs} args - Arguments to update many LifecycleEvents. + * @example + * // Update many LifecycleEvents + * const lifecycleEvent = await prisma.lifecycleEvent.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more LifecycleEvents and only return the `eventId` + * const lifecycleEventWithEventIdOnly = await prisma.lifecycleEvent.updateManyAndReturn({ + * select: { eventId: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one LifecycleEvent. + * @param {LifecycleEventUpsertArgs} args - Arguments to update or create a LifecycleEvent. + * @example + * // Update or create a LifecycleEvent + * const lifecycleEvent = await prisma.lifecycleEvent.upsert({ + * create: { + * // ... data to create a LifecycleEvent + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the LifecycleEvent we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__LifecycleEventClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of LifecycleEvents. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {LifecycleEventCountArgs} args - Arguments to filter LifecycleEvents to count. + * @example + * // Count the number of LifecycleEvents + * const count = await prisma.lifecycleEvent.count({ + * where: { + * // ... the filter for the LifecycleEvents we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a LifecycleEvent. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {LifecycleEventAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by LifecycleEvent. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {LifecycleEventGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends LifecycleEventGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: LifecycleEventGroupByArgs['orderBy'] } + : { orderBy?: LifecycleEventGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetLifecycleEventGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the LifecycleEvent model + */ +readonly fields: LifecycleEventFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for LifecycleEvent. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__LifecycleEventClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + gameVersion = {}>(args?: Prisma.Subset>): Prisma.Prisma__GameVersionClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the LifecycleEvent model + */ +export interface LifecycleEventFieldRefs { + readonly eventId: Prisma.FieldRef<"LifecycleEvent", 'String'> + readonly gameVersionId: Prisma.FieldRef<"LifecycleEvent", 'String'> + readonly event: Prisma.FieldRef<"LifecycleEvent", 'String'> + readonly from: Prisma.FieldRef<"LifecycleEvent", 'String'> + readonly to: Prisma.FieldRef<"LifecycleEvent", 'String'> + readonly actorJson: Prisma.FieldRef<"LifecycleEvent", 'Json'> + readonly requiredRole: Prisma.FieldRef<"LifecycleEvent", 'String'> + readonly requiredRecordRefsJson: Prisma.FieldRef<"LifecycleEvent", 'Json'> + readonly auditEvent: Prisma.FieldRef<"LifecycleEvent", 'String'> + readonly reasonCode: Prisma.FieldRef<"LifecycleEvent", 'String'> + readonly occurredAt: Prisma.FieldRef<"LifecycleEvent", 'DateTime'> + readonly approval: Prisma.FieldRef<"LifecycleEvent", 'String'> + readonly requiredRecordsJson: Prisma.FieldRef<"LifecycleEvent", 'Json'> + readonly createdAt: Prisma.FieldRef<"LifecycleEvent", 'DateTime'> +} + + +// Custom InputTypes +/** + * LifecycleEvent findUnique + */ +export type LifecycleEventFindUniqueArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null + /** + * Filter, which LifecycleEvent to fetch. + */ + where: Prisma.LifecycleEventWhereUniqueInput +} + +/** + * LifecycleEvent findUniqueOrThrow + */ +export type LifecycleEventFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null + /** + * Filter, which LifecycleEvent to fetch. + */ + where: Prisma.LifecycleEventWhereUniqueInput +} + +/** + * LifecycleEvent findFirst + */ +export type LifecycleEventFindFirstArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null + /** + * Filter, which LifecycleEvent to fetch. + */ + where?: Prisma.LifecycleEventWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of LifecycleEvents to fetch. + */ + orderBy?: Prisma.LifecycleEventOrderByWithRelationInput | Prisma.LifecycleEventOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for LifecycleEvents. + */ + cursor?: Prisma.LifecycleEventWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` LifecycleEvents from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` LifecycleEvents. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of LifecycleEvents. + */ + distinct?: Prisma.LifecycleEventScalarFieldEnum | Prisma.LifecycleEventScalarFieldEnum[] +} + +/** + * LifecycleEvent findFirstOrThrow + */ +export type LifecycleEventFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null + /** + * Filter, which LifecycleEvent to fetch. + */ + where?: Prisma.LifecycleEventWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of LifecycleEvents to fetch. + */ + orderBy?: Prisma.LifecycleEventOrderByWithRelationInput | Prisma.LifecycleEventOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for LifecycleEvents. + */ + cursor?: Prisma.LifecycleEventWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` LifecycleEvents from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` LifecycleEvents. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of LifecycleEvents. + */ + distinct?: Prisma.LifecycleEventScalarFieldEnum | Prisma.LifecycleEventScalarFieldEnum[] +} + +/** + * LifecycleEvent findMany + */ +export type LifecycleEventFindManyArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null + /** + * Filter, which LifecycleEvents to fetch. + */ + where?: Prisma.LifecycleEventWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of LifecycleEvents to fetch. + */ + orderBy?: Prisma.LifecycleEventOrderByWithRelationInput | Prisma.LifecycleEventOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing LifecycleEvents. + */ + cursor?: Prisma.LifecycleEventWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` LifecycleEvents from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` LifecycleEvents. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of LifecycleEvents. + */ + distinct?: Prisma.LifecycleEventScalarFieldEnum | Prisma.LifecycleEventScalarFieldEnum[] +} + +/** + * LifecycleEvent create + */ +export type LifecycleEventCreateArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null + /** + * The data needed to create a LifecycleEvent. + */ + data: Prisma.XOR +} + +/** + * LifecycleEvent createMany + */ +export type LifecycleEventCreateManyArgs = { + /** + * The data used to create many LifecycleEvents. + */ + data: Prisma.LifecycleEventCreateManyInput | Prisma.LifecycleEventCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * LifecycleEvent createManyAndReturn + */ +export type LifecycleEventCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelectCreateManyAndReturn | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * The data used to create many LifecycleEvents. + */ + data: Prisma.LifecycleEventCreateManyInput | Prisma.LifecycleEventCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventIncludeCreateManyAndReturn | null +} + +/** + * LifecycleEvent update + */ +export type LifecycleEventUpdateArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null + /** + * The data needed to update a LifecycleEvent. + */ + data: Prisma.XOR + /** + * Choose, which LifecycleEvent to update. + */ + where: Prisma.LifecycleEventWhereUniqueInput +} + +/** + * LifecycleEvent updateMany + */ +export type LifecycleEventUpdateManyArgs = { + /** + * The data used to update LifecycleEvents. + */ + data: Prisma.XOR + /** + * Filter which LifecycleEvents to update + */ + where?: Prisma.LifecycleEventWhereInput + /** + * Limit how many LifecycleEvents to update. + */ + limit?: number +} + +/** + * LifecycleEvent updateManyAndReturn + */ +export type LifecycleEventUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * The data used to update LifecycleEvents. + */ + data: Prisma.XOR + /** + * Filter which LifecycleEvents to update + */ + where?: Prisma.LifecycleEventWhereInput + /** + * Limit how many LifecycleEvents to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventIncludeUpdateManyAndReturn | null +} + +/** + * LifecycleEvent upsert + */ +export type LifecycleEventUpsertArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null + /** + * The filter to search for the LifecycleEvent to update in case it exists. + */ + where: Prisma.LifecycleEventWhereUniqueInput + /** + * In case the LifecycleEvent found by the `where` argument doesn't exist, create a new LifecycleEvent with this data. + */ + create: Prisma.XOR + /** + * In case the LifecycleEvent was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * LifecycleEvent delete + */ +export type LifecycleEventDeleteArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null + /** + * Filter which LifecycleEvent to delete. + */ + where: Prisma.LifecycleEventWhereUniqueInput +} + +/** + * LifecycleEvent deleteMany + */ +export type LifecycleEventDeleteManyArgs = { + /** + * Filter which LifecycleEvents to delete + */ + where?: Prisma.LifecycleEventWhereInput + /** + * Limit how many LifecycleEvents to delete. + */ + limit?: number +} + +/** + * LifecycleEvent.gameVersion + */ +export type LifecycleEvent$gameVersionArgs = { + /** + * Select specific fields to fetch from the GameVersion + */ + select?: Prisma.GameVersionSelect | null + /** + * Omit specific fields from the GameVersion + */ + omit?: Prisma.GameVersionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameVersionInclude | null + where?: Prisma.GameVersionWhereInput +} + +/** + * LifecycleEvent without action + */ +export type LifecycleEventDefaultArgs = { + /** + * Select specific fields to fetch from the LifecycleEvent + */ + select?: Prisma.LifecycleEventSelect | null + /** + * Omit specific fields from the LifecycleEvent + */ + omit?: Prisma.LifecycleEventOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.LifecycleEventInclude | null +} diff --git a/apps/api/src/generated/prisma/models/MainCreationAgentSession.ts b/apps/api/src/generated/prisma/models/MainCreationAgentSession.ts new file mode 100644 index 00000000..ef251b47 --- /dev/null +++ b/apps/api/src/generated/prisma/models/MainCreationAgentSession.ts @@ -0,0 +1,1883 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `MainCreationAgentSession` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model MainCreationAgentSession + * + */ +export type MainCreationAgentSessionModel = runtime.Types.Result.DefaultSelection + +export type AggregateMainCreationAgentSession = { + _count: MainCreationAgentSessionCountAggregateOutputType | null + _min: MainCreationAgentSessionMinAggregateOutputType | null + _max: MainCreationAgentSessionMaxAggregateOutputType | null +} + +export type MainCreationAgentSessionMinAggregateOutputType = { + id: string | null + creatorId: string | null + projectId: string | null + versionId: string | null + status: $Enums.MainCreationAgentSessionStatus | null + contextSummary: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type MainCreationAgentSessionMaxAggregateOutputType = { + id: string | null + creatorId: string | null + projectId: string | null + versionId: string | null + status: $Enums.MainCreationAgentSessionStatus | null + contextSummary: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type MainCreationAgentSessionCountAggregateOutputType = { + id: number + creatorId: number + projectId: number + versionId: number + status: number + contextSummary: number + createdAt: number + updatedAt: number + _all: number +} + + +export type MainCreationAgentSessionMinAggregateInputType = { + id?: true + creatorId?: true + projectId?: true + versionId?: true + status?: true + contextSummary?: true + createdAt?: true + updatedAt?: true +} + +export type MainCreationAgentSessionMaxAggregateInputType = { + id?: true + creatorId?: true + projectId?: true + versionId?: true + status?: true + contextSummary?: true + createdAt?: true + updatedAt?: true +} + +export type MainCreationAgentSessionCountAggregateInputType = { + id?: true + creatorId?: true + projectId?: true + versionId?: true + status?: true + contextSummary?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type MainCreationAgentSessionAggregateArgs = { + /** + * Filter which MainCreationAgentSession to aggregate. + */ + where?: Prisma.MainCreationAgentSessionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of MainCreationAgentSessions to fetch. + */ + orderBy?: Prisma.MainCreationAgentSessionOrderByWithRelationInput | Prisma.MainCreationAgentSessionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.MainCreationAgentSessionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` MainCreationAgentSessions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` MainCreationAgentSessions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned MainCreationAgentSessions + **/ + _count?: true | MainCreationAgentSessionCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: MainCreationAgentSessionMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: MainCreationAgentSessionMaxAggregateInputType +} + +export type GetMainCreationAgentSessionAggregateType = { + [P in keyof T & keyof AggregateMainCreationAgentSession]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type MainCreationAgentSessionGroupByArgs = { + where?: Prisma.MainCreationAgentSessionWhereInput + orderBy?: Prisma.MainCreationAgentSessionOrderByWithAggregationInput | Prisma.MainCreationAgentSessionOrderByWithAggregationInput[] + by: Prisma.MainCreationAgentSessionScalarFieldEnum[] | Prisma.MainCreationAgentSessionScalarFieldEnum + having?: Prisma.MainCreationAgentSessionScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: MainCreationAgentSessionCountAggregateInputType | true + _min?: MainCreationAgentSessionMinAggregateInputType + _max?: MainCreationAgentSessionMaxAggregateInputType +} + +export type MainCreationAgentSessionGroupByOutputType = { + id: string + creatorId: string + projectId: string + versionId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt: Date + updatedAt: Date + _count: MainCreationAgentSessionCountAggregateOutputType | null + _min: MainCreationAgentSessionMinAggregateOutputType | null + _max: MainCreationAgentSessionMaxAggregateOutputType | null +} + +export type GetMainCreationAgentSessionGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof MainCreationAgentSessionGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type MainCreationAgentSessionWhereInput = { + AND?: Prisma.MainCreationAgentSessionWhereInput | Prisma.MainCreationAgentSessionWhereInput[] + OR?: Prisma.MainCreationAgentSessionWhereInput[] + NOT?: Prisma.MainCreationAgentSessionWhereInput | Prisma.MainCreationAgentSessionWhereInput[] + id?: Prisma.StringFilter<"MainCreationAgentSession"> | string + creatorId?: Prisma.StringFilter<"MainCreationAgentSession"> | string + projectId?: Prisma.StringFilter<"MainCreationAgentSession"> | string + versionId?: Prisma.StringFilter<"MainCreationAgentSession"> | string + status?: Prisma.EnumMainCreationAgentSessionStatusFilter<"MainCreationAgentSession"> | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFilter<"MainCreationAgentSession"> | string + createdAt?: Prisma.DateTimeFilter<"MainCreationAgentSession"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"MainCreationAgentSession"> | Date | string + creator?: Prisma.XOR + project?: Prisma.XOR + version?: Prisma.XOR + tasks?: Prisma.AgentTaskListRelationFilter +} + +export type MainCreationAgentSessionOrderByWithRelationInput = { + id?: Prisma.SortOrder + creatorId?: Prisma.SortOrder + projectId?: Prisma.SortOrder + versionId?: Prisma.SortOrder + status?: Prisma.SortOrder + contextSummary?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + creator?: Prisma.UserOrderByWithRelationInput + project?: Prisma.GameProjectOrderByWithRelationInput + version?: Prisma.GameVersionOrderByWithRelationInput + tasks?: Prisma.AgentTaskOrderByRelationAggregateInput +} + +export type MainCreationAgentSessionWhereUniqueInput = Prisma.AtLeast<{ + id?: string + AND?: Prisma.MainCreationAgentSessionWhereInput | Prisma.MainCreationAgentSessionWhereInput[] + OR?: Prisma.MainCreationAgentSessionWhereInput[] + NOT?: Prisma.MainCreationAgentSessionWhereInput | Prisma.MainCreationAgentSessionWhereInput[] + creatorId?: Prisma.StringFilter<"MainCreationAgentSession"> | string + projectId?: Prisma.StringFilter<"MainCreationAgentSession"> | string + versionId?: Prisma.StringFilter<"MainCreationAgentSession"> | string + status?: Prisma.EnumMainCreationAgentSessionStatusFilter<"MainCreationAgentSession"> | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFilter<"MainCreationAgentSession"> | string + createdAt?: Prisma.DateTimeFilter<"MainCreationAgentSession"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"MainCreationAgentSession"> | Date | string + creator?: Prisma.XOR + project?: Prisma.XOR + version?: Prisma.XOR + tasks?: Prisma.AgentTaskListRelationFilter +}, "id"> + +export type MainCreationAgentSessionOrderByWithAggregationInput = { + id?: Prisma.SortOrder + creatorId?: Prisma.SortOrder + projectId?: Prisma.SortOrder + versionId?: Prisma.SortOrder + status?: Prisma.SortOrder + contextSummary?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.MainCreationAgentSessionCountOrderByAggregateInput + _max?: Prisma.MainCreationAgentSessionMaxOrderByAggregateInput + _min?: Prisma.MainCreationAgentSessionMinOrderByAggregateInput +} + +export type MainCreationAgentSessionScalarWhereWithAggregatesInput = { + AND?: Prisma.MainCreationAgentSessionScalarWhereWithAggregatesInput | Prisma.MainCreationAgentSessionScalarWhereWithAggregatesInput[] + OR?: Prisma.MainCreationAgentSessionScalarWhereWithAggregatesInput[] + NOT?: Prisma.MainCreationAgentSessionScalarWhereWithAggregatesInput | Prisma.MainCreationAgentSessionScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"MainCreationAgentSession"> | string + creatorId?: Prisma.StringWithAggregatesFilter<"MainCreationAgentSession"> | string + projectId?: Prisma.StringWithAggregatesFilter<"MainCreationAgentSession"> | string + versionId?: Prisma.StringWithAggregatesFilter<"MainCreationAgentSession"> | string + status?: Prisma.EnumMainCreationAgentSessionStatusWithAggregatesFilter<"MainCreationAgentSession"> | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringWithAggregatesFilter<"MainCreationAgentSession"> | string + createdAt?: Prisma.DateTimeWithAggregatesFilter<"MainCreationAgentSession"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"MainCreationAgentSession"> | Date | string +} + +export type MainCreationAgentSessionCreateInput = { + id: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string + creator: Prisma.UserCreateNestedOneWithoutMainCreationAgentSessionsInput + project: Prisma.GameProjectCreateNestedOneWithoutMainCreationAgentSessionScopesInput + version: Prisma.GameVersionCreateNestedOneWithoutMainCreationAgentSessionScopesInput + tasks?: Prisma.AgentTaskCreateNestedManyWithoutSessionInput +} + +export type MainCreationAgentSessionUncheckedCreateInput = { + id: string + creatorId: string + projectId: string + versionId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string + tasks?: Prisma.AgentTaskUncheckedCreateNestedManyWithoutSessionInput +} + +export type MainCreationAgentSessionUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + creator?: Prisma.UserUpdateOneRequiredWithoutMainCreationAgentSessionsNestedInput + project?: Prisma.GameProjectUpdateOneRequiredWithoutMainCreationAgentSessionScopesNestedInput + version?: Prisma.GameVersionUpdateOneRequiredWithoutMainCreationAgentSessionScopesNestedInput + tasks?: Prisma.AgentTaskUpdateManyWithoutSessionNestedInput +} + +export type MainCreationAgentSessionUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + creatorId?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + tasks?: Prisma.AgentTaskUncheckedUpdateManyWithoutSessionNestedInput +} + +export type MainCreationAgentSessionCreateManyInput = { + id: string + creatorId: string + projectId: string + versionId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type MainCreationAgentSessionUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type MainCreationAgentSessionUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + creatorId?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type MainCreationAgentSessionListRelationFilter = { + every?: Prisma.MainCreationAgentSessionWhereInput + some?: Prisma.MainCreationAgentSessionWhereInput + none?: Prisma.MainCreationAgentSessionWhereInput +} + +export type MainCreationAgentSessionOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type MainCreationAgentSessionCountOrderByAggregateInput = { + id?: Prisma.SortOrder + creatorId?: Prisma.SortOrder + projectId?: Prisma.SortOrder + versionId?: Prisma.SortOrder + status?: Prisma.SortOrder + contextSummary?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type MainCreationAgentSessionMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + creatorId?: Prisma.SortOrder + projectId?: Prisma.SortOrder + versionId?: Prisma.SortOrder + status?: Prisma.SortOrder + contextSummary?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type MainCreationAgentSessionMinOrderByAggregateInput = { + id?: Prisma.SortOrder + creatorId?: Prisma.SortOrder + projectId?: Prisma.SortOrder + versionId?: Prisma.SortOrder + status?: Prisma.SortOrder + contextSummary?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type MainCreationAgentSessionScalarRelationFilter = { + is?: Prisma.MainCreationAgentSessionWhereInput + isNot?: Prisma.MainCreationAgentSessionWhereInput +} + +export type MainCreationAgentSessionCreateNestedManyWithoutCreatorInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutCreatorInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutCreatorInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutCreatorInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutCreatorInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyCreatorInputEnvelope + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] +} + +export type MainCreationAgentSessionUncheckedCreateNestedManyWithoutCreatorInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutCreatorInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutCreatorInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutCreatorInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutCreatorInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyCreatorInputEnvelope + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] +} + +export type MainCreationAgentSessionUpdateManyWithoutCreatorNestedInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutCreatorInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutCreatorInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutCreatorInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutCreatorInput[] + upsert?: Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutCreatorInput | Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutCreatorInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyCreatorInputEnvelope + set?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + disconnect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + delete?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + update?: Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutCreatorInput | Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutCreatorInput[] + updateMany?: Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutCreatorInput | Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutCreatorInput[] + deleteMany?: Prisma.MainCreationAgentSessionScalarWhereInput | Prisma.MainCreationAgentSessionScalarWhereInput[] +} + +export type MainCreationAgentSessionUncheckedUpdateManyWithoutCreatorNestedInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutCreatorInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutCreatorInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutCreatorInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutCreatorInput[] + upsert?: Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutCreatorInput | Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutCreatorInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyCreatorInputEnvelope + set?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + disconnect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + delete?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + update?: Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutCreatorInput | Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutCreatorInput[] + updateMany?: Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutCreatorInput | Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutCreatorInput[] + deleteMany?: Prisma.MainCreationAgentSessionScalarWhereInput | Prisma.MainCreationAgentSessionScalarWhereInput[] +} + +export type MainCreationAgentSessionCreateNestedManyWithoutProjectInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutProjectInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutProjectInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutProjectInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyProjectInputEnvelope + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] +} + +export type MainCreationAgentSessionUncheckedCreateNestedManyWithoutProjectInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutProjectInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutProjectInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutProjectInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyProjectInputEnvelope + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] +} + +export type MainCreationAgentSessionUpdateManyWithoutProjectNestedInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutProjectInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutProjectInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutProjectInput[] + upsert?: Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutProjectInput | Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutProjectInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyProjectInputEnvelope + set?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + disconnect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + delete?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + update?: Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutProjectInput | Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutProjectInput[] + updateMany?: Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutProjectInput | Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutProjectInput[] + deleteMany?: Prisma.MainCreationAgentSessionScalarWhereInput | Prisma.MainCreationAgentSessionScalarWhereInput[] +} + +export type MainCreationAgentSessionUncheckedUpdateManyWithoutProjectNestedInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutProjectInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutProjectInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutProjectInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutProjectInput[] + upsert?: Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutProjectInput | Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutProjectInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyProjectInputEnvelope + set?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + disconnect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + delete?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + update?: Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutProjectInput | Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutProjectInput[] + updateMany?: Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutProjectInput | Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutProjectInput[] + deleteMany?: Prisma.MainCreationAgentSessionScalarWhereInput | Prisma.MainCreationAgentSessionScalarWhereInput[] +} + +export type MainCreationAgentSessionCreateNestedManyWithoutVersionInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutVersionInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutVersionInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutVersionInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutVersionInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyVersionInputEnvelope + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] +} + +export type MainCreationAgentSessionUncheckedCreateNestedManyWithoutVersionInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutVersionInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutVersionInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutVersionInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutVersionInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyVersionInputEnvelope + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] +} + +export type MainCreationAgentSessionUpdateManyWithoutVersionNestedInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutVersionInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutVersionInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutVersionInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutVersionInput[] + upsert?: Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutVersionInput | Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutVersionInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyVersionInputEnvelope + set?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + disconnect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + delete?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + update?: Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutVersionInput | Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutVersionInput[] + updateMany?: Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutVersionInput | Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutVersionInput[] + deleteMany?: Prisma.MainCreationAgentSessionScalarWhereInput | Prisma.MainCreationAgentSessionScalarWhereInput[] +} + +export type MainCreationAgentSessionUncheckedUpdateManyWithoutVersionNestedInput = { + create?: Prisma.XOR | Prisma.MainCreationAgentSessionCreateWithoutVersionInput[] | Prisma.MainCreationAgentSessionUncheckedCreateWithoutVersionInput[] + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutVersionInput | Prisma.MainCreationAgentSessionCreateOrConnectWithoutVersionInput[] + upsert?: Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutVersionInput | Prisma.MainCreationAgentSessionUpsertWithWhereUniqueWithoutVersionInput[] + createMany?: Prisma.MainCreationAgentSessionCreateManyVersionInputEnvelope + set?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + disconnect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + delete?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput | Prisma.MainCreationAgentSessionWhereUniqueInput[] + update?: Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutVersionInput | Prisma.MainCreationAgentSessionUpdateWithWhereUniqueWithoutVersionInput[] + updateMany?: Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutVersionInput | Prisma.MainCreationAgentSessionUpdateManyWithWhereWithoutVersionInput[] + deleteMany?: Prisma.MainCreationAgentSessionScalarWhereInput | Prisma.MainCreationAgentSessionScalarWhereInput[] +} + +export type EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput = { + set?: $Enums.MainCreationAgentSessionStatus +} + +export type MainCreationAgentSessionCreateNestedOneWithoutTasksInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutTasksInput + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput +} + +export type MainCreationAgentSessionUpdateOneRequiredWithoutTasksNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.MainCreationAgentSessionCreateOrConnectWithoutTasksInput + upsert?: Prisma.MainCreationAgentSessionUpsertWithoutTasksInput + connect?: Prisma.MainCreationAgentSessionWhereUniqueInput + update?: Prisma.XOR, Prisma.MainCreationAgentSessionUncheckedUpdateWithoutTasksInput> +} + +export type MainCreationAgentSessionCreateWithoutCreatorInput = { + id: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string + project: Prisma.GameProjectCreateNestedOneWithoutMainCreationAgentSessionScopesInput + version: Prisma.GameVersionCreateNestedOneWithoutMainCreationAgentSessionScopesInput + tasks?: Prisma.AgentTaskCreateNestedManyWithoutSessionInput +} + +export type MainCreationAgentSessionUncheckedCreateWithoutCreatorInput = { + id: string + projectId: string + versionId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string + tasks?: Prisma.AgentTaskUncheckedCreateNestedManyWithoutSessionInput +} + +export type MainCreationAgentSessionCreateOrConnectWithoutCreatorInput = { + where: Prisma.MainCreationAgentSessionWhereUniqueInput + create: Prisma.XOR +} + +export type MainCreationAgentSessionCreateManyCreatorInputEnvelope = { + data: Prisma.MainCreationAgentSessionCreateManyCreatorInput | Prisma.MainCreationAgentSessionCreateManyCreatorInput[] + skipDuplicates?: boolean +} + +export type MainCreationAgentSessionUpsertWithWhereUniqueWithoutCreatorInput = { + where: Prisma.MainCreationAgentSessionWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type MainCreationAgentSessionUpdateWithWhereUniqueWithoutCreatorInput = { + where: Prisma.MainCreationAgentSessionWhereUniqueInput + data: Prisma.XOR +} + +export type MainCreationAgentSessionUpdateManyWithWhereWithoutCreatorInput = { + where: Prisma.MainCreationAgentSessionScalarWhereInput + data: Prisma.XOR +} + +export type MainCreationAgentSessionScalarWhereInput = { + AND?: Prisma.MainCreationAgentSessionScalarWhereInput | Prisma.MainCreationAgentSessionScalarWhereInput[] + OR?: Prisma.MainCreationAgentSessionScalarWhereInput[] + NOT?: Prisma.MainCreationAgentSessionScalarWhereInput | Prisma.MainCreationAgentSessionScalarWhereInput[] + id?: Prisma.StringFilter<"MainCreationAgentSession"> | string + creatorId?: Prisma.StringFilter<"MainCreationAgentSession"> | string + projectId?: Prisma.StringFilter<"MainCreationAgentSession"> | string + versionId?: Prisma.StringFilter<"MainCreationAgentSession"> | string + status?: Prisma.EnumMainCreationAgentSessionStatusFilter<"MainCreationAgentSession"> | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFilter<"MainCreationAgentSession"> | string + createdAt?: Prisma.DateTimeFilter<"MainCreationAgentSession"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"MainCreationAgentSession"> | Date | string +} + +export type MainCreationAgentSessionCreateWithoutProjectInput = { + id: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string + creator: Prisma.UserCreateNestedOneWithoutMainCreationAgentSessionsInput + version: Prisma.GameVersionCreateNestedOneWithoutMainCreationAgentSessionScopesInput + tasks?: Prisma.AgentTaskCreateNestedManyWithoutSessionInput +} + +export type MainCreationAgentSessionUncheckedCreateWithoutProjectInput = { + id: string + creatorId: string + versionId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string + tasks?: Prisma.AgentTaskUncheckedCreateNestedManyWithoutSessionInput +} + +export type MainCreationAgentSessionCreateOrConnectWithoutProjectInput = { + where: Prisma.MainCreationAgentSessionWhereUniqueInput + create: Prisma.XOR +} + +export type MainCreationAgentSessionCreateManyProjectInputEnvelope = { + data: Prisma.MainCreationAgentSessionCreateManyProjectInput | Prisma.MainCreationAgentSessionCreateManyProjectInput[] + skipDuplicates?: boolean +} + +export type MainCreationAgentSessionUpsertWithWhereUniqueWithoutProjectInput = { + where: Prisma.MainCreationAgentSessionWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type MainCreationAgentSessionUpdateWithWhereUniqueWithoutProjectInput = { + where: Prisma.MainCreationAgentSessionWhereUniqueInput + data: Prisma.XOR +} + +export type MainCreationAgentSessionUpdateManyWithWhereWithoutProjectInput = { + where: Prisma.MainCreationAgentSessionScalarWhereInput + data: Prisma.XOR +} + +export type MainCreationAgentSessionCreateWithoutVersionInput = { + id: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string + creator: Prisma.UserCreateNestedOneWithoutMainCreationAgentSessionsInput + project: Prisma.GameProjectCreateNestedOneWithoutMainCreationAgentSessionScopesInput + tasks?: Prisma.AgentTaskCreateNestedManyWithoutSessionInput +} + +export type MainCreationAgentSessionUncheckedCreateWithoutVersionInput = { + id: string + creatorId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string + tasks?: Prisma.AgentTaskUncheckedCreateNestedManyWithoutSessionInput +} + +export type MainCreationAgentSessionCreateOrConnectWithoutVersionInput = { + where: Prisma.MainCreationAgentSessionWhereUniqueInput + create: Prisma.XOR +} + +export type MainCreationAgentSessionCreateManyVersionInputEnvelope = { + data: Prisma.MainCreationAgentSessionCreateManyVersionInput | Prisma.MainCreationAgentSessionCreateManyVersionInput[] + skipDuplicates?: boolean +} + +export type MainCreationAgentSessionUpsertWithWhereUniqueWithoutVersionInput = { + where: Prisma.MainCreationAgentSessionWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type MainCreationAgentSessionUpdateWithWhereUniqueWithoutVersionInput = { + where: Prisma.MainCreationAgentSessionWhereUniqueInput + data: Prisma.XOR +} + +export type MainCreationAgentSessionUpdateManyWithWhereWithoutVersionInput = { + where: Prisma.MainCreationAgentSessionScalarWhereInput + data: Prisma.XOR +} + +export type MainCreationAgentSessionCreateWithoutTasksInput = { + id: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string + creator: Prisma.UserCreateNestedOneWithoutMainCreationAgentSessionsInput + project: Prisma.GameProjectCreateNestedOneWithoutMainCreationAgentSessionScopesInput + version: Prisma.GameVersionCreateNestedOneWithoutMainCreationAgentSessionScopesInput +} + +export type MainCreationAgentSessionUncheckedCreateWithoutTasksInput = { + id: string + creatorId: string + projectId: string + versionId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type MainCreationAgentSessionCreateOrConnectWithoutTasksInput = { + where: Prisma.MainCreationAgentSessionWhereUniqueInput + create: Prisma.XOR +} + +export type MainCreationAgentSessionUpsertWithoutTasksInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.MainCreationAgentSessionWhereInput +} + +export type MainCreationAgentSessionUpdateToOneWithWhereWithoutTasksInput = { + where?: Prisma.MainCreationAgentSessionWhereInput + data: Prisma.XOR +} + +export type MainCreationAgentSessionUpdateWithoutTasksInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + creator?: Prisma.UserUpdateOneRequiredWithoutMainCreationAgentSessionsNestedInput + project?: Prisma.GameProjectUpdateOneRequiredWithoutMainCreationAgentSessionScopesNestedInput + version?: Prisma.GameVersionUpdateOneRequiredWithoutMainCreationAgentSessionScopesNestedInput +} + +export type MainCreationAgentSessionUncheckedUpdateWithoutTasksInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + creatorId?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type MainCreationAgentSessionCreateManyCreatorInput = { + id: string + projectId: string + versionId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type MainCreationAgentSessionUpdateWithoutCreatorInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + project?: Prisma.GameProjectUpdateOneRequiredWithoutMainCreationAgentSessionScopesNestedInput + version?: Prisma.GameVersionUpdateOneRequiredWithoutMainCreationAgentSessionScopesNestedInput + tasks?: Prisma.AgentTaskUpdateManyWithoutSessionNestedInput +} + +export type MainCreationAgentSessionUncheckedUpdateWithoutCreatorInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + tasks?: Prisma.AgentTaskUncheckedUpdateManyWithoutSessionNestedInput +} + +export type MainCreationAgentSessionUncheckedUpdateManyWithoutCreatorInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + projectId?: Prisma.StringFieldUpdateOperationsInput | string + versionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type MainCreationAgentSessionCreateManyProjectInput = { + id: string + creatorId: string + versionId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type MainCreationAgentSessionUpdateWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + creator?: Prisma.UserUpdateOneRequiredWithoutMainCreationAgentSessionsNestedInput + version?: Prisma.GameVersionUpdateOneRequiredWithoutMainCreationAgentSessionScopesNestedInput + tasks?: Prisma.AgentTaskUpdateManyWithoutSessionNestedInput +} + +export type MainCreationAgentSessionUncheckedUpdateWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + creatorId?: Prisma.StringFieldUpdateOperationsInput | string + versionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + tasks?: Prisma.AgentTaskUncheckedUpdateManyWithoutSessionNestedInput +} + +export type MainCreationAgentSessionUncheckedUpdateManyWithoutProjectInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + creatorId?: Prisma.StringFieldUpdateOperationsInput | string + versionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type MainCreationAgentSessionCreateManyVersionInput = { + id: string + creatorId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type MainCreationAgentSessionUpdateWithoutVersionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + creator?: Prisma.UserUpdateOneRequiredWithoutMainCreationAgentSessionsNestedInput + project?: Prisma.GameProjectUpdateOneRequiredWithoutMainCreationAgentSessionScopesNestedInput + tasks?: Prisma.AgentTaskUpdateManyWithoutSessionNestedInput +} + +export type MainCreationAgentSessionUncheckedUpdateWithoutVersionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + creatorId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + tasks?: Prisma.AgentTaskUncheckedUpdateManyWithoutSessionNestedInput +} + +export type MainCreationAgentSessionUncheckedUpdateManyWithoutVersionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + creatorId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumMainCreationAgentSessionStatusFieldUpdateOperationsInput | $Enums.MainCreationAgentSessionStatus + contextSummary?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + +/** + * Count Type MainCreationAgentSessionCountOutputType + */ + +export type MainCreationAgentSessionCountOutputType = { + tasks: number +} + +export type MainCreationAgentSessionCountOutputTypeSelect = { + tasks?: boolean | MainCreationAgentSessionCountOutputTypeCountTasksArgs +} + +/** + * MainCreationAgentSessionCountOutputType without action + */ +export type MainCreationAgentSessionCountOutputTypeDefaultArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSessionCountOutputType + */ + select?: Prisma.MainCreationAgentSessionCountOutputTypeSelect | null +} + +/** + * MainCreationAgentSessionCountOutputType without action + */ +export type MainCreationAgentSessionCountOutputTypeCountTasksArgs = { + where?: Prisma.AgentTaskWhereInput +} + + +export type MainCreationAgentSessionSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + creatorId?: boolean + projectId?: boolean + versionId?: boolean + status?: boolean + contextSummary?: boolean + createdAt?: boolean + updatedAt?: boolean + creator?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + version?: boolean | Prisma.GameVersionDefaultArgs + tasks?: boolean | Prisma.MainCreationAgentSession$tasksArgs + _count?: boolean | Prisma.MainCreationAgentSessionCountOutputTypeDefaultArgs +}, ExtArgs["result"]["mainCreationAgentSession"]> + +export type MainCreationAgentSessionSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + creatorId?: boolean + projectId?: boolean + versionId?: boolean + status?: boolean + contextSummary?: boolean + createdAt?: boolean + updatedAt?: boolean + creator?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + version?: boolean | Prisma.GameVersionDefaultArgs +}, ExtArgs["result"]["mainCreationAgentSession"]> + +export type MainCreationAgentSessionSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + creatorId?: boolean + projectId?: boolean + versionId?: boolean + status?: boolean + contextSummary?: boolean + createdAt?: boolean + updatedAt?: boolean + creator?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + version?: boolean | Prisma.GameVersionDefaultArgs +}, ExtArgs["result"]["mainCreationAgentSession"]> + +export type MainCreationAgentSessionSelectScalar = { + id?: boolean + creatorId?: boolean + projectId?: boolean + versionId?: boolean + status?: boolean + contextSummary?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type MainCreationAgentSessionOmit = runtime.Types.Extensions.GetOmit<"id" | "creatorId" | "projectId" | "versionId" | "status" | "contextSummary" | "createdAt" | "updatedAt", ExtArgs["result"]["mainCreationAgentSession"]> +export type MainCreationAgentSessionInclude = { + creator?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + version?: boolean | Prisma.GameVersionDefaultArgs + tasks?: boolean | Prisma.MainCreationAgentSession$tasksArgs + _count?: boolean | Prisma.MainCreationAgentSessionCountOutputTypeDefaultArgs +} +export type MainCreationAgentSessionIncludeCreateManyAndReturn = { + creator?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + version?: boolean | Prisma.GameVersionDefaultArgs +} +export type MainCreationAgentSessionIncludeUpdateManyAndReturn = { + creator?: boolean | Prisma.UserDefaultArgs + project?: boolean | Prisma.GameProjectDefaultArgs + version?: boolean | Prisma.GameVersionDefaultArgs +} + +export type $MainCreationAgentSessionPayload = { + name: "MainCreationAgentSession" + objects: { + creator: Prisma.$UserPayload + project: Prisma.$GameProjectPayload + version: Prisma.$GameVersionPayload + tasks: Prisma.$AgentTaskPayload[] + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + creatorId: string + projectId: string + versionId: string + status: $Enums.MainCreationAgentSessionStatus + contextSummary: string + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["mainCreationAgentSession"]> + composites: {} +} + +export type MainCreationAgentSessionGetPayload = runtime.Types.Result.GetResult + +export type MainCreationAgentSessionCountArgs = + Omit & { + select?: MainCreationAgentSessionCountAggregateInputType | true + } + +export interface MainCreationAgentSessionDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['MainCreationAgentSession'], meta: { name: 'MainCreationAgentSession' } } + /** + * Find zero or one MainCreationAgentSession that matches the filter. + * @param {MainCreationAgentSessionFindUniqueArgs} args - Arguments to find a MainCreationAgentSession + * @example + * // Get one MainCreationAgentSession + * const mainCreationAgentSession = await prisma.mainCreationAgentSession.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__MainCreationAgentSessionClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one MainCreationAgentSession that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {MainCreationAgentSessionFindUniqueOrThrowArgs} args - Arguments to find a MainCreationAgentSession + * @example + * // Get one MainCreationAgentSession + * const mainCreationAgentSession = await prisma.mainCreationAgentSession.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__MainCreationAgentSessionClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first MainCreationAgentSession that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MainCreationAgentSessionFindFirstArgs} args - Arguments to find a MainCreationAgentSession + * @example + * // Get one MainCreationAgentSession + * const mainCreationAgentSession = await prisma.mainCreationAgentSession.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__MainCreationAgentSessionClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first MainCreationAgentSession that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MainCreationAgentSessionFindFirstOrThrowArgs} args - Arguments to find a MainCreationAgentSession + * @example + * // Get one MainCreationAgentSession + * const mainCreationAgentSession = await prisma.mainCreationAgentSession.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__MainCreationAgentSessionClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more MainCreationAgentSessions that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MainCreationAgentSessionFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all MainCreationAgentSessions + * const mainCreationAgentSessions = await prisma.mainCreationAgentSession.findMany() + * + * // Get first 10 MainCreationAgentSessions + * const mainCreationAgentSessions = await prisma.mainCreationAgentSession.findMany({ take: 10 }) + * + * // Only select the `id` + * const mainCreationAgentSessionWithIdOnly = await prisma.mainCreationAgentSession.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a MainCreationAgentSession. + * @param {MainCreationAgentSessionCreateArgs} args - Arguments to create a MainCreationAgentSession. + * @example + * // Create one MainCreationAgentSession + * const MainCreationAgentSession = await prisma.mainCreationAgentSession.create({ + * data: { + * // ... data to create a MainCreationAgentSession + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__MainCreationAgentSessionClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many MainCreationAgentSessions. + * @param {MainCreationAgentSessionCreateManyArgs} args - Arguments to create many MainCreationAgentSessions. + * @example + * // Create many MainCreationAgentSessions + * const mainCreationAgentSession = await prisma.mainCreationAgentSession.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many MainCreationAgentSessions and returns the data saved in the database. + * @param {MainCreationAgentSessionCreateManyAndReturnArgs} args - Arguments to create many MainCreationAgentSessions. + * @example + * // Create many MainCreationAgentSessions + * const mainCreationAgentSession = await prisma.mainCreationAgentSession.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many MainCreationAgentSessions and only return the `id` + * const mainCreationAgentSessionWithIdOnly = await prisma.mainCreationAgentSession.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a MainCreationAgentSession. + * @param {MainCreationAgentSessionDeleteArgs} args - Arguments to delete one MainCreationAgentSession. + * @example + * // Delete one MainCreationAgentSession + * const MainCreationAgentSession = await prisma.mainCreationAgentSession.delete({ + * where: { + * // ... filter to delete one MainCreationAgentSession + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__MainCreationAgentSessionClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one MainCreationAgentSession. + * @param {MainCreationAgentSessionUpdateArgs} args - Arguments to update one MainCreationAgentSession. + * @example + * // Update one MainCreationAgentSession + * const mainCreationAgentSession = await prisma.mainCreationAgentSession.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__MainCreationAgentSessionClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more MainCreationAgentSessions. + * @param {MainCreationAgentSessionDeleteManyArgs} args - Arguments to filter MainCreationAgentSessions to delete. + * @example + * // Delete a few MainCreationAgentSessions + * const { count } = await prisma.mainCreationAgentSession.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more MainCreationAgentSessions. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MainCreationAgentSessionUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many MainCreationAgentSessions + * const mainCreationAgentSession = await prisma.mainCreationAgentSession.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more MainCreationAgentSessions and returns the data updated in the database. + * @param {MainCreationAgentSessionUpdateManyAndReturnArgs} args - Arguments to update many MainCreationAgentSessions. + * @example + * // Update many MainCreationAgentSessions + * const mainCreationAgentSession = await prisma.mainCreationAgentSession.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more MainCreationAgentSessions and only return the `id` + * const mainCreationAgentSessionWithIdOnly = await prisma.mainCreationAgentSession.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one MainCreationAgentSession. + * @param {MainCreationAgentSessionUpsertArgs} args - Arguments to update or create a MainCreationAgentSession. + * @example + * // Update or create a MainCreationAgentSession + * const mainCreationAgentSession = await prisma.mainCreationAgentSession.upsert({ + * create: { + * // ... data to create a MainCreationAgentSession + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the MainCreationAgentSession we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__MainCreationAgentSessionClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of MainCreationAgentSessions. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MainCreationAgentSessionCountArgs} args - Arguments to filter MainCreationAgentSessions to count. + * @example + * // Count the number of MainCreationAgentSessions + * const count = await prisma.mainCreationAgentSession.count({ + * where: { + * // ... the filter for the MainCreationAgentSessions we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a MainCreationAgentSession. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MainCreationAgentSessionAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by MainCreationAgentSession. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MainCreationAgentSessionGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends MainCreationAgentSessionGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: MainCreationAgentSessionGroupByArgs['orderBy'] } + : { orderBy?: MainCreationAgentSessionGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetMainCreationAgentSessionGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the MainCreationAgentSession model + */ +readonly fields: MainCreationAgentSessionFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for MainCreationAgentSession. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__MainCreationAgentSessionClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + creator = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + project = {}>(args?: Prisma.Subset>): Prisma.Prisma__GameProjectClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + version = {}>(args?: Prisma.Subset>): Prisma.Prisma__GameVersionClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + tasks = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the MainCreationAgentSession model + */ +export interface MainCreationAgentSessionFieldRefs { + readonly id: Prisma.FieldRef<"MainCreationAgentSession", 'String'> + readonly creatorId: Prisma.FieldRef<"MainCreationAgentSession", 'String'> + readonly projectId: Prisma.FieldRef<"MainCreationAgentSession", 'String'> + readonly versionId: Prisma.FieldRef<"MainCreationAgentSession", 'String'> + readonly status: Prisma.FieldRef<"MainCreationAgentSession", 'MainCreationAgentSessionStatus'> + readonly contextSummary: Prisma.FieldRef<"MainCreationAgentSession", 'String'> + readonly createdAt: Prisma.FieldRef<"MainCreationAgentSession", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"MainCreationAgentSession", 'DateTime'> +} + + +// Custom InputTypes +/** + * MainCreationAgentSession findUnique + */ +export type MainCreationAgentSessionFindUniqueArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + /** + * Filter, which MainCreationAgentSession to fetch. + */ + where: Prisma.MainCreationAgentSessionWhereUniqueInput +} + +/** + * MainCreationAgentSession findUniqueOrThrow + */ +export type MainCreationAgentSessionFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + /** + * Filter, which MainCreationAgentSession to fetch. + */ + where: Prisma.MainCreationAgentSessionWhereUniqueInput +} + +/** + * MainCreationAgentSession findFirst + */ +export type MainCreationAgentSessionFindFirstArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + /** + * Filter, which MainCreationAgentSession to fetch. + */ + where?: Prisma.MainCreationAgentSessionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of MainCreationAgentSessions to fetch. + */ + orderBy?: Prisma.MainCreationAgentSessionOrderByWithRelationInput | Prisma.MainCreationAgentSessionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for MainCreationAgentSessions. + */ + cursor?: Prisma.MainCreationAgentSessionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` MainCreationAgentSessions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` MainCreationAgentSessions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of MainCreationAgentSessions. + */ + distinct?: Prisma.MainCreationAgentSessionScalarFieldEnum | Prisma.MainCreationAgentSessionScalarFieldEnum[] +} + +/** + * MainCreationAgentSession findFirstOrThrow + */ +export type MainCreationAgentSessionFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + /** + * Filter, which MainCreationAgentSession to fetch. + */ + where?: Prisma.MainCreationAgentSessionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of MainCreationAgentSessions to fetch. + */ + orderBy?: Prisma.MainCreationAgentSessionOrderByWithRelationInput | Prisma.MainCreationAgentSessionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for MainCreationAgentSessions. + */ + cursor?: Prisma.MainCreationAgentSessionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` MainCreationAgentSessions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` MainCreationAgentSessions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of MainCreationAgentSessions. + */ + distinct?: Prisma.MainCreationAgentSessionScalarFieldEnum | Prisma.MainCreationAgentSessionScalarFieldEnum[] +} + +/** + * MainCreationAgentSession findMany + */ +export type MainCreationAgentSessionFindManyArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + /** + * Filter, which MainCreationAgentSessions to fetch. + */ + where?: Prisma.MainCreationAgentSessionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of MainCreationAgentSessions to fetch. + */ + orderBy?: Prisma.MainCreationAgentSessionOrderByWithRelationInput | Prisma.MainCreationAgentSessionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing MainCreationAgentSessions. + */ + cursor?: Prisma.MainCreationAgentSessionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` MainCreationAgentSessions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` MainCreationAgentSessions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of MainCreationAgentSessions. + */ + distinct?: Prisma.MainCreationAgentSessionScalarFieldEnum | Prisma.MainCreationAgentSessionScalarFieldEnum[] +} + +/** + * MainCreationAgentSession create + */ +export type MainCreationAgentSessionCreateArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + /** + * The data needed to create a MainCreationAgentSession. + */ + data: Prisma.XOR +} + +/** + * MainCreationAgentSession createMany + */ +export type MainCreationAgentSessionCreateManyArgs = { + /** + * The data used to create many MainCreationAgentSessions. + */ + data: Prisma.MainCreationAgentSessionCreateManyInput | Prisma.MainCreationAgentSessionCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * MainCreationAgentSession createManyAndReturn + */ +export type MainCreationAgentSessionCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelectCreateManyAndReturn | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * The data used to create many MainCreationAgentSessions. + */ + data: Prisma.MainCreationAgentSessionCreateManyInput | Prisma.MainCreationAgentSessionCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionIncludeCreateManyAndReturn | null +} + +/** + * MainCreationAgentSession update + */ +export type MainCreationAgentSessionUpdateArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + /** + * The data needed to update a MainCreationAgentSession. + */ + data: Prisma.XOR + /** + * Choose, which MainCreationAgentSession to update. + */ + where: Prisma.MainCreationAgentSessionWhereUniqueInput +} + +/** + * MainCreationAgentSession updateMany + */ +export type MainCreationAgentSessionUpdateManyArgs = { + /** + * The data used to update MainCreationAgentSessions. + */ + data: Prisma.XOR + /** + * Filter which MainCreationAgentSessions to update + */ + where?: Prisma.MainCreationAgentSessionWhereInput + /** + * Limit how many MainCreationAgentSessions to update. + */ + limit?: number +} + +/** + * MainCreationAgentSession updateManyAndReturn + */ +export type MainCreationAgentSessionUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * The data used to update MainCreationAgentSessions. + */ + data: Prisma.XOR + /** + * Filter which MainCreationAgentSessions to update + */ + where?: Prisma.MainCreationAgentSessionWhereInput + /** + * Limit how many MainCreationAgentSessions to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionIncludeUpdateManyAndReturn | null +} + +/** + * MainCreationAgentSession upsert + */ +export type MainCreationAgentSessionUpsertArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + /** + * The filter to search for the MainCreationAgentSession to update in case it exists. + */ + where: Prisma.MainCreationAgentSessionWhereUniqueInput + /** + * In case the MainCreationAgentSession found by the `where` argument doesn't exist, create a new MainCreationAgentSession with this data. + */ + create: Prisma.XOR + /** + * In case the MainCreationAgentSession was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * MainCreationAgentSession delete + */ +export type MainCreationAgentSessionDeleteArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + /** + * Filter which MainCreationAgentSession to delete. + */ + where: Prisma.MainCreationAgentSessionWhereUniqueInput +} + +/** + * MainCreationAgentSession deleteMany + */ +export type MainCreationAgentSessionDeleteManyArgs = { + /** + * Filter which MainCreationAgentSessions to delete + */ + where?: Prisma.MainCreationAgentSessionWhereInput + /** + * Limit how many MainCreationAgentSessions to delete. + */ + limit?: number +} + +/** + * MainCreationAgentSession.tasks + */ +export type MainCreationAgentSession$tasksArgs = { + /** + * Select specific fields to fetch from the AgentTask + */ + select?: Prisma.AgentTaskSelect | null + /** + * Omit specific fields from the AgentTask + */ + omit?: Prisma.AgentTaskOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AgentTaskInclude | null + where?: Prisma.AgentTaskWhereInput + orderBy?: Prisma.AgentTaskOrderByWithRelationInput | Prisma.AgentTaskOrderByWithRelationInput[] + cursor?: Prisma.AgentTaskWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.AgentTaskScalarFieldEnum | Prisma.AgentTaskScalarFieldEnum[] +} + +/** + * MainCreationAgentSession without action + */ +export type MainCreationAgentSessionDefaultArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null +} diff --git a/apps/api/src/generated/prisma/models/ReviewRecord.ts b/apps/api/src/generated/prisma/models/ReviewRecord.ts new file mode 100644 index 00000000..c58bd3e2 --- /dev/null +++ b/apps/api/src/generated/prisma/models/ReviewRecord.ts @@ -0,0 +1,1656 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `ReviewRecord` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model ReviewRecord + * + */ +export type ReviewRecordModel = runtime.Types.Result.DefaultSelection + +export type AggregateReviewRecord = { + _count: ReviewRecordCountAggregateOutputType | null + _min: ReviewRecordMinAggregateOutputType | null + _max: ReviewRecordMaxAggregateOutputType | null +} + +export type ReviewRecordMinAggregateOutputType = { + id: string | null + gameVersionId: string | null + status: $Enums.ReviewRecordStatus | null + decision: $Enums.ReviewDecision | null + reasonCode: string | null + decidedById: string | null + decidedAt: Date | null + createdAt: Date | null + updatedAt: Date | null +} + +export type ReviewRecordMaxAggregateOutputType = { + id: string | null + gameVersionId: string | null + status: $Enums.ReviewRecordStatus | null + decision: $Enums.ReviewDecision | null + reasonCode: string | null + decidedById: string | null + decidedAt: Date | null + createdAt: Date | null + updatedAt: Date | null +} + +export type ReviewRecordCountAggregateOutputType = { + id: number + gameVersionId: number + status: number + decision: number + reasonCode: number + decidedById: number + decidedAt: number + createdAt: number + updatedAt: number + _all: number +} + + +export type ReviewRecordMinAggregateInputType = { + id?: true + gameVersionId?: true + status?: true + decision?: true + reasonCode?: true + decidedById?: true + decidedAt?: true + createdAt?: true + updatedAt?: true +} + +export type ReviewRecordMaxAggregateInputType = { + id?: true + gameVersionId?: true + status?: true + decision?: true + reasonCode?: true + decidedById?: true + decidedAt?: true + createdAt?: true + updatedAt?: true +} + +export type ReviewRecordCountAggregateInputType = { + id?: true + gameVersionId?: true + status?: true + decision?: true + reasonCode?: true + decidedById?: true + decidedAt?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type ReviewRecordAggregateArgs = { + /** + * Filter which ReviewRecord to aggregate. + */ + where?: Prisma.ReviewRecordWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of ReviewRecords to fetch. + */ + orderBy?: Prisma.ReviewRecordOrderByWithRelationInput | Prisma.ReviewRecordOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.ReviewRecordWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` ReviewRecords from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` ReviewRecords. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned ReviewRecords + **/ + _count?: true | ReviewRecordCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: ReviewRecordMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: ReviewRecordMaxAggregateInputType +} + +export type GetReviewRecordAggregateType = { + [P in keyof T & keyof AggregateReviewRecord]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type ReviewRecordGroupByArgs = { + where?: Prisma.ReviewRecordWhereInput + orderBy?: Prisma.ReviewRecordOrderByWithAggregationInput | Prisma.ReviewRecordOrderByWithAggregationInput[] + by: Prisma.ReviewRecordScalarFieldEnum[] | Prisma.ReviewRecordScalarFieldEnum + having?: Prisma.ReviewRecordScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: ReviewRecordCountAggregateInputType | true + _min?: ReviewRecordMinAggregateInputType + _max?: ReviewRecordMaxAggregateInputType +} + +export type ReviewRecordGroupByOutputType = { + id: string + gameVersionId: string + status: $Enums.ReviewRecordStatus + decision: $Enums.ReviewDecision | null + reasonCode: string | null + decidedById: string | null + decidedAt: Date | null + createdAt: Date + updatedAt: Date + _count: ReviewRecordCountAggregateOutputType | null + _min: ReviewRecordMinAggregateOutputType | null + _max: ReviewRecordMaxAggregateOutputType | null +} + +export type GetReviewRecordGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof ReviewRecordGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type ReviewRecordWhereInput = { + AND?: Prisma.ReviewRecordWhereInput | Prisma.ReviewRecordWhereInput[] + OR?: Prisma.ReviewRecordWhereInput[] + NOT?: Prisma.ReviewRecordWhereInput | Prisma.ReviewRecordWhereInput[] + id?: Prisma.StringFilter<"ReviewRecord"> | string + gameVersionId?: Prisma.StringFilter<"ReviewRecord"> | string + status?: Prisma.EnumReviewRecordStatusFilter<"ReviewRecord"> | $Enums.ReviewRecordStatus + decision?: Prisma.EnumReviewDecisionNullableFilter<"ReviewRecord"> | $Enums.ReviewDecision | null + reasonCode?: Prisma.StringNullableFilter<"ReviewRecord"> | string | null + decidedById?: Prisma.StringNullableFilter<"ReviewRecord"> | string | null + decidedAt?: Prisma.DateTimeNullableFilter<"ReviewRecord"> | Date | string | null + createdAt?: Prisma.DateTimeFilter<"ReviewRecord"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"ReviewRecord"> | Date | string + gameVersion?: Prisma.XOR + decidedBy?: Prisma.XOR | null +} + +export type ReviewRecordOrderByWithRelationInput = { + id?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + status?: Prisma.SortOrder + decision?: Prisma.SortOrderInput | Prisma.SortOrder + reasonCode?: Prisma.SortOrderInput | Prisma.SortOrder + decidedById?: Prisma.SortOrderInput | Prisma.SortOrder + decidedAt?: Prisma.SortOrderInput | Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + gameVersion?: Prisma.GameVersionOrderByWithRelationInput + decidedBy?: Prisma.UserOrderByWithRelationInput +} + +export type ReviewRecordWhereUniqueInput = Prisma.AtLeast<{ + id?: string + AND?: Prisma.ReviewRecordWhereInput | Prisma.ReviewRecordWhereInput[] + OR?: Prisma.ReviewRecordWhereInput[] + NOT?: Prisma.ReviewRecordWhereInput | Prisma.ReviewRecordWhereInput[] + gameVersionId?: Prisma.StringFilter<"ReviewRecord"> | string + status?: Prisma.EnumReviewRecordStatusFilter<"ReviewRecord"> | $Enums.ReviewRecordStatus + decision?: Prisma.EnumReviewDecisionNullableFilter<"ReviewRecord"> | $Enums.ReviewDecision | null + reasonCode?: Prisma.StringNullableFilter<"ReviewRecord"> | string | null + decidedById?: Prisma.StringNullableFilter<"ReviewRecord"> | string | null + decidedAt?: Prisma.DateTimeNullableFilter<"ReviewRecord"> | Date | string | null + createdAt?: Prisma.DateTimeFilter<"ReviewRecord"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"ReviewRecord"> | Date | string + gameVersion?: Prisma.XOR + decidedBy?: Prisma.XOR | null +}, "id"> + +export type ReviewRecordOrderByWithAggregationInput = { + id?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + status?: Prisma.SortOrder + decision?: Prisma.SortOrderInput | Prisma.SortOrder + reasonCode?: Prisma.SortOrderInput | Prisma.SortOrder + decidedById?: Prisma.SortOrderInput | Prisma.SortOrder + decidedAt?: Prisma.SortOrderInput | Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.ReviewRecordCountOrderByAggregateInput + _max?: Prisma.ReviewRecordMaxOrderByAggregateInput + _min?: Prisma.ReviewRecordMinOrderByAggregateInput +} + +export type ReviewRecordScalarWhereWithAggregatesInput = { + AND?: Prisma.ReviewRecordScalarWhereWithAggregatesInput | Prisma.ReviewRecordScalarWhereWithAggregatesInput[] + OR?: Prisma.ReviewRecordScalarWhereWithAggregatesInput[] + NOT?: Prisma.ReviewRecordScalarWhereWithAggregatesInput | Prisma.ReviewRecordScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"ReviewRecord"> | string + gameVersionId?: Prisma.StringWithAggregatesFilter<"ReviewRecord"> | string + status?: Prisma.EnumReviewRecordStatusWithAggregatesFilter<"ReviewRecord"> | $Enums.ReviewRecordStatus + decision?: Prisma.EnumReviewDecisionNullableWithAggregatesFilter<"ReviewRecord"> | $Enums.ReviewDecision | null + reasonCode?: Prisma.StringNullableWithAggregatesFilter<"ReviewRecord"> | string | null + decidedById?: Prisma.StringNullableWithAggregatesFilter<"ReviewRecord"> | string | null + decidedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"ReviewRecord"> | Date | string | null + createdAt?: Prisma.DateTimeWithAggregatesFilter<"ReviewRecord"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"ReviewRecord"> | Date | string +} + +export type ReviewRecordCreateInput = { + id: string + status: $Enums.ReviewRecordStatus + decision?: $Enums.ReviewDecision | null + reasonCode?: string | null + decidedAt?: Date | string | null + createdAt?: Date | string + updatedAt?: Date | string + gameVersion: Prisma.GameVersionCreateNestedOneWithoutReviewRecordsInput + decidedBy?: Prisma.UserCreateNestedOneWithoutReviewDecisionsInput +} + +export type ReviewRecordUncheckedCreateInput = { + id: string + gameVersionId: string + status: $Enums.ReviewRecordStatus + decision?: $Enums.ReviewDecision | null + reasonCode?: string | null + decidedById?: string | null + decidedAt?: Date | string | null + createdAt?: Date | string + updatedAt?: Date | string +} + +export type ReviewRecordUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumReviewRecordStatusFieldUpdateOperationsInput | $Enums.ReviewRecordStatus + decision?: Prisma.NullableEnumReviewDecisionFieldUpdateOperationsInput | $Enums.ReviewDecision | null + reasonCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + gameVersion?: Prisma.GameVersionUpdateOneRequiredWithoutReviewRecordsNestedInput + decidedBy?: Prisma.UserUpdateOneWithoutReviewDecisionsNestedInput +} + +export type ReviewRecordUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + gameVersionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumReviewRecordStatusFieldUpdateOperationsInput | $Enums.ReviewRecordStatus + decision?: Prisma.NullableEnumReviewDecisionFieldUpdateOperationsInput | $Enums.ReviewDecision | null + reasonCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedById?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type ReviewRecordCreateManyInput = { + id: string + gameVersionId: string + status: $Enums.ReviewRecordStatus + decision?: $Enums.ReviewDecision | null + reasonCode?: string | null + decidedById?: string | null + decidedAt?: Date | string | null + createdAt?: Date | string + updatedAt?: Date | string +} + +export type ReviewRecordUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumReviewRecordStatusFieldUpdateOperationsInput | $Enums.ReviewRecordStatus + decision?: Prisma.NullableEnumReviewDecisionFieldUpdateOperationsInput | $Enums.ReviewDecision | null + reasonCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type ReviewRecordUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + gameVersionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumReviewRecordStatusFieldUpdateOperationsInput | $Enums.ReviewRecordStatus + decision?: Prisma.NullableEnumReviewDecisionFieldUpdateOperationsInput | $Enums.ReviewDecision | null + reasonCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedById?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type ReviewRecordListRelationFilter = { + every?: Prisma.ReviewRecordWhereInput + some?: Prisma.ReviewRecordWhereInput + none?: Prisma.ReviewRecordWhereInput +} + +export type ReviewRecordOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type ReviewRecordCountOrderByAggregateInput = { + id?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + status?: Prisma.SortOrder + decision?: Prisma.SortOrder + reasonCode?: Prisma.SortOrder + decidedById?: Prisma.SortOrder + decidedAt?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type ReviewRecordMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + status?: Prisma.SortOrder + decision?: Prisma.SortOrder + reasonCode?: Prisma.SortOrder + decidedById?: Prisma.SortOrder + decidedAt?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type ReviewRecordMinOrderByAggregateInput = { + id?: Prisma.SortOrder + gameVersionId?: Prisma.SortOrder + status?: Prisma.SortOrder + decision?: Prisma.SortOrder + reasonCode?: Prisma.SortOrder + decidedById?: Prisma.SortOrder + decidedAt?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type ReviewRecordCreateNestedManyWithoutDecidedByInput = { + create?: Prisma.XOR | Prisma.ReviewRecordCreateWithoutDecidedByInput[] | Prisma.ReviewRecordUncheckedCreateWithoutDecidedByInput[] + connectOrCreate?: Prisma.ReviewRecordCreateOrConnectWithoutDecidedByInput | Prisma.ReviewRecordCreateOrConnectWithoutDecidedByInput[] + createMany?: Prisma.ReviewRecordCreateManyDecidedByInputEnvelope + connect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] +} + +export type ReviewRecordUncheckedCreateNestedManyWithoutDecidedByInput = { + create?: Prisma.XOR | Prisma.ReviewRecordCreateWithoutDecidedByInput[] | Prisma.ReviewRecordUncheckedCreateWithoutDecidedByInput[] + connectOrCreate?: Prisma.ReviewRecordCreateOrConnectWithoutDecidedByInput | Prisma.ReviewRecordCreateOrConnectWithoutDecidedByInput[] + createMany?: Prisma.ReviewRecordCreateManyDecidedByInputEnvelope + connect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] +} + +export type ReviewRecordUpdateManyWithoutDecidedByNestedInput = { + create?: Prisma.XOR | Prisma.ReviewRecordCreateWithoutDecidedByInput[] | Prisma.ReviewRecordUncheckedCreateWithoutDecidedByInput[] + connectOrCreate?: Prisma.ReviewRecordCreateOrConnectWithoutDecidedByInput | Prisma.ReviewRecordCreateOrConnectWithoutDecidedByInput[] + upsert?: Prisma.ReviewRecordUpsertWithWhereUniqueWithoutDecidedByInput | Prisma.ReviewRecordUpsertWithWhereUniqueWithoutDecidedByInput[] + createMany?: Prisma.ReviewRecordCreateManyDecidedByInputEnvelope + set?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + disconnect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + delete?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + connect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + update?: Prisma.ReviewRecordUpdateWithWhereUniqueWithoutDecidedByInput | Prisma.ReviewRecordUpdateWithWhereUniqueWithoutDecidedByInput[] + updateMany?: Prisma.ReviewRecordUpdateManyWithWhereWithoutDecidedByInput | Prisma.ReviewRecordUpdateManyWithWhereWithoutDecidedByInput[] + deleteMany?: Prisma.ReviewRecordScalarWhereInput | Prisma.ReviewRecordScalarWhereInput[] +} + +export type ReviewRecordUncheckedUpdateManyWithoutDecidedByNestedInput = { + create?: Prisma.XOR | Prisma.ReviewRecordCreateWithoutDecidedByInput[] | Prisma.ReviewRecordUncheckedCreateWithoutDecidedByInput[] + connectOrCreate?: Prisma.ReviewRecordCreateOrConnectWithoutDecidedByInput | Prisma.ReviewRecordCreateOrConnectWithoutDecidedByInput[] + upsert?: Prisma.ReviewRecordUpsertWithWhereUniqueWithoutDecidedByInput | Prisma.ReviewRecordUpsertWithWhereUniqueWithoutDecidedByInput[] + createMany?: Prisma.ReviewRecordCreateManyDecidedByInputEnvelope + set?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + disconnect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + delete?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + connect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + update?: Prisma.ReviewRecordUpdateWithWhereUniqueWithoutDecidedByInput | Prisma.ReviewRecordUpdateWithWhereUniqueWithoutDecidedByInput[] + updateMany?: Prisma.ReviewRecordUpdateManyWithWhereWithoutDecidedByInput | Prisma.ReviewRecordUpdateManyWithWhereWithoutDecidedByInput[] + deleteMany?: Prisma.ReviewRecordScalarWhereInput | Prisma.ReviewRecordScalarWhereInput[] +} + +export type ReviewRecordCreateNestedManyWithoutGameVersionInput = { + create?: Prisma.XOR | Prisma.ReviewRecordCreateWithoutGameVersionInput[] | Prisma.ReviewRecordUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.ReviewRecordCreateOrConnectWithoutGameVersionInput | Prisma.ReviewRecordCreateOrConnectWithoutGameVersionInput[] + createMany?: Prisma.ReviewRecordCreateManyGameVersionInputEnvelope + connect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] +} + +export type ReviewRecordUncheckedCreateNestedManyWithoutGameVersionInput = { + create?: Prisma.XOR | Prisma.ReviewRecordCreateWithoutGameVersionInput[] | Prisma.ReviewRecordUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.ReviewRecordCreateOrConnectWithoutGameVersionInput | Prisma.ReviewRecordCreateOrConnectWithoutGameVersionInput[] + createMany?: Prisma.ReviewRecordCreateManyGameVersionInputEnvelope + connect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] +} + +export type ReviewRecordUpdateManyWithoutGameVersionNestedInput = { + create?: Prisma.XOR | Prisma.ReviewRecordCreateWithoutGameVersionInput[] | Prisma.ReviewRecordUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.ReviewRecordCreateOrConnectWithoutGameVersionInput | Prisma.ReviewRecordCreateOrConnectWithoutGameVersionInput[] + upsert?: Prisma.ReviewRecordUpsertWithWhereUniqueWithoutGameVersionInput | Prisma.ReviewRecordUpsertWithWhereUniqueWithoutGameVersionInput[] + createMany?: Prisma.ReviewRecordCreateManyGameVersionInputEnvelope + set?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + disconnect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + delete?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + connect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + update?: Prisma.ReviewRecordUpdateWithWhereUniqueWithoutGameVersionInput | Prisma.ReviewRecordUpdateWithWhereUniqueWithoutGameVersionInput[] + updateMany?: Prisma.ReviewRecordUpdateManyWithWhereWithoutGameVersionInput | Prisma.ReviewRecordUpdateManyWithWhereWithoutGameVersionInput[] + deleteMany?: Prisma.ReviewRecordScalarWhereInput | Prisma.ReviewRecordScalarWhereInput[] +} + +export type ReviewRecordUncheckedUpdateManyWithoutGameVersionNestedInput = { + create?: Prisma.XOR | Prisma.ReviewRecordCreateWithoutGameVersionInput[] | Prisma.ReviewRecordUncheckedCreateWithoutGameVersionInput[] + connectOrCreate?: Prisma.ReviewRecordCreateOrConnectWithoutGameVersionInput | Prisma.ReviewRecordCreateOrConnectWithoutGameVersionInput[] + upsert?: Prisma.ReviewRecordUpsertWithWhereUniqueWithoutGameVersionInput | Prisma.ReviewRecordUpsertWithWhereUniqueWithoutGameVersionInput[] + createMany?: Prisma.ReviewRecordCreateManyGameVersionInputEnvelope + set?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + disconnect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + delete?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + connect?: Prisma.ReviewRecordWhereUniqueInput | Prisma.ReviewRecordWhereUniqueInput[] + update?: Prisma.ReviewRecordUpdateWithWhereUniqueWithoutGameVersionInput | Prisma.ReviewRecordUpdateWithWhereUniqueWithoutGameVersionInput[] + updateMany?: Prisma.ReviewRecordUpdateManyWithWhereWithoutGameVersionInput | Prisma.ReviewRecordUpdateManyWithWhereWithoutGameVersionInput[] + deleteMany?: Prisma.ReviewRecordScalarWhereInput | Prisma.ReviewRecordScalarWhereInput[] +} + +export type EnumReviewRecordStatusFieldUpdateOperationsInput = { + set?: $Enums.ReviewRecordStatus +} + +export type NullableEnumReviewDecisionFieldUpdateOperationsInput = { + set?: $Enums.ReviewDecision | null +} + +export type ReviewRecordCreateWithoutDecidedByInput = { + id: string + status: $Enums.ReviewRecordStatus + decision?: $Enums.ReviewDecision | null + reasonCode?: string | null + decidedAt?: Date | string | null + createdAt?: Date | string + updatedAt?: Date | string + gameVersion: Prisma.GameVersionCreateNestedOneWithoutReviewRecordsInput +} + +export type ReviewRecordUncheckedCreateWithoutDecidedByInput = { + id: string + gameVersionId: string + status: $Enums.ReviewRecordStatus + decision?: $Enums.ReviewDecision | null + reasonCode?: string | null + decidedAt?: Date | string | null + createdAt?: Date | string + updatedAt?: Date | string +} + +export type ReviewRecordCreateOrConnectWithoutDecidedByInput = { + where: Prisma.ReviewRecordWhereUniqueInput + create: Prisma.XOR +} + +export type ReviewRecordCreateManyDecidedByInputEnvelope = { + data: Prisma.ReviewRecordCreateManyDecidedByInput | Prisma.ReviewRecordCreateManyDecidedByInput[] + skipDuplicates?: boolean +} + +export type ReviewRecordUpsertWithWhereUniqueWithoutDecidedByInput = { + where: Prisma.ReviewRecordWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type ReviewRecordUpdateWithWhereUniqueWithoutDecidedByInput = { + where: Prisma.ReviewRecordWhereUniqueInput + data: Prisma.XOR +} + +export type ReviewRecordUpdateManyWithWhereWithoutDecidedByInput = { + where: Prisma.ReviewRecordScalarWhereInput + data: Prisma.XOR +} + +export type ReviewRecordScalarWhereInput = { + AND?: Prisma.ReviewRecordScalarWhereInput | Prisma.ReviewRecordScalarWhereInput[] + OR?: Prisma.ReviewRecordScalarWhereInput[] + NOT?: Prisma.ReviewRecordScalarWhereInput | Prisma.ReviewRecordScalarWhereInput[] + id?: Prisma.StringFilter<"ReviewRecord"> | string + gameVersionId?: Prisma.StringFilter<"ReviewRecord"> | string + status?: Prisma.EnumReviewRecordStatusFilter<"ReviewRecord"> | $Enums.ReviewRecordStatus + decision?: Prisma.EnumReviewDecisionNullableFilter<"ReviewRecord"> | $Enums.ReviewDecision | null + reasonCode?: Prisma.StringNullableFilter<"ReviewRecord"> | string | null + decidedById?: Prisma.StringNullableFilter<"ReviewRecord"> | string | null + decidedAt?: Prisma.DateTimeNullableFilter<"ReviewRecord"> | Date | string | null + createdAt?: Prisma.DateTimeFilter<"ReviewRecord"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"ReviewRecord"> | Date | string +} + +export type ReviewRecordCreateWithoutGameVersionInput = { + id: string + status: $Enums.ReviewRecordStatus + decision?: $Enums.ReviewDecision | null + reasonCode?: string | null + decidedAt?: Date | string | null + createdAt?: Date | string + updatedAt?: Date | string + decidedBy?: Prisma.UserCreateNestedOneWithoutReviewDecisionsInput +} + +export type ReviewRecordUncheckedCreateWithoutGameVersionInput = { + id: string + status: $Enums.ReviewRecordStatus + decision?: $Enums.ReviewDecision | null + reasonCode?: string | null + decidedById?: string | null + decidedAt?: Date | string | null + createdAt?: Date | string + updatedAt?: Date | string +} + +export type ReviewRecordCreateOrConnectWithoutGameVersionInput = { + where: Prisma.ReviewRecordWhereUniqueInput + create: Prisma.XOR +} + +export type ReviewRecordCreateManyGameVersionInputEnvelope = { + data: Prisma.ReviewRecordCreateManyGameVersionInput | Prisma.ReviewRecordCreateManyGameVersionInput[] + skipDuplicates?: boolean +} + +export type ReviewRecordUpsertWithWhereUniqueWithoutGameVersionInput = { + where: Prisma.ReviewRecordWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type ReviewRecordUpdateWithWhereUniqueWithoutGameVersionInput = { + where: Prisma.ReviewRecordWhereUniqueInput + data: Prisma.XOR +} + +export type ReviewRecordUpdateManyWithWhereWithoutGameVersionInput = { + where: Prisma.ReviewRecordScalarWhereInput + data: Prisma.XOR +} + +export type ReviewRecordCreateManyDecidedByInput = { + id: string + gameVersionId: string + status: $Enums.ReviewRecordStatus + decision?: $Enums.ReviewDecision | null + reasonCode?: string | null + decidedAt?: Date | string | null + createdAt?: Date | string + updatedAt?: Date | string +} + +export type ReviewRecordUpdateWithoutDecidedByInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumReviewRecordStatusFieldUpdateOperationsInput | $Enums.ReviewRecordStatus + decision?: Prisma.NullableEnumReviewDecisionFieldUpdateOperationsInput | $Enums.ReviewDecision | null + reasonCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + gameVersion?: Prisma.GameVersionUpdateOneRequiredWithoutReviewRecordsNestedInput +} + +export type ReviewRecordUncheckedUpdateWithoutDecidedByInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + gameVersionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumReviewRecordStatusFieldUpdateOperationsInput | $Enums.ReviewRecordStatus + decision?: Prisma.NullableEnumReviewDecisionFieldUpdateOperationsInput | $Enums.ReviewDecision | null + reasonCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type ReviewRecordUncheckedUpdateManyWithoutDecidedByInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + gameVersionId?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumReviewRecordStatusFieldUpdateOperationsInput | $Enums.ReviewRecordStatus + decision?: Prisma.NullableEnumReviewDecisionFieldUpdateOperationsInput | $Enums.ReviewDecision | null + reasonCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type ReviewRecordCreateManyGameVersionInput = { + id: string + status: $Enums.ReviewRecordStatus + decision?: $Enums.ReviewDecision | null + reasonCode?: string | null + decidedById?: string | null + decidedAt?: Date | string | null + createdAt?: Date | string + updatedAt?: Date | string +} + +export type ReviewRecordUpdateWithoutGameVersionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumReviewRecordStatusFieldUpdateOperationsInput | $Enums.ReviewRecordStatus + decision?: Prisma.NullableEnumReviewDecisionFieldUpdateOperationsInput | $Enums.ReviewDecision | null + reasonCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + decidedBy?: Prisma.UserUpdateOneWithoutReviewDecisionsNestedInput +} + +export type ReviewRecordUncheckedUpdateWithoutGameVersionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumReviewRecordStatusFieldUpdateOperationsInput | $Enums.ReviewRecordStatus + decision?: Prisma.NullableEnumReviewDecisionFieldUpdateOperationsInput | $Enums.ReviewDecision | null + reasonCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedById?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type ReviewRecordUncheckedUpdateManyWithoutGameVersionInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumReviewRecordStatusFieldUpdateOperationsInput | $Enums.ReviewRecordStatus + decision?: Prisma.NullableEnumReviewDecisionFieldUpdateOperationsInput | $Enums.ReviewDecision | null + reasonCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedById?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + decidedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + + +export type ReviewRecordSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + gameVersionId?: boolean + status?: boolean + decision?: boolean + reasonCode?: boolean + decidedById?: boolean + decidedAt?: boolean + createdAt?: boolean + updatedAt?: boolean + gameVersion?: boolean | Prisma.GameVersionDefaultArgs + decidedBy?: boolean | Prisma.ReviewRecord$decidedByArgs +}, ExtArgs["result"]["reviewRecord"]> + +export type ReviewRecordSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + gameVersionId?: boolean + status?: boolean + decision?: boolean + reasonCode?: boolean + decidedById?: boolean + decidedAt?: boolean + createdAt?: boolean + updatedAt?: boolean + gameVersion?: boolean | Prisma.GameVersionDefaultArgs + decidedBy?: boolean | Prisma.ReviewRecord$decidedByArgs +}, ExtArgs["result"]["reviewRecord"]> + +export type ReviewRecordSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + gameVersionId?: boolean + status?: boolean + decision?: boolean + reasonCode?: boolean + decidedById?: boolean + decidedAt?: boolean + createdAt?: boolean + updatedAt?: boolean + gameVersion?: boolean | Prisma.GameVersionDefaultArgs + decidedBy?: boolean | Prisma.ReviewRecord$decidedByArgs +}, ExtArgs["result"]["reviewRecord"]> + +export type ReviewRecordSelectScalar = { + id?: boolean + gameVersionId?: boolean + status?: boolean + decision?: boolean + reasonCode?: boolean + decidedById?: boolean + decidedAt?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type ReviewRecordOmit = runtime.Types.Extensions.GetOmit<"id" | "gameVersionId" | "status" | "decision" | "reasonCode" | "decidedById" | "decidedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["reviewRecord"]> +export type ReviewRecordInclude = { + gameVersion?: boolean | Prisma.GameVersionDefaultArgs + decidedBy?: boolean | Prisma.ReviewRecord$decidedByArgs +} +export type ReviewRecordIncludeCreateManyAndReturn = { + gameVersion?: boolean | Prisma.GameVersionDefaultArgs + decidedBy?: boolean | Prisma.ReviewRecord$decidedByArgs +} +export type ReviewRecordIncludeUpdateManyAndReturn = { + gameVersion?: boolean | Prisma.GameVersionDefaultArgs + decidedBy?: boolean | Prisma.ReviewRecord$decidedByArgs +} + +export type $ReviewRecordPayload = { + name: "ReviewRecord" + objects: { + gameVersion: Prisma.$GameVersionPayload + decidedBy: Prisma.$UserPayload | null + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + gameVersionId: string + status: $Enums.ReviewRecordStatus + decision: $Enums.ReviewDecision | null + reasonCode: string | null + decidedById: string | null + decidedAt: Date | null + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["reviewRecord"]> + composites: {} +} + +export type ReviewRecordGetPayload = runtime.Types.Result.GetResult + +export type ReviewRecordCountArgs = + Omit & { + select?: ReviewRecordCountAggregateInputType | true + } + +export interface ReviewRecordDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['ReviewRecord'], meta: { name: 'ReviewRecord' } } + /** + * Find zero or one ReviewRecord that matches the filter. + * @param {ReviewRecordFindUniqueArgs} args - Arguments to find a ReviewRecord + * @example + * // Get one ReviewRecord + * const reviewRecord = await prisma.reviewRecord.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__ReviewRecordClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one ReviewRecord that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {ReviewRecordFindUniqueOrThrowArgs} args - Arguments to find a ReviewRecord + * @example + * // Get one ReviewRecord + * const reviewRecord = await prisma.reviewRecord.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__ReviewRecordClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first ReviewRecord that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ReviewRecordFindFirstArgs} args - Arguments to find a ReviewRecord + * @example + * // Get one ReviewRecord + * const reviewRecord = await prisma.reviewRecord.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__ReviewRecordClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first ReviewRecord that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ReviewRecordFindFirstOrThrowArgs} args - Arguments to find a ReviewRecord + * @example + * // Get one ReviewRecord + * const reviewRecord = await prisma.reviewRecord.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__ReviewRecordClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more ReviewRecords that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ReviewRecordFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all ReviewRecords + * const reviewRecords = await prisma.reviewRecord.findMany() + * + * // Get first 10 ReviewRecords + * const reviewRecords = await prisma.reviewRecord.findMany({ take: 10 }) + * + * // Only select the `id` + * const reviewRecordWithIdOnly = await prisma.reviewRecord.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a ReviewRecord. + * @param {ReviewRecordCreateArgs} args - Arguments to create a ReviewRecord. + * @example + * // Create one ReviewRecord + * const ReviewRecord = await prisma.reviewRecord.create({ + * data: { + * // ... data to create a ReviewRecord + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__ReviewRecordClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many ReviewRecords. + * @param {ReviewRecordCreateManyArgs} args - Arguments to create many ReviewRecords. + * @example + * // Create many ReviewRecords + * const reviewRecord = await prisma.reviewRecord.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many ReviewRecords and returns the data saved in the database. + * @param {ReviewRecordCreateManyAndReturnArgs} args - Arguments to create many ReviewRecords. + * @example + * // Create many ReviewRecords + * const reviewRecord = await prisma.reviewRecord.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many ReviewRecords and only return the `id` + * const reviewRecordWithIdOnly = await prisma.reviewRecord.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a ReviewRecord. + * @param {ReviewRecordDeleteArgs} args - Arguments to delete one ReviewRecord. + * @example + * // Delete one ReviewRecord + * const ReviewRecord = await prisma.reviewRecord.delete({ + * where: { + * // ... filter to delete one ReviewRecord + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__ReviewRecordClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one ReviewRecord. + * @param {ReviewRecordUpdateArgs} args - Arguments to update one ReviewRecord. + * @example + * // Update one ReviewRecord + * const reviewRecord = await prisma.reviewRecord.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__ReviewRecordClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more ReviewRecords. + * @param {ReviewRecordDeleteManyArgs} args - Arguments to filter ReviewRecords to delete. + * @example + * // Delete a few ReviewRecords + * const { count } = await prisma.reviewRecord.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more ReviewRecords. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ReviewRecordUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many ReviewRecords + * const reviewRecord = await prisma.reviewRecord.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more ReviewRecords and returns the data updated in the database. + * @param {ReviewRecordUpdateManyAndReturnArgs} args - Arguments to update many ReviewRecords. + * @example + * // Update many ReviewRecords + * const reviewRecord = await prisma.reviewRecord.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more ReviewRecords and only return the `id` + * const reviewRecordWithIdOnly = await prisma.reviewRecord.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one ReviewRecord. + * @param {ReviewRecordUpsertArgs} args - Arguments to update or create a ReviewRecord. + * @example + * // Update or create a ReviewRecord + * const reviewRecord = await prisma.reviewRecord.upsert({ + * create: { + * // ... data to create a ReviewRecord + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the ReviewRecord we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__ReviewRecordClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of ReviewRecords. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ReviewRecordCountArgs} args - Arguments to filter ReviewRecords to count. + * @example + * // Count the number of ReviewRecords + * const count = await prisma.reviewRecord.count({ + * where: { + * // ... the filter for the ReviewRecords we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a ReviewRecord. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ReviewRecordAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by ReviewRecord. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {ReviewRecordGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends ReviewRecordGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: ReviewRecordGroupByArgs['orderBy'] } + : { orderBy?: ReviewRecordGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetReviewRecordGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the ReviewRecord model + */ +readonly fields: ReviewRecordFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for ReviewRecord. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__ReviewRecordClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + gameVersion = {}>(args?: Prisma.Subset>): Prisma.Prisma__GameVersionClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + decidedBy = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the ReviewRecord model + */ +export interface ReviewRecordFieldRefs { + readonly id: Prisma.FieldRef<"ReviewRecord", 'String'> + readonly gameVersionId: Prisma.FieldRef<"ReviewRecord", 'String'> + readonly status: Prisma.FieldRef<"ReviewRecord", 'ReviewRecordStatus'> + readonly decision: Prisma.FieldRef<"ReviewRecord", 'ReviewDecision'> + readonly reasonCode: Prisma.FieldRef<"ReviewRecord", 'String'> + readonly decidedById: Prisma.FieldRef<"ReviewRecord", 'String'> + readonly decidedAt: Prisma.FieldRef<"ReviewRecord", 'DateTime'> + readonly createdAt: Prisma.FieldRef<"ReviewRecord", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"ReviewRecord", 'DateTime'> +} + + +// Custom InputTypes +/** + * ReviewRecord findUnique + */ +export type ReviewRecordFindUniqueArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + /** + * Filter, which ReviewRecord to fetch. + */ + where: Prisma.ReviewRecordWhereUniqueInput +} + +/** + * ReviewRecord findUniqueOrThrow + */ +export type ReviewRecordFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + /** + * Filter, which ReviewRecord to fetch. + */ + where: Prisma.ReviewRecordWhereUniqueInput +} + +/** + * ReviewRecord findFirst + */ +export type ReviewRecordFindFirstArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + /** + * Filter, which ReviewRecord to fetch. + */ + where?: Prisma.ReviewRecordWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of ReviewRecords to fetch. + */ + orderBy?: Prisma.ReviewRecordOrderByWithRelationInput | Prisma.ReviewRecordOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for ReviewRecords. + */ + cursor?: Prisma.ReviewRecordWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` ReviewRecords from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` ReviewRecords. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of ReviewRecords. + */ + distinct?: Prisma.ReviewRecordScalarFieldEnum | Prisma.ReviewRecordScalarFieldEnum[] +} + +/** + * ReviewRecord findFirstOrThrow + */ +export type ReviewRecordFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + /** + * Filter, which ReviewRecord to fetch. + */ + where?: Prisma.ReviewRecordWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of ReviewRecords to fetch. + */ + orderBy?: Prisma.ReviewRecordOrderByWithRelationInput | Prisma.ReviewRecordOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for ReviewRecords. + */ + cursor?: Prisma.ReviewRecordWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` ReviewRecords from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` ReviewRecords. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of ReviewRecords. + */ + distinct?: Prisma.ReviewRecordScalarFieldEnum | Prisma.ReviewRecordScalarFieldEnum[] +} + +/** + * ReviewRecord findMany + */ +export type ReviewRecordFindManyArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + /** + * Filter, which ReviewRecords to fetch. + */ + where?: Prisma.ReviewRecordWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of ReviewRecords to fetch. + */ + orderBy?: Prisma.ReviewRecordOrderByWithRelationInput | Prisma.ReviewRecordOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing ReviewRecords. + */ + cursor?: Prisma.ReviewRecordWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` ReviewRecords from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` ReviewRecords. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of ReviewRecords. + */ + distinct?: Prisma.ReviewRecordScalarFieldEnum | Prisma.ReviewRecordScalarFieldEnum[] +} + +/** + * ReviewRecord create + */ +export type ReviewRecordCreateArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + /** + * The data needed to create a ReviewRecord. + */ + data: Prisma.XOR +} + +/** + * ReviewRecord createMany + */ +export type ReviewRecordCreateManyArgs = { + /** + * The data used to create many ReviewRecords. + */ + data: Prisma.ReviewRecordCreateManyInput | Prisma.ReviewRecordCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * ReviewRecord createManyAndReturn + */ +export type ReviewRecordCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelectCreateManyAndReturn | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * The data used to create many ReviewRecords. + */ + data: Prisma.ReviewRecordCreateManyInput | Prisma.ReviewRecordCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordIncludeCreateManyAndReturn | null +} + +/** + * ReviewRecord update + */ +export type ReviewRecordUpdateArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + /** + * The data needed to update a ReviewRecord. + */ + data: Prisma.XOR + /** + * Choose, which ReviewRecord to update. + */ + where: Prisma.ReviewRecordWhereUniqueInput +} + +/** + * ReviewRecord updateMany + */ +export type ReviewRecordUpdateManyArgs = { + /** + * The data used to update ReviewRecords. + */ + data: Prisma.XOR + /** + * Filter which ReviewRecords to update + */ + where?: Prisma.ReviewRecordWhereInput + /** + * Limit how many ReviewRecords to update. + */ + limit?: number +} + +/** + * ReviewRecord updateManyAndReturn + */ +export type ReviewRecordUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * The data used to update ReviewRecords. + */ + data: Prisma.XOR + /** + * Filter which ReviewRecords to update + */ + where?: Prisma.ReviewRecordWhereInput + /** + * Limit how many ReviewRecords to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordIncludeUpdateManyAndReturn | null +} + +/** + * ReviewRecord upsert + */ +export type ReviewRecordUpsertArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + /** + * The filter to search for the ReviewRecord to update in case it exists. + */ + where: Prisma.ReviewRecordWhereUniqueInput + /** + * In case the ReviewRecord found by the `where` argument doesn't exist, create a new ReviewRecord with this data. + */ + create: Prisma.XOR + /** + * In case the ReviewRecord was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * ReviewRecord delete + */ +export type ReviewRecordDeleteArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + /** + * Filter which ReviewRecord to delete. + */ + where: Prisma.ReviewRecordWhereUniqueInput +} + +/** + * ReviewRecord deleteMany + */ +export type ReviewRecordDeleteManyArgs = { + /** + * Filter which ReviewRecords to delete + */ + where?: Prisma.ReviewRecordWhereInput + /** + * Limit how many ReviewRecords to delete. + */ + limit?: number +} + +/** + * ReviewRecord.decidedBy + */ +export type ReviewRecord$decidedByArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + where?: Prisma.UserWhereInput +} + +/** + * ReviewRecord without action + */ +export type ReviewRecordDefaultArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null +} diff --git a/apps/api/src/generated/prisma/models/User.ts b/apps/api/src/generated/prisma/models/User.ts new file mode 100644 index 00000000..f4d9ffb5 --- /dev/null +++ b/apps/api/src/generated/prisma/models/User.ts @@ -0,0 +1,2210 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `User` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model User + * + */ +export type UserModel = runtime.Types.Result.DefaultSelection + +export type AggregateUser = { + _count: UserCountAggregateOutputType | null + _min: UserMinAggregateOutputType | null + _max: UserMaxAggregateOutputType | null +} + +export type UserMinAggregateOutputType = { + id: string | null + email: string | null + displayName: string | null + status: $Enums.UserStatus | null + createdAt: Date | null + updatedAt: Date | null +} + +export type UserMaxAggregateOutputType = { + id: string | null + email: string | null + displayName: string | null + status: $Enums.UserStatus | null + createdAt: Date | null + updatedAt: Date | null +} + +export type UserCountAggregateOutputType = { + id: number + email: number + displayName: number + status: number + createdAt: number + updatedAt: number + _all: number +} + + +export type UserMinAggregateInputType = { + id?: true + email?: true + displayName?: true + status?: true + createdAt?: true + updatedAt?: true +} + +export type UserMaxAggregateInputType = { + id?: true + email?: true + displayName?: true + status?: true + createdAt?: true + updatedAt?: true +} + +export type UserCountAggregateInputType = { + id?: true + email?: true + displayName?: true + status?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type UserAggregateArgs = { + /** + * Filter which User to aggregate. + */ + where?: Prisma.UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: Prisma.UserOrderByWithRelationInput | Prisma.UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Users + **/ + _count?: true | UserCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: UserMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: UserMaxAggregateInputType +} + +export type GetUserAggregateType = { + [P in keyof T & keyof AggregateUser]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type UserGroupByArgs = { + where?: Prisma.UserWhereInput + orderBy?: Prisma.UserOrderByWithAggregationInput | Prisma.UserOrderByWithAggregationInput[] + by: Prisma.UserScalarFieldEnum[] | Prisma.UserScalarFieldEnum + having?: Prisma.UserScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: UserCountAggregateInputType | true + _min?: UserMinAggregateInputType + _max?: UserMaxAggregateInputType +} + +export type UserGroupByOutputType = { + id: string + email: string | null + displayName: string + status: $Enums.UserStatus + createdAt: Date + updatedAt: Date + _count: UserCountAggregateOutputType | null + _min: UserMinAggregateOutputType | null + _max: UserMaxAggregateOutputType | null +} + +export type GetUserGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof UserGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type UserWhereInput = { + AND?: Prisma.UserWhereInput | Prisma.UserWhereInput[] + OR?: Prisma.UserWhereInput[] + NOT?: Prisma.UserWhereInput | Prisma.UserWhereInput[] + id?: Prisma.StringFilter<"User"> | string + email?: Prisma.StringNullableFilter<"User"> | string | null + displayName?: Prisma.StringFilter<"User"> | string + status?: Prisma.EnumUserStatusFilter<"User"> | $Enums.UserStatus + createdAt?: Prisma.DateTimeFilter<"User"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string + roles?: Prisma.UserRoleListRelationFilter + anonymousIdentities?: Prisma.AnonymousIdentityListRelationFilter + gameProjects?: Prisma.GameProjectListRelationFilter + auditLogs?: Prisma.AuditLogListRelationFilter + jobs?: Prisma.JobListRelationFilter + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionListRelationFilter + reviewDecisions?: Prisma.ReviewRecordListRelationFilter +} + +export type UserOrderByWithRelationInput = { + id?: Prisma.SortOrder + email?: Prisma.SortOrderInput | Prisma.SortOrder + displayName?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + roles?: Prisma.UserRoleOrderByRelationAggregateInput + anonymousIdentities?: Prisma.AnonymousIdentityOrderByRelationAggregateInput + gameProjects?: Prisma.GameProjectOrderByRelationAggregateInput + auditLogs?: Prisma.AuditLogOrderByRelationAggregateInput + jobs?: Prisma.JobOrderByRelationAggregateInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionOrderByRelationAggregateInput + reviewDecisions?: Prisma.ReviewRecordOrderByRelationAggregateInput +} + +export type UserWhereUniqueInput = Prisma.AtLeast<{ + id?: string + email?: string + AND?: Prisma.UserWhereInput | Prisma.UserWhereInput[] + OR?: Prisma.UserWhereInput[] + NOT?: Prisma.UserWhereInput | Prisma.UserWhereInput[] + displayName?: Prisma.StringFilter<"User"> | string + status?: Prisma.EnumUserStatusFilter<"User"> | $Enums.UserStatus + createdAt?: Prisma.DateTimeFilter<"User"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string + roles?: Prisma.UserRoleListRelationFilter + anonymousIdentities?: Prisma.AnonymousIdentityListRelationFilter + gameProjects?: Prisma.GameProjectListRelationFilter + auditLogs?: Prisma.AuditLogListRelationFilter + jobs?: Prisma.JobListRelationFilter + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionListRelationFilter + reviewDecisions?: Prisma.ReviewRecordListRelationFilter +}, "id" | "email"> + +export type UserOrderByWithAggregationInput = { + id?: Prisma.SortOrder + email?: Prisma.SortOrderInput | Prisma.SortOrder + displayName?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.UserCountOrderByAggregateInput + _max?: Prisma.UserMaxOrderByAggregateInput + _min?: Prisma.UserMinOrderByAggregateInput +} + +export type UserScalarWhereWithAggregatesInput = { + AND?: Prisma.UserScalarWhereWithAggregatesInput | Prisma.UserScalarWhereWithAggregatesInput[] + OR?: Prisma.UserScalarWhereWithAggregatesInput[] + NOT?: Prisma.UserScalarWhereWithAggregatesInput | Prisma.UserScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"User"> | string + email?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null + displayName?: Prisma.StringWithAggregatesFilter<"User"> | string + status?: Prisma.EnumUserStatusWithAggregatesFilter<"User"> | $Enums.UserStatus + createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string +} + +export type UserCreateInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogCreateNestedManyWithoutActorInput + jobs?: Prisma.JobCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordCreateNestedManyWithoutDecidedByInput +} + +export type UserUncheckedCreateInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleUncheckedCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectUncheckedCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogUncheckedCreateNestedManyWithoutActorInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutDecidedByInput +} + +export type UserUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUpdateManyWithoutDecidedByNestedInput +} + +export type UserUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUncheckedUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUncheckedUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUncheckedUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUncheckedUpdateManyWithoutDecidedByNestedInput +} + +export type UserCreateManyInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string +} + +export type UserUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type UserUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type UserCountOrderByAggregateInput = { + id?: Prisma.SortOrder + email?: Prisma.SortOrder + displayName?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type UserMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + email?: Prisma.SortOrder + displayName?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type UserMinOrderByAggregateInput = { + id?: Prisma.SortOrder + email?: Prisma.SortOrder + displayName?: Prisma.SortOrder + status?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type UserScalarRelationFilter = { + is?: Prisma.UserWhereInput + isNot?: Prisma.UserWhereInput +} + +export type UserNullableScalarRelationFilter = { + is?: Prisma.UserWhereInput | null + isNot?: Prisma.UserWhereInput | null +} + +export type StringFieldUpdateOperationsInput = { + set?: string +} + +export type NullableStringFieldUpdateOperationsInput = { + set?: string | null +} + +export type EnumUserStatusFieldUpdateOperationsInput = { + set?: $Enums.UserStatus +} + +export type DateTimeFieldUpdateOperationsInput = { + set?: Date | string +} + +export type UserCreateNestedOneWithoutRolesInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutRolesInput + connect?: Prisma.UserWhereUniqueInput +} + +export type UserUpdateOneRequiredWithoutRolesNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutRolesInput + upsert?: Prisma.UserUpsertWithoutRolesInput + connect?: Prisma.UserWhereUniqueInput + update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutRolesInput> +} + +export type UserCreateNestedOneWithoutAnonymousIdentitiesInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutAnonymousIdentitiesInput + connect?: Prisma.UserWhereUniqueInput +} + +export type UserUpdateOneRequiredWithoutAnonymousIdentitiesNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutAnonymousIdentitiesInput + upsert?: Prisma.UserUpsertWithoutAnonymousIdentitiesInput + connect?: Prisma.UserWhereUniqueInput + update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutAnonymousIdentitiesInput> +} + +export type UserCreateNestedOneWithoutGameProjectsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutGameProjectsInput + connect?: Prisma.UserWhereUniqueInput +} + +export type UserUpdateOneRequiredWithoutGameProjectsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutGameProjectsInput + upsert?: Prisma.UserUpsertWithoutGameProjectsInput + connect?: Prisma.UserWhereUniqueInput + update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutGameProjectsInput> +} + +export type UserCreateNestedOneWithoutJobsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutJobsInput + connect?: Prisma.UserWhereUniqueInput +} + +export type UserUpdateOneRequiredWithoutJobsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutJobsInput + upsert?: Prisma.UserUpsertWithoutJobsInput + connect?: Prisma.UserWhereUniqueInput + update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutJobsInput> +} + +export type UserCreateNestedOneWithoutAuditLogsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutAuditLogsInput + connect?: Prisma.UserWhereUniqueInput +} + +export type UserUpdateOneRequiredWithoutAuditLogsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutAuditLogsInput + upsert?: Prisma.UserUpsertWithoutAuditLogsInput + connect?: Prisma.UserWhereUniqueInput + update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutAuditLogsInput> +} + +export type UserCreateNestedOneWithoutMainCreationAgentSessionsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutMainCreationAgentSessionsInput + connect?: Prisma.UserWhereUniqueInput +} + +export type UserUpdateOneRequiredWithoutMainCreationAgentSessionsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutMainCreationAgentSessionsInput + upsert?: Prisma.UserUpsertWithoutMainCreationAgentSessionsInput + connect?: Prisma.UserWhereUniqueInput + update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutMainCreationAgentSessionsInput> +} + +export type UserCreateNestedOneWithoutReviewDecisionsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutReviewDecisionsInput + connect?: Prisma.UserWhereUniqueInput +} + +export type UserUpdateOneWithoutReviewDecisionsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutReviewDecisionsInput + upsert?: Prisma.UserUpsertWithoutReviewDecisionsInput + disconnect?: Prisma.UserWhereInput | boolean + delete?: Prisma.UserWhereInput | boolean + connect?: Prisma.UserWhereUniqueInput + update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutReviewDecisionsInput> +} + +export type UserCreateWithoutRolesInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + anonymousIdentities?: Prisma.AnonymousIdentityCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogCreateNestedManyWithoutActorInput + jobs?: Prisma.JobCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordCreateNestedManyWithoutDecidedByInput +} + +export type UserUncheckedCreateWithoutRolesInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectUncheckedCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogUncheckedCreateNestedManyWithoutActorInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutDecidedByInput +} + +export type UserCreateOrConnectWithoutRolesInput = { + where: Prisma.UserWhereUniqueInput + create: Prisma.XOR +} + +export type UserUpsertWithoutRolesInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.UserWhereInput +} + +export type UserUpdateToOneWithWhereWithoutRolesInput = { + where?: Prisma.UserWhereInput + data: Prisma.XOR +} + +export type UserUpdateWithoutRolesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + anonymousIdentities?: Prisma.AnonymousIdentityUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUpdateManyWithoutDecidedByNestedInput +} + +export type UserUncheckedUpdateWithoutRolesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUncheckedUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUncheckedUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUncheckedUpdateManyWithoutDecidedByNestedInput +} + +export type UserCreateWithoutAnonymousIdentitiesInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogCreateNestedManyWithoutActorInput + jobs?: Prisma.JobCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordCreateNestedManyWithoutDecidedByInput +} + +export type UserUncheckedCreateWithoutAnonymousIdentitiesInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleUncheckedCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectUncheckedCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogUncheckedCreateNestedManyWithoutActorInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutDecidedByInput +} + +export type UserCreateOrConnectWithoutAnonymousIdentitiesInput = { + where: Prisma.UserWhereUniqueInput + create: Prisma.XOR +} + +export type UserUpsertWithoutAnonymousIdentitiesInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.UserWhereInput +} + +export type UserUpdateToOneWithWhereWithoutAnonymousIdentitiesInput = { + where?: Prisma.UserWhereInput + data: Prisma.XOR +} + +export type UserUpdateWithoutAnonymousIdentitiesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUpdateManyWithoutDecidedByNestedInput +} + +export type UserUncheckedUpdateWithoutAnonymousIdentitiesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUncheckedUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUncheckedUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUncheckedUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUncheckedUpdateManyWithoutDecidedByNestedInput +} + +export type UserCreateWithoutGameProjectsInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityCreateNestedManyWithoutUserInput + auditLogs?: Prisma.AuditLogCreateNestedManyWithoutActorInput + jobs?: Prisma.JobCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordCreateNestedManyWithoutDecidedByInput +} + +export type UserUncheckedCreateWithoutGameProjectsInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleUncheckedCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedCreateNestedManyWithoutUserInput + auditLogs?: Prisma.AuditLogUncheckedCreateNestedManyWithoutActorInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutDecidedByInput +} + +export type UserCreateOrConnectWithoutGameProjectsInput = { + where: Prisma.UserWhereUniqueInput + create: Prisma.XOR +} + +export type UserUpsertWithoutGameProjectsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.UserWhereInput +} + +export type UserUpdateToOneWithWhereWithoutGameProjectsInput = { + where?: Prisma.UserWhereInput + data: Prisma.XOR +} + +export type UserUpdateWithoutGameProjectsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUpdateManyWithoutUserNestedInput + auditLogs?: Prisma.AuditLogUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUpdateManyWithoutDecidedByNestedInput +} + +export type UserUncheckedUpdateWithoutGameProjectsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUncheckedUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedUpdateManyWithoutUserNestedInput + auditLogs?: Prisma.AuditLogUncheckedUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUncheckedUpdateManyWithoutDecidedByNestedInput +} + +export type UserCreateWithoutJobsInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordCreateNestedManyWithoutDecidedByInput +} + +export type UserUncheckedCreateWithoutJobsInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleUncheckedCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectUncheckedCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogUncheckedCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutDecidedByInput +} + +export type UserCreateOrConnectWithoutJobsInput = { + where: Prisma.UserWhereUniqueInput + create: Prisma.XOR +} + +export type UserUpsertWithoutJobsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.UserWhereInput +} + +export type UserUpdateToOneWithWhereWithoutJobsInput = { + where?: Prisma.UserWhereInput + data: Prisma.XOR +} + +export type UserUpdateWithoutJobsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUpdateManyWithoutDecidedByNestedInput +} + +export type UserUncheckedUpdateWithoutJobsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUncheckedUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUncheckedUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUncheckedUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUncheckedUpdateManyWithoutDecidedByNestedInput +} + +export type UserCreateWithoutAuditLogsInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectCreateNestedManyWithoutOwnerInput + jobs?: Prisma.JobCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordCreateNestedManyWithoutDecidedByInput +} + +export type UserUncheckedCreateWithoutAuditLogsInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleUncheckedCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectUncheckedCreateNestedManyWithoutOwnerInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutCreatorInput + reviewDecisions?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutDecidedByInput +} + +export type UserCreateOrConnectWithoutAuditLogsInput = { + where: Prisma.UserWhereUniqueInput + create: Prisma.XOR +} + +export type UserUpsertWithoutAuditLogsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.UserWhereInput +} + +export type UserUpdateToOneWithWhereWithoutAuditLogsInput = { + where?: Prisma.UserWhereInput + data: Prisma.XOR +} + +export type UserUpdateWithoutAuditLogsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUpdateManyWithoutOwnerNestedInput + jobs?: Prisma.JobUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUpdateManyWithoutDecidedByNestedInput +} + +export type UserUncheckedUpdateWithoutAuditLogsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUncheckedUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUncheckedUpdateManyWithoutOwnerNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutCreatorNestedInput + reviewDecisions?: Prisma.ReviewRecordUncheckedUpdateManyWithoutDecidedByNestedInput +} + +export type UserCreateWithoutMainCreationAgentSessionsInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogCreateNestedManyWithoutActorInput + jobs?: Prisma.JobCreateNestedManyWithoutActorInput + reviewDecisions?: Prisma.ReviewRecordCreateNestedManyWithoutDecidedByInput +} + +export type UserUncheckedCreateWithoutMainCreationAgentSessionsInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleUncheckedCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectUncheckedCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogUncheckedCreateNestedManyWithoutActorInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutActorInput + reviewDecisions?: Prisma.ReviewRecordUncheckedCreateNestedManyWithoutDecidedByInput +} + +export type UserCreateOrConnectWithoutMainCreationAgentSessionsInput = { + where: Prisma.UserWhereUniqueInput + create: Prisma.XOR +} + +export type UserUpsertWithoutMainCreationAgentSessionsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.UserWhereInput +} + +export type UserUpdateToOneWithWhereWithoutMainCreationAgentSessionsInput = { + where?: Prisma.UserWhereInput + data: Prisma.XOR +} + +export type UserUpdateWithoutMainCreationAgentSessionsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUpdateManyWithoutActorNestedInput + reviewDecisions?: Prisma.ReviewRecordUpdateManyWithoutDecidedByNestedInput +} + +export type UserUncheckedUpdateWithoutMainCreationAgentSessionsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUncheckedUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUncheckedUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUncheckedUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutActorNestedInput + reviewDecisions?: Prisma.ReviewRecordUncheckedUpdateManyWithoutDecidedByNestedInput +} + +export type UserCreateWithoutReviewDecisionsInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogCreateNestedManyWithoutActorInput + jobs?: Prisma.JobCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionCreateNestedManyWithoutCreatorInput +} + +export type UserUncheckedCreateWithoutReviewDecisionsInput = { + id: string + email?: string | null + displayName: string + status?: $Enums.UserStatus + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.UserRoleUncheckedCreateNestedManyWithoutUserInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedCreateNestedManyWithoutUserInput + gameProjects?: Prisma.GameProjectUncheckedCreateNestedManyWithoutOwnerInput + auditLogs?: Prisma.AuditLogUncheckedCreateNestedManyWithoutActorInput + jobs?: Prisma.JobUncheckedCreateNestedManyWithoutActorInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedCreateNestedManyWithoutCreatorInput +} + +export type UserCreateOrConnectWithoutReviewDecisionsInput = { + where: Prisma.UserWhereUniqueInput + create: Prisma.XOR +} + +export type UserUpsertWithoutReviewDecisionsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.UserWhereInput +} + +export type UserUpdateToOneWithWhereWithoutReviewDecisionsInput = { + where?: Prisma.UserWhereInput + data: Prisma.XOR +} + +export type UserUpdateWithoutReviewDecisionsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUpdateManyWithoutCreatorNestedInput +} + +export type UserUncheckedUpdateWithoutReviewDecisionsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + email?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + displayName?: Prisma.StringFieldUpdateOperationsInput | string + status?: Prisma.EnumUserStatusFieldUpdateOperationsInput | $Enums.UserStatus + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.UserRoleUncheckedUpdateManyWithoutUserNestedInput + anonymousIdentities?: Prisma.AnonymousIdentityUncheckedUpdateManyWithoutUserNestedInput + gameProjects?: Prisma.GameProjectUncheckedUpdateManyWithoutOwnerNestedInput + auditLogs?: Prisma.AuditLogUncheckedUpdateManyWithoutActorNestedInput + jobs?: Prisma.JobUncheckedUpdateManyWithoutActorNestedInput + mainCreationAgentSessions?: Prisma.MainCreationAgentSessionUncheckedUpdateManyWithoutCreatorNestedInput +} + + +/** + * Count Type UserCountOutputType + */ + +export type UserCountOutputType = { + roles: number + anonymousIdentities: number + gameProjects: number + auditLogs: number + jobs: number + mainCreationAgentSessions: number + reviewDecisions: number +} + +export type UserCountOutputTypeSelect = { + roles?: boolean | UserCountOutputTypeCountRolesArgs + anonymousIdentities?: boolean | UserCountOutputTypeCountAnonymousIdentitiesArgs + gameProjects?: boolean | UserCountOutputTypeCountGameProjectsArgs + auditLogs?: boolean | UserCountOutputTypeCountAuditLogsArgs + jobs?: boolean | UserCountOutputTypeCountJobsArgs + mainCreationAgentSessions?: boolean | UserCountOutputTypeCountMainCreationAgentSessionsArgs + reviewDecisions?: boolean | UserCountOutputTypeCountReviewDecisionsArgs +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeDefaultArgs = { + /** + * Select specific fields to fetch from the UserCountOutputType + */ + select?: Prisma.UserCountOutputTypeSelect | null +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeCountRolesArgs = { + where?: Prisma.UserRoleWhereInput +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeCountAnonymousIdentitiesArgs = { + where?: Prisma.AnonymousIdentityWhereInput +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeCountGameProjectsArgs = { + where?: Prisma.GameProjectWhereInput +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeCountAuditLogsArgs = { + where?: Prisma.AuditLogWhereInput +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeCountJobsArgs = { + where?: Prisma.JobWhereInput +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeCountMainCreationAgentSessionsArgs = { + where?: Prisma.MainCreationAgentSessionWhereInput +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeCountReviewDecisionsArgs = { + where?: Prisma.ReviewRecordWhereInput +} + + +export type UserSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + email?: boolean + displayName?: boolean + status?: boolean + createdAt?: boolean + updatedAt?: boolean + roles?: boolean | Prisma.User$rolesArgs + anonymousIdentities?: boolean | Prisma.User$anonymousIdentitiesArgs + gameProjects?: boolean | Prisma.User$gameProjectsArgs + auditLogs?: boolean | Prisma.User$auditLogsArgs + jobs?: boolean | Prisma.User$jobsArgs + mainCreationAgentSessions?: boolean | Prisma.User$mainCreationAgentSessionsArgs + reviewDecisions?: boolean | Prisma.User$reviewDecisionsArgs + _count?: boolean | Prisma.UserCountOutputTypeDefaultArgs +}, ExtArgs["result"]["user"]> + +export type UserSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + email?: boolean + displayName?: boolean + status?: boolean + createdAt?: boolean + updatedAt?: boolean +}, ExtArgs["result"]["user"]> + +export type UserSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + email?: boolean + displayName?: boolean + status?: boolean + createdAt?: boolean + updatedAt?: boolean +}, ExtArgs["result"]["user"]> + +export type UserSelectScalar = { + id?: boolean + email?: boolean + displayName?: boolean + status?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type UserOmit = runtime.Types.Extensions.GetOmit<"id" | "email" | "displayName" | "status" | "createdAt" | "updatedAt", ExtArgs["result"]["user"]> +export type UserInclude = { + roles?: boolean | Prisma.User$rolesArgs + anonymousIdentities?: boolean | Prisma.User$anonymousIdentitiesArgs + gameProjects?: boolean | Prisma.User$gameProjectsArgs + auditLogs?: boolean | Prisma.User$auditLogsArgs + jobs?: boolean | Prisma.User$jobsArgs + mainCreationAgentSessions?: boolean | Prisma.User$mainCreationAgentSessionsArgs + reviewDecisions?: boolean | Prisma.User$reviewDecisionsArgs + _count?: boolean | Prisma.UserCountOutputTypeDefaultArgs +} +export type UserIncludeCreateManyAndReturn = {} +export type UserIncludeUpdateManyAndReturn = {} + +export type $UserPayload = { + name: "User" + objects: { + roles: Prisma.$UserRolePayload[] + anonymousIdentities: Prisma.$AnonymousIdentityPayload[] + gameProjects: Prisma.$GameProjectPayload[] + auditLogs: Prisma.$AuditLogPayload[] + jobs: Prisma.$JobPayload[] + mainCreationAgentSessions: Prisma.$MainCreationAgentSessionPayload[] + reviewDecisions: Prisma.$ReviewRecordPayload[] + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + email: string | null + displayName: string + status: $Enums.UserStatus + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["user"]> + composites: {} +} + +export type UserGetPayload = runtime.Types.Result.GetResult + +export type UserCountArgs = + Omit & { + select?: UserCountAggregateInputType | true + } + +export interface UserDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['User'], meta: { name: 'User' } } + /** + * Find zero or one User that matches the filter. + * @param {UserFindUniqueArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one User that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {UserFindUniqueOrThrowArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first User that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindFirstArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first User that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindFirstOrThrowArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Users that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Users + * const users = await prisma.user.findMany() + * + * // Get first 10 Users + * const users = await prisma.user.findMany({ take: 10 }) + * + * // Only select the `id` + * const userWithIdOnly = await prisma.user.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a User. + * @param {UserCreateArgs} args - Arguments to create a User. + * @example + * // Create one User + * const User = await prisma.user.create({ + * data: { + * // ... data to create a User + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Users. + * @param {UserCreateManyArgs} args - Arguments to create many Users. + * @example + * // Create many Users + * const user = await prisma.user.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Users and returns the data saved in the database. + * @param {UserCreateManyAndReturnArgs} args - Arguments to create many Users. + * @example + * // Create many Users + * const user = await prisma.user.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Users and only return the `id` + * const userWithIdOnly = await prisma.user.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a User. + * @param {UserDeleteArgs} args - Arguments to delete one User. + * @example + * // Delete one User + * const User = await prisma.user.delete({ + * where: { + * // ... filter to delete one User + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one User. + * @param {UserUpdateArgs} args - Arguments to update one User. + * @example + * // Update one User + * const user = await prisma.user.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Users. + * @param {UserDeleteManyArgs} args - Arguments to filter Users to delete. + * @example + * // Delete a few Users + * const { count } = await prisma.user.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Users. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Users + * const user = await prisma.user.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Users and returns the data updated in the database. + * @param {UserUpdateManyAndReturnArgs} args - Arguments to update many Users. + * @example + * // Update many Users + * const user = await prisma.user.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Users and only return the `id` + * const userWithIdOnly = await prisma.user.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one User. + * @param {UserUpsertArgs} args - Arguments to update or create a User. + * @example + * // Update or create a User + * const user = await prisma.user.upsert({ + * create: { + * // ... data to create a User + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the User we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Users. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserCountArgs} args - Arguments to filter Users to count. + * @example + * // Count the number of Users + * const count = await prisma.user.count({ + * where: { + * // ... the filter for the Users we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a User. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by User. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends UserGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: UserGroupByArgs['orderBy'] } + : { orderBy?: UserGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetUserGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the User model + */ +readonly fields: UserFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for User. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__UserClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + roles = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + anonymousIdentities = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + gameProjects = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + auditLogs = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + jobs = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + mainCreationAgentSessions = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + reviewDecisions = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the User model + */ +export interface UserFieldRefs { + readonly id: Prisma.FieldRef<"User", 'String'> + readonly email: Prisma.FieldRef<"User", 'String'> + readonly displayName: Prisma.FieldRef<"User", 'String'> + readonly status: Prisma.FieldRef<"User", 'UserStatus'> + readonly createdAt: Prisma.FieldRef<"User", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"User", 'DateTime'> +} + + +// Custom InputTypes +/** + * User findUnique + */ +export type UserFindUniqueArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter, which User to fetch. + */ + where: Prisma.UserWhereUniqueInput +} + +/** + * User findUniqueOrThrow + */ +export type UserFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter, which User to fetch. + */ + where: Prisma.UserWhereUniqueInput +} + +/** + * User findFirst + */ +export type UserFindFirstArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter, which User to fetch. + */ + where?: Prisma.UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: Prisma.UserOrderByWithRelationInput | Prisma.UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Users. + */ + cursor?: Prisma.UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Users. + */ + distinct?: Prisma.UserScalarFieldEnum | Prisma.UserScalarFieldEnum[] +} + +/** + * User findFirstOrThrow + */ +export type UserFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter, which User to fetch. + */ + where?: Prisma.UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: Prisma.UserOrderByWithRelationInput | Prisma.UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Users. + */ + cursor?: Prisma.UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Users. + */ + distinct?: Prisma.UserScalarFieldEnum | Prisma.UserScalarFieldEnum[] +} + +/** + * User findMany + */ +export type UserFindManyArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter, which Users to fetch. + */ + where?: Prisma.UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: Prisma.UserOrderByWithRelationInput | Prisma.UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Users. + */ + cursor?: Prisma.UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Users. + */ + distinct?: Prisma.UserScalarFieldEnum | Prisma.UserScalarFieldEnum[] +} + +/** + * User create + */ +export type UserCreateArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * The data needed to create a User. + */ + data: Prisma.XOR +} + +/** + * User createMany + */ +export type UserCreateManyArgs = { + /** + * The data used to create many Users. + */ + data: Prisma.UserCreateManyInput | Prisma.UserCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * User createManyAndReturn + */ +export type UserCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelectCreateManyAndReturn | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * The data used to create many Users. + */ + data: Prisma.UserCreateManyInput | Prisma.UserCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * User update + */ +export type UserUpdateArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * The data needed to update a User. + */ + data: Prisma.XOR + /** + * Choose, which User to update. + */ + where: Prisma.UserWhereUniqueInput +} + +/** + * User updateMany + */ +export type UserUpdateManyArgs = { + /** + * The data used to update Users. + */ + data: Prisma.XOR + /** + * Filter which Users to update + */ + where?: Prisma.UserWhereInput + /** + * Limit how many Users to update. + */ + limit?: number +} + +/** + * User updateManyAndReturn + */ +export type UserUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * The data used to update Users. + */ + data: Prisma.XOR + /** + * Filter which Users to update + */ + where?: Prisma.UserWhereInput + /** + * Limit how many Users to update. + */ + limit?: number +} + +/** + * User upsert + */ +export type UserUpsertArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * The filter to search for the User to update in case it exists. + */ + where: Prisma.UserWhereUniqueInput + /** + * In case the User found by the `where` argument doesn't exist, create a new User with this data. + */ + create: Prisma.XOR + /** + * In case the User was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * User delete + */ +export type UserDeleteArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter which User to delete. + */ + where: Prisma.UserWhereUniqueInput +} + +/** + * User deleteMany + */ +export type UserDeleteManyArgs = { + /** + * Filter which Users to delete + */ + where?: Prisma.UserWhereInput + /** + * Limit how many Users to delete. + */ + limit?: number +} + +/** + * User.roles + */ +export type User$rolesArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null + where?: Prisma.UserRoleWhereInput + orderBy?: Prisma.UserRoleOrderByWithRelationInput | Prisma.UserRoleOrderByWithRelationInput[] + cursor?: Prisma.UserRoleWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.UserRoleScalarFieldEnum | Prisma.UserRoleScalarFieldEnum[] +} + +/** + * User.anonymousIdentities + */ +export type User$anonymousIdentitiesArgs = { + /** + * Select specific fields to fetch from the AnonymousIdentity + */ + select?: Prisma.AnonymousIdentitySelect | null + /** + * Omit specific fields from the AnonymousIdentity + */ + omit?: Prisma.AnonymousIdentityOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AnonymousIdentityInclude | null + where?: Prisma.AnonymousIdentityWhereInput + orderBy?: Prisma.AnonymousIdentityOrderByWithRelationInput | Prisma.AnonymousIdentityOrderByWithRelationInput[] + cursor?: Prisma.AnonymousIdentityWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.AnonymousIdentityScalarFieldEnum | Prisma.AnonymousIdentityScalarFieldEnum[] +} + +/** + * User.gameProjects + */ +export type User$gameProjectsArgs = { + /** + * Select specific fields to fetch from the GameProject + */ + select?: Prisma.GameProjectSelect | null + /** + * Omit specific fields from the GameProject + */ + omit?: Prisma.GameProjectOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.GameProjectInclude | null + where?: Prisma.GameProjectWhereInput + orderBy?: Prisma.GameProjectOrderByWithRelationInput | Prisma.GameProjectOrderByWithRelationInput[] + cursor?: Prisma.GameProjectWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.GameProjectScalarFieldEnum | Prisma.GameProjectScalarFieldEnum[] +} + +/** + * User.auditLogs + */ +export type User$auditLogsArgs = { + /** + * Select specific fields to fetch from the AuditLog + */ + select?: Prisma.AuditLogSelect | null + /** + * Omit specific fields from the AuditLog + */ + omit?: Prisma.AuditLogOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.AuditLogInclude | null + where?: Prisma.AuditLogWhereInput + orderBy?: Prisma.AuditLogOrderByWithRelationInput | Prisma.AuditLogOrderByWithRelationInput[] + cursor?: Prisma.AuditLogWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.AuditLogScalarFieldEnum | Prisma.AuditLogScalarFieldEnum[] +} + +/** + * User.jobs + */ +export type User$jobsArgs = { + /** + * Select specific fields to fetch from the Job + */ + select?: Prisma.JobSelect | null + /** + * Omit specific fields from the Job + */ + omit?: Prisma.JobOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.JobInclude | null + where?: Prisma.JobWhereInput + orderBy?: Prisma.JobOrderByWithRelationInput | Prisma.JobOrderByWithRelationInput[] + cursor?: Prisma.JobWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.JobScalarFieldEnum | Prisma.JobScalarFieldEnum[] +} + +/** + * User.mainCreationAgentSessions + */ +export type User$mainCreationAgentSessionsArgs = { + /** + * Select specific fields to fetch from the MainCreationAgentSession + */ + select?: Prisma.MainCreationAgentSessionSelect | null + /** + * Omit specific fields from the MainCreationAgentSession + */ + omit?: Prisma.MainCreationAgentSessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.MainCreationAgentSessionInclude | null + where?: Prisma.MainCreationAgentSessionWhereInput + orderBy?: Prisma.MainCreationAgentSessionOrderByWithRelationInput | Prisma.MainCreationAgentSessionOrderByWithRelationInput[] + cursor?: Prisma.MainCreationAgentSessionWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.MainCreationAgentSessionScalarFieldEnum | Prisma.MainCreationAgentSessionScalarFieldEnum[] +} + +/** + * User.reviewDecisions + */ +export type User$reviewDecisionsArgs = { + /** + * Select specific fields to fetch from the ReviewRecord + */ + select?: Prisma.ReviewRecordSelect | null + /** + * Omit specific fields from the ReviewRecord + */ + omit?: Prisma.ReviewRecordOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.ReviewRecordInclude | null + where?: Prisma.ReviewRecordWhereInput + orderBy?: Prisma.ReviewRecordOrderByWithRelationInput | Prisma.ReviewRecordOrderByWithRelationInput[] + cursor?: Prisma.ReviewRecordWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.ReviewRecordScalarFieldEnum | Prisma.ReviewRecordScalarFieldEnum[] +} + +/** + * User without action + */ +export type UserDefaultArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null +} diff --git a/apps/api/src/generated/prisma/models/UserRole.ts b/apps/api/src/generated/prisma/models/UserRole.ts new file mode 100644 index 00000000..95adaf07 --- /dev/null +++ b/apps/api/src/generated/prisma/models/UserRole.ts @@ -0,0 +1,1320 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `UserRole` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.js" +import type * as Prisma from "../internal/prismaNamespace.js" + +/** + * Model UserRole + * + */ +export type UserRoleModel = runtime.Types.Result.DefaultSelection + +export type AggregateUserRole = { + _count: UserRoleCountAggregateOutputType | null + _min: UserRoleMinAggregateOutputType | null + _max: UserRoleMaxAggregateOutputType | null +} + +export type UserRoleMinAggregateOutputType = { + id: string | null + userId: string | null + role: $Enums.UserRoleName | null + createdAt: Date | null +} + +export type UserRoleMaxAggregateOutputType = { + id: string | null + userId: string | null + role: $Enums.UserRoleName | null + createdAt: Date | null +} + +export type UserRoleCountAggregateOutputType = { + id: number + userId: number + role: number + createdAt: number + _all: number +} + + +export type UserRoleMinAggregateInputType = { + id?: true + userId?: true + role?: true + createdAt?: true +} + +export type UserRoleMaxAggregateInputType = { + id?: true + userId?: true + role?: true + createdAt?: true +} + +export type UserRoleCountAggregateInputType = { + id?: true + userId?: true + role?: true + createdAt?: true + _all?: true +} + +export type UserRoleAggregateArgs = { + /** + * Filter which UserRole to aggregate. + */ + where?: Prisma.UserRoleWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of UserRoles to fetch. + */ + orderBy?: Prisma.UserRoleOrderByWithRelationInput | Prisma.UserRoleOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.UserRoleWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` UserRoles from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` UserRoles. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned UserRoles + **/ + _count?: true | UserRoleCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: UserRoleMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: UserRoleMaxAggregateInputType +} + +export type GetUserRoleAggregateType = { + [P in keyof T & keyof AggregateUserRole]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type UserRoleGroupByArgs = { + where?: Prisma.UserRoleWhereInput + orderBy?: Prisma.UserRoleOrderByWithAggregationInput | Prisma.UserRoleOrderByWithAggregationInput[] + by: Prisma.UserRoleScalarFieldEnum[] | Prisma.UserRoleScalarFieldEnum + having?: Prisma.UserRoleScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: UserRoleCountAggregateInputType | true + _min?: UserRoleMinAggregateInputType + _max?: UserRoleMaxAggregateInputType +} + +export type UserRoleGroupByOutputType = { + id: string + userId: string + role: $Enums.UserRoleName + createdAt: Date + _count: UserRoleCountAggregateOutputType | null + _min: UserRoleMinAggregateOutputType | null + _max: UserRoleMaxAggregateOutputType | null +} + +export type GetUserRoleGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof UserRoleGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type UserRoleWhereInput = { + AND?: Prisma.UserRoleWhereInput | Prisma.UserRoleWhereInput[] + OR?: Prisma.UserRoleWhereInput[] + NOT?: Prisma.UserRoleWhereInput | Prisma.UserRoleWhereInput[] + id?: Prisma.StringFilter<"UserRole"> | string + userId?: Prisma.StringFilter<"UserRole"> | string + role?: Prisma.EnumUserRoleNameFilter<"UserRole"> | $Enums.UserRoleName + createdAt?: Prisma.DateTimeFilter<"UserRole"> | Date | string + user?: Prisma.XOR +} + +export type UserRoleOrderByWithRelationInput = { + id?: Prisma.SortOrder + userId?: Prisma.SortOrder + role?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + user?: Prisma.UserOrderByWithRelationInput +} + +export type UserRoleWhereUniqueInput = Prisma.AtLeast<{ + id?: string + userId_role?: Prisma.UserRoleUserIdRoleCompoundUniqueInput + AND?: Prisma.UserRoleWhereInput | Prisma.UserRoleWhereInput[] + OR?: Prisma.UserRoleWhereInput[] + NOT?: Prisma.UserRoleWhereInput | Prisma.UserRoleWhereInput[] + userId?: Prisma.StringFilter<"UserRole"> | string + role?: Prisma.EnumUserRoleNameFilter<"UserRole"> | $Enums.UserRoleName + createdAt?: Prisma.DateTimeFilter<"UserRole"> | Date | string + user?: Prisma.XOR +}, "id" | "userId_role"> + +export type UserRoleOrderByWithAggregationInput = { + id?: Prisma.SortOrder + userId?: Prisma.SortOrder + role?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + _count?: Prisma.UserRoleCountOrderByAggregateInput + _max?: Prisma.UserRoleMaxOrderByAggregateInput + _min?: Prisma.UserRoleMinOrderByAggregateInput +} + +export type UserRoleScalarWhereWithAggregatesInput = { + AND?: Prisma.UserRoleScalarWhereWithAggregatesInput | Prisma.UserRoleScalarWhereWithAggregatesInput[] + OR?: Prisma.UserRoleScalarWhereWithAggregatesInput[] + NOT?: Prisma.UserRoleScalarWhereWithAggregatesInput | Prisma.UserRoleScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"UserRole"> | string + userId?: Prisma.StringWithAggregatesFilter<"UserRole"> | string + role?: Prisma.EnumUserRoleNameWithAggregatesFilter<"UserRole"> | $Enums.UserRoleName + createdAt?: Prisma.DateTimeWithAggregatesFilter<"UserRole"> | Date | string +} + +export type UserRoleCreateInput = { + id?: string + role: $Enums.UserRoleName + createdAt?: Date | string + user: Prisma.UserCreateNestedOneWithoutRolesInput +} + +export type UserRoleUncheckedCreateInput = { + id?: string + userId: string + role: $Enums.UserRoleName + createdAt?: Date | string +} + +export type UserRoleUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + role?: Prisma.EnumUserRoleNameFieldUpdateOperationsInput | $Enums.UserRoleName + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + user?: Prisma.UserUpdateOneRequiredWithoutRolesNestedInput +} + +export type UserRoleUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + userId?: Prisma.StringFieldUpdateOperationsInput | string + role?: Prisma.EnumUserRoleNameFieldUpdateOperationsInput | $Enums.UserRoleName + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type UserRoleCreateManyInput = { + id?: string + userId: string + role: $Enums.UserRoleName + createdAt?: Date | string +} + +export type UserRoleUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + role?: Prisma.EnumUserRoleNameFieldUpdateOperationsInput | $Enums.UserRoleName + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type UserRoleUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + userId?: Prisma.StringFieldUpdateOperationsInput | string + role?: Prisma.EnumUserRoleNameFieldUpdateOperationsInput | $Enums.UserRoleName + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type UserRoleListRelationFilter = { + every?: Prisma.UserRoleWhereInput + some?: Prisma.UserRoleWhereInput + none?: Prisma.UserRoleWhereInput +} + +export type UserRoleOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type UserRoleUserIdRoleCompoundUniqueInput = { + userId: string + role: $Enums.UserRoleName +} + +export type UserRoleCountOrderByAggregateInput = { + id?: Prisma.SortOrder + userId?: Prisma.SortOrder + role?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type UserRoleMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + userId?: Prisma.SortOrder + role?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type UserRoleMinOrderByAggregateInput = { + id?: Prisma.SortOrder + userId?: Prisma.SortOrder + role?: Prisma.SortOrder + createdAt?: Prisma.SortOrder +} + +export type UserRoleCreateNestedManyWithoutUserInput = { + create?: Prisma.XOR | Prisma.UserRoleCreateWithoutUserInput[] | Prisma.UserRoleUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.UserRoleCreateOrConnectWithoutUserInput | Prisma.UserRoleCreateOrConnectWithoutUserInput[] + createMany?: Prisma.UserRoleCreateManyUserInputEnvelope + connect?: Prisma.UserRoleWhereUniqueInput | Prisma.UserRoleWhereUniqueInput[] +} + +export type UserRoleUncheckedCreateNestedManyWithoutUserInput = { + create?: Prisma.XOR | Prisma.UserRoleCreateWithoutUserInput[] | Prisma.UserRoleUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.UserRoleCreateOrConnectWithoutUserInput | Prisma.UserRoleCreateOrConnectWithoutUserInput[] + createMany?: Prisma.UserRoleCreateManyUserInputEnvelope + connect?: Prisma.UserRoleWhereUniqueInput | Prisma.UserRoleWhereUniqueInput[] +} + +export type UserRoleUpdateManyWithoutUserNestedInput = { + create?: Prisma.XOR | Prisma.UserRoleCreateWithoutUserInput[] | Prisma.UserRoleUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.UserRoleCreateOrConnectWithoutUserInput | Prisma.UserRoleCreateOrConnectWithoutUserInput[] + upsert?: Prisma.UserRoleUpsertWithWhereUniqueWithoutUserInput | Prisma.UserRoleUpsertWithWhereUniqueWithoutUserInput[] + createMany?: Prisma.UserRoleCreateManyUserInputEnvelope + set?: Prisma.UserRoleWhereUniqueInput | Prisma.UserRoleWhereUniqueInput[] + disconnect?: Prisma.UserRoleWhereUniqueInput | Prisma.UserRoleWhereUniqueInput[] + delete?: Prisma.UserRoleWhereUniqueInput | Prisma.UserRoleWhereUniqueInput[] + connect?: Prisma.UserRoleWhereUniqueInput | Prisma.UserRoleWhereUniqueInput[] + update?: Prisma.UserRoleUpdateWithWhereUniqueWithoutUserInput | Prisma.UserRoleUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: Prisma.UserRoleUpdateManyWithWhereWithoutUserInput | Prisma.UserRoleUpdateManyWithWhereWithoutUserInput[] + deleteMany?: Prisma.UserRoleScalarWhereInput | Prisma.UserRoleScalarWhereInput[] +} + +export type UserRoleUncheckedUpdateManyWithoutUserNestedInput = { + create?: Prisma.XOR | Prisma.UserRoleCreateWithoutUserInput[] | Prisma.UserRoleUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.UserRoleCreateOrConnectWithoutUserInput | Prisma.UserRoleCreateOrConnectWithoutUserInput[] + upsert?: Prisma.UserRoleUpsertWithWhereUniqueWithoutUserInput | Prisma.UserRoleUpsertWithWhereUniqueWithoutUserInput[] + createMany?: Prisma.UserRoleCreateManyUserInputEnvelope + set?: Prisma.UserRoleWhereUniqueInput | Prisma.UserRoleWhereUniqueInput[] + disconnect?: Prisma.UserRoleWhereUniqueInput | Prisma.UserRoleWhereUniqueInput[] + delete?: Prisma.UserRoleWhereUniqueInput | Prisma.UserRoleWhereUniqueInput[] + connect?: Prisma.UserRoleWhereUniqueInput | Prisma.UserRoleWhereUniqueInput[] + update?: Prisma.UserRoleUpdateWithWhereUniqueWithoutUserInput | Prisma.UserRoleUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: Prisma.UserRoleUpdateManyWithWhereWithoutUserInput | Prisma.UserRoleUpdateManyWithWhereWithoutUserInput[] + deleteMany?: Prisma.UserRoleScalarWhereInput | Prisma.UserRoleScalarWhereInput[] +} + +export type EnumUserRoleNameFieldUpdateOperationsInput = { + set?: $Enums.UserRoleName +} + +export type UserRoleCreateWithoutUserInput = { + id?: string + role: $Enums.UserRoleName + createdAt?: Date | string +} + +export type UserRoleUncheckedCreateWithoutUserInput = { + id?: string + role: $Enums.UserRoleName + createdAt?: Date | string +} + +export type UserRoleCreateOrConnectWithoutUserInput = { + where: Prisma.UserRoleWhereUniqueInput + create: Prisma.XOR +} + +export type UserRoleCreateManyUserInputEnvelope = { + data: Prisma.UserRoleCreateManyUserInput | Prisma.UserRoleCreateManyUserInput[] + skipDuplicates?: boolean +} + +export type UserRoleUpsertWithWhereUniqueWithoutUserInput = { + where: Prisma.UserRoleWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type UserRoleUpdateWithWhereUniqueWithoutUserInput = { + where: Prisma.UserRoleWhereUniqueInput + data: Prisma.XOR +} + +export type UserRoleUpdateManyWithWhereWithoutUserInput = { + where: Prisma.UserRoleScalarWhereInput + data: Prisma.XOR +} + +export type UserRoleScalarWhereInput = { + AND?: Prisma.UserRoleScalarWhereInput | Prisma.UserRoleScalarWhereInput[] + OR?: Prisma.UserRoleScalarWhereInput[] + NOT?: Prisma.UserRoleScalarWhereInput | Prisma.UserRoleScalarWhereInput[] + id?: Prisma.StringFilter<"UserRole"> | string + userId?: Prisma.StringFilter<"UserRole"> | string + role?: Prisma.EnumUserRoleNameFilter<"UserRole"> | $Enums.UserRoleName + createdAt?: Prisma.DateTimeFilter<"UserRole"> | Date | string +} + +export type UserRoleCreateManyUserInput = { + id?: string + role: $Enums.UserRoleName + createdAt?: Date | string +} + +export type UserRoleUpdateWithoutUserInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + role?: Prisma.EnumUserRoleNameFieldUpdateOperationsInput | $Enums.UserRoleName + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type UserRoleUncheckedUpdateWithoutUserInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + role?: Prisma.EnumUserRoleNameFieldUpdateOperationsInput | $Enums.UserRoleName + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type UserRoleUncheckedUpdateManyWithoutUserInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + role?: Prisma.EnumUserRoleNameFieldUpdateOperationsInput | $Enums.UserRoleName + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + + +export type UserRoleSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + userId?: boolean + role?: boolean + createdAt?: boolean + user?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["userRole"]> + +export type UserRoleSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + userId?: boolean + role?: boolean + createdAt?: boolean + user?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["userRole"]> + +export type UserRoleSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + userId?: boolean + role?: boolean + createdAt?: boolean + user?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["userRole"]> + +export type UserRoleSelectScalar = { + id?: boolean + userId?: boolean + role?: boolean + createdAt?: boolean +} + +export type UserRoleOmit = runtime.Types.Extensions.GetOmit<"id" | "userId" | "role" | "createdAt", ExtArgs["result"]["userRole"]> +export type UserRoleInclude = { + user?: boolean | Prisma.UserDefaultArgs +} +export type UserRoleIncludeCreateManyAndReturn = { + user?: boolean | Prisma.UserDefaultArgs +} +export type UserRoleIncludeUpdateManyAndReturn = { + user?: boolean | Prisma.UserDefaultArgs +} + +export type $UserRolePayload = { + name: "UserRole" + objects: { + user: Prisma.$UserPayload + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + userId: string + role: $Enums.UserRoleName + createdAt: Date + }, ExtArgs["result"]["userRole"]> + composites: {} +} + +export type UserRoleGetPayload = runtime.Types.Result.GetResult + +export type UserRoleCountArgs = + Omit & { + select?: UserRoleCountAggregateInputType | true + } + +export interface UserRoleDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['UserRole'], meta: { name: 'UserRole' } } + /** + * Find zero or one UserRole that matches the filter. + * @param {UserRoleFindUniqueArgs} args - Arguments to find a UserRole + * @example + * // Get one UserRole + * const userRole = await prisma.userRole.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__UserRoleClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one UserRole that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {UserRoleFindUniqueOrThrowArgs} args - Arguments to find a UserRole + * @example + * // Get one UserRole + * const userRole = await prisma.userRole.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__UserRoleClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first UserRole that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserRoleFindFirstArgs} args - Arguments to find a UserRole + * @example + * // Get one UserRole + * const userRole = await prisma.userRole.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__UserRoleClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first UserRole that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserRoleFindFirstOrThrowArgs} args - Arguments to find a UserRole + * @example + * // Get one UserRole + * const userRole = await prisma.userRole.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__UserRoleClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more UserRoles that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserRoleFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all UserRoles + * const userRoles = await prisma.userRole.findMany() + * + * // Get first 10 UserRoles + * const userRoles = await prisma.userRole.findMany({ take: 10 }) + * + * // Only select the `id` + * const userRoleWithIdOnly = await prisma.userRole.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a UserRole. + * @param {UserRoleCreateArgs} args - Arguments to create a UserRole. + * @example + * // Create one UserRole + * const UserRole = await prisma.userRole.create({ + * data: { + * // ... data to create a UserRole + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__UserRoleClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many UserRoles. + * @param {UserRoleCreateManyArgs} args - Arguments to create many UserRoles. + * @example + * // Create many UserRoles + * const userRole = await prisma.userRole.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many UserRoles and returns the data saved in the database. + * @param {UserRoleCreateManyAndReturnArgs} args - Arguments to create many UserRoles. + * @example + * // Create many UserRoles + * const userRole = await prisma.userRole.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many UserRoles and only return the `id` + * const userRoleWithIdOnly = await prisma.userRole.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a UserRole. + * @param {UserRoleDeleteArgs} args - Arguments to delete one UserRole. + * @example + * // Delete one UserRole + * const UserRole = await prisma.userRole.delete({ + * where: { + * // ... filter to delete one UserRole + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__UserRoleClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one UserRole. + * @param {UserRoleUpdateArgs} args - Arguments to update one UserRole. + * @example + * // Update one UserRole + * const userRole = await prisma.userRole.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__UserRoleClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more UserRoles. + * @param {UserRoleDeleteManyArgs} args - Arguments to filter UserRoles to delete. + * @example + * // Delete a few UserRoles + * const { count } = await prisma.userRole.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more UserRoles. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserRoleUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many UserRoles + * const userRole = await prisma.userRole.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more UserRoles and returns the data updated in the database. + * @param {UserRoleUpdateManyAndReturnArgs} args - Arguments to update many UserRoles. + * @example + * // Update many UserRoles + * const userRole = await prisma.userRole.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more UserRoles and only return the `id` + * const userRoleWithIdOnly = await prisma.userRole.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one UserRole. + * @param {UserRoleUpsertArgs} args - Arguments to update or create a UserRole. + * @example + * // Update or create a UserRole + * const userRole = await prisma.userRole.upsert({ + * create: { + * // ... data to create a UserRole + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the UserRole we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__UserRoleClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of UserRoles. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserRoleCountArgs} args - Arguments to filter UserRoles to count. + * @example + * // Count the number of UserRoles + * const count = await prisma.userRole.count({ + * where: { + * // ... the filter for the UserRoles we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a UserRole. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserRoleAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by UserRole. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserRoleGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends UserRoleGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: UserRoleGroupByArgs['orderBy'] } + : { orderBy?: UserRoleGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetUserRoleGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the UserRole model + */ +readonly fields: UserRoleFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for UserRole. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__UserRoleClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + user = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the UserRole model + */ +export interface UserRoleFieldRefs { + readonly id: Prisma.FieldRef<"UserRole", 'String'> + readonly userId: Prisma.FieldRef<"UserRole", 'String'> + readonly role: Prisma.FieldRef<"UserRole", 'UserRoleName'> + readonly createdAt: Prisma.FieldRef<"UserRole", 'DateTime'> +} + + +// Custom InputTypes +/** + * UserRole findUnique + */ +export type UserRoleFindUniqueArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null + /** + * Filter, which UserRole to fetch. + */ + where: Prisma.UserRoleWhereUniqueInput +} + +/** + * UserRole findUniqueOrThrow + */ +export type UserRoleFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null + /** + * Filter, which UserRole to fetch. + */ + where: Prisma.UserRoleWhereUniqueInput +} + +/** + * UserRole findFirst + */ +export type UserRoleFindFirstArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null + /** + * Filter, which UserRole to fetch. + */ + where?: Prisma.UserRoleWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of UserRoles to fetch. + */ + orderBy?: Prisma.UserRoleOrderByWithRelationInput | Prisma.UserRoleOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for UserRoles. + */ + cursor?: Prisma.UserRoleWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` UserRoles from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` UserRoles. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of UserRoles. + */ + distinct?: Prisma.UserRoleScalarFieldEnum | Prisma.UserRoleScalarFieldEnum[] +} + +/** + * UserRole findFirstOrThrow + */ +export type UserRoleFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null + /** + * Filter, which UserRole to fetch. + */ + where?: Prisma.UserRoleWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of UserRoles to fetch. + */ + orderBy?: Prisma.UserRoleOrderByWithRelationInput | Prisma.UserRoleOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for UserRoles. + */ + cursor?: Prisma.UserRoleWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` UserRoles from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` UserRoles. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of UserRoles. + */ + distinct?: Prisma.UserRoleScalarFieldEnum | Prisma.UserRoleScalarFieldEnum[] +} + +/** + * UserRole findMany + */ +export type UserRoleFindManyArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null + /** + * Filter, which UserRoles to fetch. + */ + where?: Prisma.UserRoleWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of UserRoles to fetch. + */ + orderBy?: Prisma.UserRoleOrderByWithRelationInput | Prisma.UserRoleOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing UserRoles. + */ + cursor?: Prisma.UserRoleWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` UserRoles from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` UserRoles. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of UserRoles. + */ + distinct?: Prisma.UserRoleScalarFieldEnum | Prisma.UserRoleScalarFieldEnum[] +} + +/** + * UserRole create + */ +export type UserRoleCreateArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null + /** + * The data needed to create a UserRole. + */ + data: Prisma.XOR +} + +/** + * UserRole createMany + */ +export type UserRoleCreateManyArgs = { + /** + * The data used to create many UserRoles. + */ + data: Prisma.UserRoleCreateManyInput | Prisma.UserRoleCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * UserRole createManyAndReturn + */ +export type UserRoleCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelectCreateManyAndReturn | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * The data used to create many UserRoles. + */ + data: Prisma.UserRoleCreateManyInput | Prisma.UserRoleCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleIncludeCreateManyAndReturn | null +} + +/** + * UserRole update + */ +export type UserRoleUpdateArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null + /** + * The data needed to update a UserRole. + */ + data: Prisma.XOR + /** + * Choose, which UserRole to update. + */ + where: Prisma.UserRoleWhereUniqueInput +} + +/** + * UserRole updateMany + */ +export type UserRoleUpdateManyArgs = { + /** + * The data used to update UserRoles. + */ + data: Prisma.XOR + /** + * Filter which UserRoles to update + */ + where?: Prisma.UserRoleWhereInput + /** + * Limit how many UserRoles to update. + */ + limit?: number +} + +/** + * UserRole updateManyAndReturn + */ +export type UserRoleUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * The data used to update UserRoles. + */ + data: Prisma.XOR + /** + * Filter which UserRoles to update + */ + where?: Prisma.UserRoleWhereInput + /** + * Limit how many UserRoles to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleIncludeUpdateManyAndReturn | null +} + +/** + * UserRole upsert + */ +export type UserRoleUpsertArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null + /** + * The filter to search for the UserRole to update in case it exists. + */ + where: Prisma.UserRoleWhereUniqueInput + /** + * In case the UserRole found by the `where` argument doesn't exist, create a new UserRole with this data. + */ + create: Prisma.XOR + /** + * In case the UserRole was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * UserRole delete + */ +export type UserRoleDeleteArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null + /** + * Filter which UserRole to delete. + */ + where: Prisma.UserRoleWhereUniqueInput +} + +/** + * UserRole deleteMany + */ +export type UserRoleDeleteManyArgs = { + /** + * Filter which UserRoles to delete + */ + where?: Prisma.UserRoleWhereInput + /** + * Limit how many UserRoles to delete. + */ + limit?: number +} + +/** + * UserRole without action + */ +export type UserRoleDefaultArgs = { + /** + * Select specific fields to fetch from the UserRole + */ + select?: Prisma.UserRoleSelect | null + /** + * Omit specific fields from the UserRole + */ + omit?: Prisma.UserRoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserRoleInclude | null +} diff --git a/apps/api/src/health.controller.spec.ts b/apps/api/src/health.controller.spec.ts new file mode 100644 index 00000000..8ff54033 --- /dev/null +++ b/apps/api/src/health.controller.spec.ts @@ -0,0 +1,19 @@ +import { Test } from "@nestjs/testing"; +import { describe, expect, it } from "vitest"; +import { AppModule } from "./app.module.js"; +import { HealthController } from "./health.controller.js"; + +describe("HealthController", () => { + it("is wired by AppModule and returns the API health payload", async () => { + const moduleRef = await Test.createTestingModule({ + imports: [AppModule] + }).compile(); + + const controller = moduleRef.get(HealthController); + + expect(controller.check()).toEqual({ + service: "@huijing/api", + status: "ok" + }); + }); +}); diff --git a/apps/api/src/health.controller.ts b/apps/api/src/health.controller.ts new file mode 100644 index 00000000..2bd88d28 --- /dev/null +++ b/apps/api/src/health.controller.ts @@ -0,0 +1,17 @@ +import { Controller, Get } from "@nestjs/common"; + +export interface HealthResponse { + readonly service: "@huijing/api"; + readonly status: "ok"; +} + +@Controller("health") +export class HealthController { + @Get() + check(): HealthResponse { + return { + service: "@huijing/api", + status: "ok" + }; + } +} diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts new file mode 100644 index 00000000..8128ebec --- /dev/null +++ b/apps/api/src/main.ts @@ -0,0 +1,17 @@ +import "reflect-metadata"; +import { NestFactory } from "@nestjs/core"; +import { resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { AppModule } from "./app.module.js"; + +export async function bootstrap(port = 3001): Promise { + const app = await NestFactory.create(AppModule); + await app.listen(port); +} + +const currentModulePath = fileURLToPath(import.meta.url); +const executedModulePath = process.argv[1] ? resolve(process.argv[1]) : undefined; + +if (executedModulePath === currentModulePath) { + void bootstrap(); +} diff --git a/apps/api/src/modules/assets/assets.api.spec.ts b/apps/api/src/modules/assets/assets.api.spec.ts new file mode 100644 index 00000000..7b3f5657 --- /dev/null +++ b/apps/api/src/modules/assets/assets.api.spec.ts @@ -0,0 +1,247 @@ +import { type INestApplication } from "@nestjs/common"; +import { Test } from "@nestjs/testing"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { mkdtemp, rm } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { AppModule } from "../../app.module.js"; +import { PrismaClient } from "../../generated/prisma/client.js"; +import { StorageBoundaryError } from "../storage/index.js"; +import { S1_STORAGE_ADAPTER, type StorageObjectPlanner } from "./index.js"; + +const databaseUrl = process.env.DATABASE_URL ?? "postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public"; +const adapter = new PrismaPg({ connectionString: databaseUrl }); +const prisma = new PrismaClient({ adapter }); +const runId = `task8-assets-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; + +type TestApp = { + readonly app: INestApplication; + readonly baseUrl: string; +}; + +async function createTestApp(storageRoot: string, storagePlanner?: StorageObjectPlanner): Promise { + process.env.S1_STORAGE_ROOT = storageRoot; + const builder = Test.createTestingModule({ + imports: [AppModule] + }); + if (storagePlanner) builder.overrideProvider(S1_STORAGE_ADAPTER).useValue(storagePlanner); + const moduleRef = await builder.compile(); + const app = moduleRef.createNestApplication(); + await app.init(); + const server = await app.listen(0); + const address = server.address(); + if (address === null || typeof address === "string") throw new Error("Nest test server did not expose a TCP port"); + return { app, baseUrl: `http://127.0.0.1:${address.port}` }; +} + +async function requestJson(testApp: TestApp, requestPath: string, init: RequestInit = {}) { + const response = await fetch(`${testApp.baseUrl}${requestPath}`, { + ...init, + headers: { + "content-type": "application/json", + ...init.headers + } + }); + const body = (await response.json().catch(() => null)) as unknown; + return { response, body }; +} + +async function login(testApp: TestApp, email: string): Promise { + const response = await requestJson(testApp, "/auth/login", { + method: "POST", + body: JSON.stringify({ email }) + }); + expect(response.response.status).toBe(201); + return (response.body as { token: string }).token; +} + +async function seedDb(): Promise<{ readonly ownedProjectId: string; readonly foreignProjectId: string }> { + await prisma.user.upsert({ + where: { id: "seed-creator" }, + update: {}, + create: { id: "seed-creator", email: "creator@example.test", displayName: "Seed Creator" } + }); + await prisma.user.upsert({ + where: { id: "seed-creator-other" }, + update: {}, + create: { id: "seed-creator-other", email: "creator-other@example.test", displayName: "Seed Other Creator" } + }); + const ownedProjectId = `${runId}-owned-project`; + const foreignProjectId = `${runId}-foreign-project`; + await prisma.gameProject.create({ + data: { id: ownedProjectId, ownerId: "seed-creator", slug: `${runId}-owned`, title: "owned" } + }); + await prisma.gameProject.create({ + data: { id: foreignProjectId, ownerId: "seed-creator-other", slug: `${runId}-foreign`, title: "foreign" } + }); + return { ownedProjectId, foreignProjectId }; +} + +async function cleanup(): Promise { + await prisma.gameProject.deleteMany({ where: { id: { startsWith: runId } } }); +} + +describe("Asset HTTP APIs", () => { + let testApp: TestApp | undefined; + let storageRoot: string | undefined; + let previousStorageRoot: string | undefined; + + beforeEach(async () => { + await cleanup(); + previousStorageRoot = process.env.S1_STORAGE_ROOT; + storageRoot = await mkdtemp(path.join(os.tmpdir(), "huijing-task8-assets-")); + testApp = await createTestApp(storageRoot); + }); + + afterEach(async () => { + await testApp?.app.close(); + testApp = undefined; + await cleanup(); + if (storageRoot) await rm(storageRoot, { recursive: true, force: true }); + storageRoot = undefined; + if (previousStorageRoot === undefined) { + delete process.env.S1_STORAGE_ROOT; + } else { + process.env.S1_STORAGE_ROOT = previousStorageRoot; + } + previousStorageRoot = undefined; + }); + + it("POST /assets/presign returns a local mock upload target for the owning creator and writes audit", async () => { + const { ownedProjectId } = await seedDb(); + const token = await login(testApp!, "creator@example.test"); + + const presign = await requestJson(testApp!, "/assets/presign", { + method: "POST", + headers: { authorization: `Bearer ${token}` }, + body: JSON.stringify({ + projectId: ownedProjectId, + kind: "cover", + objectName: "cover.png", + mimeType: "image/png", + byteSize: 128, + sha256: "a".repeat(64) + }) + }); + + expect(presign.response.status).toBe(201); + expect(presign.body).toMatchObject({ + projectId: ownedProjectId, + storageKey: `owners/seed-creator/projects/${ownedProjectId}/cover.png`, + uploadUrl: `local://s1-storage/owners/seed-creator/projects/${ownedProjectId}/cover.png`, + method: "PUT" + }); + await expect(prisma.auditLog.findFirst({ where: { targetId: ownedProjectId, action: "asset.presign.created" } })).resolves.toMatchObject({ + actorId: "seed-creator", + targetType: "GameProject" + }); + }); + + it("POST /assets/presign rejects foreign project access before any audit mutation", async () => { + const { foreignProjectId } = await seedDb(); + const token = await login(testApp!, "creator@example.test"); + + const denied = await requestJson(testApp!, "/assets/presign", { + method: "POST", + headers: { authorization: `Bearer ${token}` }, + body: JSON.stringify({ + projectId: foreignProjectId, + kind: "cover", + objectName: "cover.png", + mimeType: "image/png", + byteSize: 128, + sha256: "a".repeat(64) + }) + }); + + expect(denied.response.status).toBe(403); + expect(denied.body).toEqual({ + code: "FORBIDDEN", + message: expect.any(String), + requestId: null, + details: expect.anything() + }); + await expect(prisma.auditLog.count({ where: { targetId: foreignProjectId } })).resolves.toBe(0); + }); + + it("POST /assets/presign delegates key construction to the storage boundary planner", async () => { + const { ownedProjectId } = await seedDb(); + const plannedInputs: unknown[] = []; + await testApp?.app.close(); + testApp = await createTestApp(storageRoot!, { + planObject(input) { + plannedInputs.push(input); + return { + storageKey: "owners/from-storage-boundary/projects/fake/planned.png", + byteSize: input.byteSize, + sha256: input.expectedSha256.toLowerCase(), + mimeType: input.mimeType + }; + } + }); + const token = await login(testApp!, "creator@example.test"); + + const presign = await requestJson(testApp!, "/assets/presign", { + method: "POST", + headers: { authorization: `Bearer ${token}` }, + body: JSON.stringify({ + projectId: ownedProjectId, + kind: "cover", + objectName: "api-layer-must-not-parse%2Fthis.png", + mimeType: "image/png", + byteSize: 128, + sha256: "b".repeat(64) + }) + }); + + expect(presign.response.status).toBe(201); + expect(presign.body).toMatchObject({ + storageKey: "owners/from-storage-boundary/projects/fake/planned.png", + uploadUrl: "local://s1-storage/owners/from-storage-boundary/projects/fake/planned.png" + }); + expect(plannedInputs).toEqual([ + expect.objectContaining({ + ownerId: "seed-creator", + projectId: ownedProjectId, + objectName: "api-layer-must-not-parse%2Fthis.png" + }) + ]); + }); + + it("POST /assets/presign maps storage boundary errors to structured API errors without audit mutation", async () => { + const { ownedProjectId } = await seedDb(); + await testApp?.app.close(); + testApp = await createTestApp(storageRoot!, { + planObject() { + throw new StorageBoundaryError("MIME_NOT_ALLOWED"); + } + }); + const token = await login(testApp!, "creator@example.test"); + const beforeAuditCount = await prisma.auditLog.count({ where: { targetId: ownedProjectId, action: "asset.presign.created" } }); + + const denied = await requestJson(testApp!, "/assets/presign", { + method: "POST", + headers: { authorization: `Bearer ${token}` }, + body: JSON.stringify({ + projectId: ownedProjectId, + kind: "cover", + objectName: "cover.png", + mimeType: "image/png", + byteSize: 128, + sha256: "c".repeat(64) + }) + }); + + expect(denied.response.status).toBe(400); + expect(denied.body).toEqual({ + code: "MIME_NOT_ALLOWED", + message: expect.any(String), + requestId: null, + details: expect.anything() + }); + await expect(prisma.auditLog.count({ where: { targetId: ownedProjectId, action: "asset.presign.created" } })).resolves.toBe( + beforeAuditCount + ); + }); +}); diff --git a/apps/api/src/modules/assets/index.ts b/apps/api/src/modules/assets/index.ts new file mode 100644 index 00000000..8d0cc4eb --- /dev/null +++ b/apps/api/src/modules/assets/index.ts @@ -0,0 +1,167 @@ +import { + BadRequestException, + Body, + Controller, + ForbiddenException, + Inject, + Injectable, + Module, + NotFoundException, + Post, + Req, + UseGuards +} from "@nestjs/common"; +import { randomUUID } from "node:crypto"; +import { AuthGuard, AuthModule, type AuthActor } from "../auth/index.js"; +import { AuditService } from "../audit/index.js"; +import { creatorOwnsResource } from "../rbac/index.js"; +import { apiError, S1ApiRuntimeModule, S1PrismaClient } from "../projects/api-runtime.js"; +import { LocalStorageAdapter, StorageBoundaryError, type PlanObjectInput, type PlanObjectResult } from "../storage/index.js"; + +type RequestWithActor = { + readonly actor: AuthActor; +}; + +type PresignBody = { + readonly projectId?: unknown; + readonly kind?: unknown; + readonly objectName?: unknown; + readonly mimeType?: unknown; + readonly byteSize?: unknown; + readonly sha256?: unknown; +}; + +type LocalUploadTarget = { + readonly projectId: string; + readonly kind: string; + readonly storageKey: string; + readonly uploadUrl: string; + readonly method: "PUT"; + readonly headers: { + readonly "content-type": string; + readonly "x-sha256": string; + }; + readonly maxBytes: number; +}; + +export interface StorageObjectPlanner { + planObject(input: PlanObjectInput): PlanObjectResult; +} + +export const S1_STORAGE_ADAPTER = Symbol("S1_STORAGE_ADAPTER"); + +const maxUploadBytes = 10 * 1024 * 1024; +const allowedMimeTypes = ["image/png", "image/jpeg", "image/webp", "text/plain", "application/json"] as const; + +function requireNonEmptyString(value: unknown, field: string): string { + if (typeof value !== "string" || value.trim() === "") { + throw new BadRequestException(apiError("INVALID_REQUEST", `${field} must be a non-empty string`, { field })); + } + return value.trim(); +} + +function requireInteger(value: unknown, field: string): number { + if (typeof value !== "number" || !Number.isInteger(value)) { + throw new BadRequestException(apiError("INVALID_REQUEST", `${field} must be an integer`, { field })); + } + return value; +} + +@Injectable() +export class AssetsApiService { + constructor( + private readonly db: S1PrismaClient, + @Inject(S1_STORAGE_ADAPTER) private readonly storage: StorageObjectPlanner + ) {} + + async presign(actor: AuthActor, body: PresignBody): Promise { + const projectId = requireNonEmptyString(body.projectId, "projectId"); + const kind = requireNonEmptyString(body.kind, "kind"); + const objectName = requireNonEmptyString(body.objectName, "objectName"); + const mimeType = requireNonEmptyString(body.mimeType, "mimeType"); + const byteSize = requireInteger(body.byteSize, "byteSize"); + const sha256 = requireNonEmptyString(body.sha256, "sha256"); + + const project = await this.db.gameProject.findUnique({ where: { id: projectId } }); + if (!project) throw new NotFoundException(apiError("NOT_FOUND", "Project not found", { projectId })); + if (!creatorOwnsResource(actor, project)) { + // 外部项目在任何 presign/audit 写入前拒绝,避免为越权尝试产生可误用的 upload target。 + throw new ForbiddenException(apiError("FORBIDDEN", "Actor cannot presign assets for this project", { projectId })); + } + + let planned: PlanObjectResult; + try { + planned = this.storage.planObject({ + ownerId: actor.id, + projectId, + objectName, + mimeType, + byteSize, + expectedSha256: sha256 + }); + } catch (error) { + if (error instanceof StorageBoundaryError) { + throw new BadRequestException(apiError(error.code, error.message, { storageBoundary: true })); + } + throw error; + } + + await new AuditService({ db: this.db }).append({ + id: randomUUID(), + actorId: actor.id, + action: "asset.presign.created", + targetType: "GameProject", + targetId: projectId, + eventJson: { + kind, + storageKey: planned.storageKey, + mimeType: planned.mimeType, + byteSize: planned.byteSize, + sha256: planned.sha256 + } + }); + + return { + projectId, + kind, + storageKey: planned.storageKey, + uploadUrl: `local://s1-storage/${planned.storageKey}`, + method: "PUT", + headers: { + "content-type": planned.mimeType, + "x-sha256": planned.sha256 + }, + maxBytes: maxUploadBytes + }; + } +} + +@Controller() +@UseGuards(AuthGuard) +export class AssetsController { + constructor(private readonly service: AssetsApiService) {} + + @Post("assets/presign") + presign(@Req() request: RequestWithActor, @Body() body: PresignBody): Promise { + return this.service.presign(request.actor, body); + } +} + +@Module({ + imports: [S1ApiRuntimeModule, AuthModule], + controllers: [AssetsController], + providers: [ + AssetsApiService, + { + provide: S1_STORAGE_ADAPTER, + useFactory: () => + new LocalStorageAdapter({ + root: process.env.S1_STORAGE_ROOT ?? ".s1-storage", + allowedMimeTypes, + maxBytes: maxUploadBytes + }) + } + ], + exports: [S1_STORAGE_ADAPTER] +}) +export class AssetsModule {} diff --git a/apps/api/src/modules/audit/audit.api.spec.ts b/apps/api/src/modules/audit/audit.api.spec.ts new file mode 100644 index 00000000..b2145a8a --- /dev/null +++ b/apps/api/src/modules/audit/audit.api.spec.ts @@ -0,0 +1,134 @@ +import { type INestApplication } from "@nestjs/common"; +import { Test } from "@nestjs/testing"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { AppModule } from "../../app.module.js"; +import { PrismaClient } from "../../generated/prisma/client.js"; + +const databaseUrl = process.env.DATABASE_URL ?? "postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public"; +const adapter = new PrismaPg({ connectionString: databaseUrl }); +const prisma = new PrismaClient({ adapter }); +const runId = `task8-audit-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; + +type TestApp = { + readonly app: INestApplication; + readonly baseUrl: string; +}; + +async function createTestApp(): Promise { + const moduleRef = await Test.createTestingModule({ + imports: [AppModule] + }).compile(); + const app = moduleRef.createNestApplication(); + await app.init(); + const server = await app.listen(0); + const address = server.address(); + if (address === null || typeof address === "string") throw new Error("Nest test server did not expose a TCP port"); + return { app, baseUrl: `http://127.0.0.1:${address.port}` }; +} + +async function requestJson(testApp: TestApp, requestPath: string, init: RequestInit = {}) { + const response = await fetch(`${testApp.baseUrl}${requestPath}`, { + ...init, + headers: { + "content-type": "application/json", + ...init.headers + } + }); + const body = (await response.json().catch(() => null)) as unknown; + return { response, body }; +} + +async function login(testApp: TestApp, email: string): Promise { + const response = await requestJson(testApp, "/auth/login", { + method: "POST", + body: JSON.stringify({ email }) + }); + expect(response.response.status).toBe(201); + return (response.body as { token: string }).token; +} + +async function ensureSeedUsers(): Promise { + await prisma.user.upsert({ + where: { id: "seed-creator" }, + update: {}, + create: { id: "seed-creator", email: "creator@example.test", displayName: "Seed Creator" } + }); + await prisma.user.upsert({ + where: { id: "seed-operator" }, + update: {}, + create: { id: "seed-operator", email: "operator@example.test", displayName: "Seed Operator" } + }); + await prisma.user.upsert({ + where: { id: "seed-admin" }, + update: {}, + create: { id: "seed-admin", email: "admin@example.test", displayName: "Seed Admin" } + }); +} + +async function cleanup(): Promise { + await prisma.gameProject.deleteMany({ where: { id: { startsWith: runId } } }); +} + +describe("Audit HTTP APIs", () => { + let testApp: TestApp | undefined; + + beforeEach(async () => { + await cleanup(); + await ensureSeedUsers(); + testApp = await createTestApp(); + }); + + afterEach(async () => { + await testApp?.app.close(); + testApp = undefined; + await cleanup(); + }); + + it("GET /audit-logs requires operator/admin and returns S1 foundation audit facts", async () => { + await prisma.auditLog.create({ + data: { + id: `${runId}-audit`, + actorId: "seed-creator", + action: "project.created", + targetType: "GameProject", + targetId: `${runId}-project`, + eventJson: { source: "task8-test" } + } + }); + const creatorToken = await login(testApp!, "creator@example.test"); + const operatorToken = await login(testApp!, "operator@example.test"); + const adminToken = await login(testApp!, "admin@example.test"); + + const denied = await requestJson(testApp!, "/audit-logs", { + headers: { authorization: `Bearer ${creatorToken}` } + }); + expect(denied.response.status).toBe(403); + expect(denied.body).toEqual({ + code: "FORBIDDEN", + message: expect.any(String), + requestId: null, + details: expect.anything() + }); + + const operatorRead = await requestJson(testApp!, "/audit-logs", { + headers: { authorization: `Bearer ${operatorToken}` } + }); + expect(operatorRead.response.status).toBe(200); + expect(operatorRead.body).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: `${runId}-audit`, action: "project.created", targetType: "GameProject" }) + ]) + ); + + const adminRead = await requestJson(testApp!, "/audit-logs", { + headers: { authorization: `Bearer ${adminToken}` } + }); + expect(adminRead.response.status).toBe(200); + expect(adminRead.body).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: `${runId}-audit`, action: "project.created", targetId: `${runId}-project` }) + ]) + ); + }); +}); diff --git a/apps/api/src/modules/audit/audit.spec.ts b/apps/api/src/modules/audit/audit.spec.ts new file mode 100644 index 00000000..47c4ec5c --- /dev/null +++ b/apps/api/src/modules/audit/audit.spec.ts @@ -0,0 +1,189 @@ +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { PrismaClient } from "../../generated/prisma/client.js"; +import { + AuditMutationRejectedError, + AuditService, + findAuditBoundaryViolations, + scanAuditBoundary +} from "./index.js"; +import { afterAll, describe, expect, it } from "vitest"; + +const databaseUrl = process.env.DATABASE_URL ?? "postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public"; +const adapter = new PrismaPg({ connectionString: databaseUrl }); +const prisma = new PrismaClient({ adapter }); +const runId = `task7-audit-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; +const rollbackToken = Symbol("audit rollback"); +let savepointSequence = 0; + +type DbClient = Prisma.TransactionClient; + +async function withRollback(callback: (tx: DbClient) => Promise): Promise { + try { + await prisma.$transaction(async (tx) => { + await callback(tx); + throw rollbackToken; + }); + } catch (error) { + if (error !== rollbackToken) throw error; + } +} + +async function expectPrismaRejectedInSavepoint( + db: DbClient, + action: () => Promise, + pattern: RegExp +): Promise { + const savepointName = `task7_audit_sp_${++savepointSequence}`; + await db.$executeRawUnsafe(`SAVEPOINT ${savepointName}`); + + let caught: unknown; + try { + await action(); + } catch (error) { + caught = error; + } + + await db.$executeRawUnsafe(`ROLLBACK TO SAVEPOINT ${savepointName}`); + await db.$executeRawUnsafe(`RELEASE SAVEPOINT ${savepointName}`); + + if (caught === undefined) throw new Error(`Expected Prisma action to reject with ${pattern}`); + expect(() => { + throw caught; + }).toThrow(pattern); +} + +async function seedActor(db: DbClient, suffix: string) { + return db.user.create({ + data: { + id: `${runId}-${suffix}-actor`, + email: `${runId}-${suffix}@example.test`, + displayName: `${suffix} actor` + } + }); +} + +describe("AuditService", () => { + afterAll(async () => { + await prisma.$disconnect(); + }); + + it("appends audit entries and exposes no update/delete path", async () => { + await withRollback(async (tx) => { + const actor = await seedActor(tx, "append"); + const service = new AuditService({ db: tx }); + + const audit = await service.append({ + id: `${runId}-append-audit`, + actorId: actor.id, + action: "job.cancel.blocked", + targetType: "Job", + targetId: `${runId}-job`, + eventJson: { reasonCode: "NOT_QUEUED" } + }); + + expect(audit.action).toBe("job.cancel.blocked"); + expect("update" in service).toBe(false); + expect("delete" in service).toBe(false); + await expect(service.rejectMutation("update")).rejects.toMatchObject({ + code: "AUDIT_APPEND_ONLY" + }); + await expect(service.rejectMutation("delete")).rejects.toMatchObject({ + code: "AUDIT_APPEND_ONLY" + }); + }); + }); + + it("DB trigger rejects direct Prisma auditLog.update/delete", async () => { + await withRollback(async (tx) => { + const actor = await seedActor(tx, "trigger"); + const service = new AuditService({ db: tx }); + const audit = await service.append({ + id: `${runId}-trigger-audit`, + actorId: actor.id, + action: "audit.trigger", + targetType: "AuditLog", + targetId: "self", + eventJson: {} + }); + + await expectPrismaRejectedInSavepoint( + tx, + () => tx.auditLog.update({ where: { id: audit.id }, data: { action: "changed" } }), + /AuditLog is append-only/ + ); + await expectPrismaRejectedInSavepoint(tx, () => tx.auditLog.delete({ where: { id: audit.id } }), /AuditLog is append-only/); + }); + }); + + it("static scan fails if auditLog.update/delete appears in S1 application code", async () => { + expect( + findAuditBoundaryViolations([ + { + path: "apps/api/src/modules/projects/project.service.ts", + content: "await db.auditLog.update({ where: { id }, data: {} });" + }, + { + path: "apps/api/src/modules/audit/index.ts", + content: "await db.auditLog.create({ data });" + }, + { + path: "apps/api/src/modules/audit/bad.ts", + content: "await db.auditLog.update({ where: { id }, data: {} });" + } + ]) + ).toEqual([ + { path: "apps/api/src/modules/projects/project.service.ts", reason: "AUDIT_UPDATE_DELETE_FORBIDDEN" }, + { path: "apps/api/src/modules/audit/bad.ts", reason: "AUDIT_UPDATE_DELETE_FORBIDDEN" } + ]); + + const tempRoot = await mkdtemp(path.join(os.tmpdir(), "huijing-audit-scan-")); + await writeFile( + path.join(tempRoot, "bad.ts"), + "async function bad(db) { await db.auditLog.delete({ where: { id: 'x' } }); }", + "utf8" + ); + await expect(scanAuditBoundary(tempRoot)).resolves.toEqual([ + { path: "bad.ts", reason: "AUDIT_UPDATE_DELETE_FORBIDDEN" } + ]); + await rm(tempRoot, { recursive: true, force: true }); + + await expect(scanAuditBoundary(process.cwd())).resolves.toEqual([]); + }); + + it("high-risk blocked actions can write audit facts without mutating target state", async () => { + const actor = await prisma.$transaction((tx) => seedActor(tx, "blocked")); + await expect( + prisma.$transaction(async (tx) => { + const service = new AuditService({ db: prisma }); + await service.append({ + id: `${runId}-blocked-audit`, + actorId: actor.id, + action: "asset.upload.blocked", + targetType: "Asset", + targetId: `${runId}-asset`, + eventJson: { reasonCode: "MIME_NOT_ALLOWED" } + }); + await tx.asset.create({ + data: { + id: `${runId}-asset`, + projectId: "missing-project", + kind: "image", + storageKey: "bad", + mimeType: "application/x-msdownload", + byteSize: 1, + sha256: "0".repeat(64) + } + }); + }) + ).rejects.toThrow(); + + await expect(prisma.auditLog.findUnique({ where: { id: `${runId}-blocked-audit` } })).resolves.toMatchObject({ + action: "asset.upload.blocked", + targetId: `${runId}-asset` + }); + await expect(prisma.asset.findUnique({ where: { id: `${runId}-asset` } })).resolves.toBeNull(); + }); +}); diff --git a/apps/api/src/modules/audit/index.ts b/apps/api/src/modules/audit/index.ts new file mode 100644 index 00000000..38bbc3f0 --- /dev/null +++ b/apps/api/src/modules/audit/index.ts @@ -0,0 +1,271 @@ +import { readdir, readFile } from "node:fs/promises"; +import path from "node:path"; +import { Controller, ForbiddenException, Get, Injectable, Module, Req, UseGuards } from "@nestjs/common"; +import { Prisma, type AuditLog } from "../../generated/prisma/client.js"; +import { AuthGuard, AuthModule, type AuthActor } from "../auth/index.js"; +import { canReadReviewFoundationData } from "../rbac/index.js"; +import { apiError, S1ApiRuntimeModule, S1PrismaClient } from "../projects/api-runtime.js"; + +export type AppendAuditInput = { + readonly id: string; + readonly actorId: string; + readonly action: string; + readonly targetType: string; + readonly targetId: string; + readonly eventJson: Prisma.InputJsonValue; +}; + +export type AuditServiceOptions = { + readonly db: Pick; +}; + +export type AuditBoundaryViolation = { + readonly path: string; + readonly reason: "AUDIT_UPDATE_DELETE_FORBIDDEN"; +}; + +type RequestWithActor = { + readonly actor: AuthActor; +}; + +export type AuditLogDto = { + readonly id: string; + readonly actorId: string; + readonly action: string; + readonly targetType: string; + readonly targetId: string; + readonly eventJson: unknown; + readonly createdAt: string; +}; + +type ScanFile = { + readonly path: string; + readonly content: string; +}; + +const generatedPrismaPrefix = "apps/api/src/generated/prisma/"; +const historicalAuditTriggerTest = "apps/api/src/prisma.schema.spec.ts"; +const ignoredScanSegments = new Set(["node_modules", "dist", ".vite", "coverage", ".next"]); + +export class AuditMutationRejectedError extends Error { + readonly code = "AUDIT_APPEND_ONLY"; + + constructor(action: "update" | "delete") { + super(`AuditLog is append-only; ${action} is not allowed`); + this.name = "AuditMutationRejectedError"; + } +} + +export class AuditService { + private readonly db: Pick; + + constructor(options: AuditServiceOptions) { + this.db = options.db; + } + + async append(input: AppendAuditInput): Promise { + return this.db.auditLog.create({ + data: { + id: input.id, + actorId: input.actorId, + action: input.action, + targetType: input.targetType, + targetId: input.targetId, + eventJson: input.eventJson + } + }); + } + + async rejectMutation(action: "update" | "delete"): Promise { + // S1 service 层只暴露 append;测试用这个显式拒绝入口证明没有静默 update/delete 路径。 + throw new AuditMutationRejectedError(action); + } +} + +function auditLogDto(auditLog: AuditLog): AuditLogDto { + return { + id: auditLog.id, + actorId: auditLog.actorId, + action: auditLog.action, + targetType: auditLog.targetType, + targetId: auditLog.targetId, + eventJson: auditLog.eventJson, + createdAt: auditLog.createdAt.toISOString() + }; +} + +@Injectable() +export class AuditApiService { + constructor(private readonly db: S1PrismaClient) {} + + async listAuditLogs(actor: AuthActor): Promise { + if (!canReadReviewFoundationData(actor, "audit-log")) { + // S1 audit endpoint 是审核基础数据读面,不是 creator 自助查询或管理 CRUD。 + throw new ForbiddenException(apiError("FORBIDDEN", "Operator or admin role is required for audit logs")); + } + + const auditLogs = await this.db.auditLog.findMany({ + orderBy: [{ createdAt: "desc" }, { id: "desc" }], + take: 200 + }); + return auditLogs.map(auditLogDto); + } +} + +@Controller() +@UseGuards(AuthGuard) +export class AuditController { + constructor(private readonly service: AuditApiService) {} + + @Get("audit-logs") + listAuditLogs(@Req() request: RequestWithActor): Promise { + return this.service.listAuditLogs(request.actor); + } +} + +@Module({ + imports: [S1ApiRuntimeModule, AuthModule], + controllers: [AuditController], + providers: [AuditApiService], + exports: [AuditApiService] +}) +export class AuditModule {} + +function isIgnoredScanPath(filePath: string): boolean { + return ( + filePath.split("/").some((segment) => ignoredScanSegments.has(segment)) || + filePath.includes("/generated/prisma/") || + filePath.endsWith(".spec.ts") + ); +} + +function findMatchingParen(content: string, openParenIndex: number): number { + let depth = 0; + for (let index = openParenIndex; index < content.length; index += 1) { + const char = content[index]; + if (char === "(") depth += 1; + if (char === ")") { + depth -= 1; + if (depth === 0) return index; + } + } + return -1; +} + +function maskStringLiterals(content: string): string { + let output = ""; + let index = 0; + + while (index < content.length) { + const quote = content[index]; + if (quote !== '"' && quote !== "'" && quote !== "`") { + output += quote; + index += 1; + continue; + } + + output += quote; + index += 1; + while (index < content.length) { + const char = content[index]; + if (char === "\\") { + output += " "; + index += 1; + if (index < content.length) { + output += " "; + index += 1; + } + continue; + } + if (char === quote) { + output += quote; + index += 1; + break; + } + output += " "; + index += 1; + } + } + + return output; +} + +function isAuditTriggerAssertion(filePath: string, content: string, structure: string, mutationIndex: number): boolean { + if (filePath !== historicalAuditTriggerTest && filePath !== "apps/api/src/modules/audit/audit.spec.ts") return false; + + let searchCursor = mutationIndex; + while (searchCursor >= 0) { + const assertionIndex = structure.lastIndexOf("expectPrismaRejectedInSavepoint", searchCursor); + if (assertionIndex === -1) return false; + + const openParenIndex = structure.indexOf("(", assertionIndex); + if (openParenIndex === -1 || openParenIndex > mutationIndex) { + searchCursor = assertionIndex - 1; + continue; + } + + const closeParenIndex = findMatchingParen(structure, openParenIndex); + if (closeParenIndex === -1 || closeParenIndex < mutationIndex) { + searchCursor = assertionIndex - 1; + continue; + } + + const assertionSource = content.slice(openParenIndex, closeParenIndex + 1); + return /AuditLog is append-only/.test(assertionSource); + } + + return false; +} + +function hasAuditMutation(filePath: string, content: string): boolean { + const structure = maskStringLiterals(content); + const mutationPattern = /\.auditLog\.(?:update|updateMany|updateManyAndReturn|upsert|delete|deleteMany)\s*\(/g; + + for (const match of structure.matchAll(mutationPattern)) { + if (typeof match.index === "number" && isAuditTriggerAssertion(filePath, content, structure, match.index)) continue; + return true; + } + + return false; +} + +export function findAuditBoundaryViolations(files: readonly ScanFile[]): AuditBoundaryViolation[] { + const violations: AuditBoundaryViolation[] = []; + for (const file of files) { + const normalizedPath = file.path.split(path.sep).join("/"); + if (isIgnoredScanPath(normalizedPath)) continue; + if (normalizedPath.startsWith(generatedPrismaPrefix) || normalizedPath.startsWith("src/generated/prisma/")) continue; + if (hasAuditMutation(normalizedPath, file.content)) { + violations.push({ path: normalizedPath, reason: "AUDIT_UPDATE_DELETE_FORBIDDEN" }); + } + } + return violations; +} + +async function collectFiles(root: string, relativeDir = ""): Promise { + const absoluteDir = path.join(root, relativeDir); + const entries = await readdir(absoluteDir, { withFileTypes: true }).catch(() => []); + const files: ScanFile[] = []; + + for (const entry of entries) { + if (entry.isDirectory() && ignoredScanSegments.has(entry.name)) continue; + const relativePath = path.join(relativeDir, entry.name); + const absolutePath = path.join(root, relativePath); + if (entry.isDirectory()) files.push(...(await collectFiles(root, relativePath))); + if (entry.isFile() && /\.(?:ts|tsx|js|mjs|cjs)$/.test(entry.name)) { + files.push({ path: relativePath, content: await readFile(absolutePath, "utf8") }); + } + } + + return files; +} + +export async function scanAuditBoundary(root: string): Promise { + const files = root.endsWith("games-development-ai") + ? [ + ...(await collectFiles(root, "apps/api/src/modules")), + ...(await collectFiles(root, "apps/worker/src")) + ] + : await collectFiles(root); + return findAuditBoundaryViolations(files); +} diff --git a/apps/api/src/modules/auth/auth.spec.ts b/apps/api/src/modules/auth/auth.spec.ts new file mode 100644 index 00000000..669ab0dc --- /dev/null +++ b/apps/api/src/modules/auth/auth.spec.ts @@ -0,0 +1,118 @@ +import { type INestApplication, Controller, Get, UseGuards } from "@nestjs/common"; +import { Test } from "@nestjs/testing"; +import { afterEach, describe, expect, it } from "vitest"; +import { AppModule } from "../../app.module.js"; +import { AuthGuard, AuthModule } from "./index.js"; + +@Controller("task6-protected") +class Task6ProtectedController { + @Get() + @UseGuards(AuthGuard) + check() { + return { ok: true }; + } +} + +type Task6TestApp = { + readonly app: INestApplication; + readonly baseUrl: string; +}; + +async function createTestApp(): Promise { + const moduleRef = await Test.createTestingModule({ + imports: [AppModule, AuthModule], + controllers: [Task6ProtectedController] + }).compile(); + const app = moduleRef.createNestApplication(); + await app.init(); + const server = await app.listen(0); + const address = server.address(); + if (address === null || typeof address === "string") throw new Error("Nest test server did not expose a TCP port"); + + return { app, baseUrl: `http://127.0.0.1:${address.port}` }; +} + +async function requestJson(testApp: Task6TestApp, path: string, init: RequestInit = {}) { + const response = await fetch(`${testApp.baseUrl}${path}`, { + ...init, + headers: { + "content-type": "application/json", + ...init.headers + } + }); + const body = (await response.json().catch(() => null)) as unknown; + return { response, body }; +} + +describe("Auth HTTP boundary", () => { + let testApp: Task6TestApp | undefined; + + afterEach(async () => { + await testApp?.app.close(); + testApp = undefined; + }); + + it("POST /auth/login returns a usable token for a seeded user and GET /me returns the actor roles", async () => { + testApp = await createTestApp(); + + const login = await requestJson(testApp, "/auth/login", { + method: "POST", + body: JSON.stringify({ email: "creator@example.test" }) + }); + + expect(login.response.status).toBe(201); + expect(login.body).toEqual({ + token: expect.any(String), + actor: { + id: "seed-creator", + email: "creator@example.test", + displayName: "Seed Creator", + roles: ["creator"] + } + }); + + const token = (login.body as { token: string }).token; + const me = await requestJson(testApp, "/me", { + headers: { authorization: `Bearer ${token}` } + }); + + expect(me.response.status).toBe(200); + expect(me.body).toEqual({ + id: "seed-creator", + email: "creator@example.test", + displayName: "Seed Creator", + roles: ["creator"] + }); + }); + + it("POST /auth/logout invalidates the session token used by tests", async () => { + testApp = await createTestApp(); + const login = await requestJson(testApp, "/auth/login", { + method: "POST", + body: JSON.stringify({ email: "operator@example.test" }) + }); + const token = (login.body as { token: string }).token; + + const logout = await requestJson(testApp, "/auth/logout", { + method: "POST", + headers: { authorization: `Bearer ${token}` } + }); + expect(logout.response.status).toBe(201); + expect(logout.body).toEqual({ ok: true }); + + const meAfterLogout = await requestJson(testApp, "/me", { + headers: { authorization: `Bearer ${token}` } + }); + expect(meAfterLogout.response.status).toBe(401); + expect(meAfterLogout.body).toMatchObject({ code: "UNAUTHENTICATED" }); + }); + + it("rejects anonymous access to a protected test route without calling later project/version endpoints", async () => { + testApp = await createTestApp(); + + const protectedResponse = await requestJson(testApp, "/task6-protected"); + + expect(protectedResponse.response.status).toBe(403); + expect(protectedResponse.body).toMatchObject({ code: "FORBIDDEN" }); + }); +}); diff --git a/apps/api/src/modules/auth/index.ts b/apps/api/src/modules/auth/index.ts new file mode 100644 index 00000000..01d9afd6 --- /dev/null +++ b/apps/api/src/modules/auth/index.ts @@ -0,0 +1,181 @@ +import { randomBytes } from "node:crypto"; +import { + Body, + Controller, + ForbiddenException, + Get, + Headers, + Injectable, + Module, + Post, + UnauthorizedException, + type CanActivate, + type ExecutionContext +} from "@nestjs/common"; +import type { AuthenticatedActor } from "../rbac/index.js"; + +export type AuthActor = AuthenticatedActor & { + readonly email: string; + readonly displayName: string; +}; + +export type LoginResult = { + readonly token: string; + readonly actor: AuthActor; +}; + +type LoginBody = { + readonly email?: unknown; + readonly userId?: unknown; +}; + +type RequestLike = { + readonly headers?: { + readonly authorization?: string | readonly string[]; + }; + actor?: AuthActor; +}; + +const seededUsers: readonly AuthActor[] = [ + { + id: "seed-admin", + email: "admin@example.test", + displayName: "Seed Admin", + roles: ["admin"] + }, + { + id: "seed-operator", + email: "operator@example.test", + displayName: "Seed Operator", + roles: ["operator"] + }, + { + id: "seed-creator", + email: "creator@example.test", + displayName: "Seed Creator", + roles: ["creator"] + }, + { + id: "seed-player", + email: "player@example.test", + displayName: "Seed Player", + roles: ["player"] + } +]; + +function apiError(code: string, message: string, details: unknown = null) { + return { + code, + message, + requestId: null, + details + }; +} + +function normalizeAuthorizationHeader(header: string | readonly string[] | undefined): string | undefined { + if (typeof header === "string") return header; + return header?.[0]; +} + +@Injectable() +export class AuthService { + private readonly usersById = new Map(seededUsers.map((user) => [user.id, user])); + private readonly usersByEmail = new Map(seededUsers.map((user) => [user.email, user])); + private readonly sessions = new Map(); + + login(body: LoginBody): LoginResult { + const actor = this.findSeededUser(body); + if (!actor) { + throw new UnauthorizedException(apiError("AUTH_INVALID_CREDENTIALS", "Unknown local S1 test user")); + } + + const token = randomBytes(32).toString("base64url"); + this.sessions.set(token, actor.id); + return { token, actor }; + } + + logout(authorization: string | readonly string[] | undefined): { readonly ok: true } { + const token = this.extractBearerToken(authorization); + if (!token || !this.sessions.delete(token)) { + throw new UnauthorizedException(apiError("UNAUTHENTICATED", "Session token is missing or invalid")); + } + + return { ok: true }; + } + + getActorFromAuthorizationHeader(authorization: string | readonly string[] | undefined): AuthActor | null { + const token = this.extractBearerToken(authorization); + if (!token) return null; + + const userId = this.sessions.get(token); + return userId ? this.usersById.get(userId) ?? null : null; + } + + requireActorFromAuthorizationHeader(authorization: string | readonly string[] | undefined): AuthActor { + const actor = this.getActorFromAuthorizationHeader(authorization); + if (!actor) { + throw new UnauthorizedException(apiError("UNAUTHENTICATED", "Session token is missing or invalid")); + } + + return actor; + } + + private findSeededUser(body: LoginBody): AuthActor | undefined { + if (typeof body.email === "string") return this.usersByEmail.get(body.email); + if (typeof body.userId === "string") return this.usersById.get(body.userId); + return undefined; + } + + private extractBearerToken(authorization: string | readonly string[] | undefined): string | null { + const header = normalizeAuthorizationHeader(authorization); + if (!header) return null; + + const [scheme, token, extra] = header.trim().split(/\s+/); + if (scheme !== "Bearer" || !token || extra) return null; + return token; + } +} + +@Injectable() +export class AuthGuard implements CanActivate { + constructor(private readonly authService: AuthService) {} + + canActivate(context: ExecutionContext): boolean { + const request = context.switchToHttp().getRequest(); + const actor = this.authService.getActorFromAuthorizationHeader(request.headers?.authorization); + if (!actor) { + // 受保护路由必须在服务端拒绝匿名访问;S6 之前不把 public feed 行为混入这里。 + throw new ForbiddenException(apiError("FORBIDDEN", "Authenticated actor is required")); + } + + request.actor = actor; + return true; + } +} + +@Controller() +export class AuthController { + constructor(private readonly authService: AuthService) {} + + @Post("auth/login") + login(@Body() body: LoginBody): LoginResult { + return this.authService.login(body); + } + + @Post("auth/logout") + logout(@Headers("authorization") authorization: string | readonly string[] | undefined): { readonly ok: true } { + return this.authService.logout(authorization); + } + + @Get("me") + me(@Headers("authorization") authorization: string | readonly string[] | undefined): AuthActor { + return this.authService.requireActorFromAuthorizationHeader(authorization); + } +} + +@Module({ + controllers: [AuthController], + providers: [AuthService, AuthGuard], + exports: [AuthService, AuthGuard] +}) +export class AuthModule {} diff --git a/apps/api/src/modules/harness-gate/harness-gate.spec.ts b/apps/api/src/modules/harness-gate/harness-gate.spec.ts new file mode 100644 index 00000000..78b3913c --- /dev/null +++ b/apps/api/src/modules/harness-gate/harness-gate.spec.ts @@ -0,0 +1,62 @@ +import { readFile } from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; +import { HarnessGateService, parseHarnessGateConfig } from "./index.js"; + +const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../../.."); +const fixturePath = (...segments: string[]) => path.join(repoRoot, "harness", "fixtures", ...segments); + +async function readFixture(...segments: string[]): Promise { + return JSON.parse(await readFile(fixturePath(...segments), "utf8")); +} + +describe("HarnessGateService", () => { + it("uses the S0 CLI client to accept a real passing contract fixture", async () => { + const gate = new HarnessGateService(); + + await expect( + gate.validateContract("GameIR", await readFixture("mvp", "valid", "simulation-game-ir-valid.json")) + ).resolves.toEqual({ ok: true, reasonCode: null }); + }); + + it("preserves S0 reasonCode for a real failing contract fixture", async () => { + const gate = new HarnessGateService(); + + await expect( + gate.validateContract( + "ValidationReport", + await readFixture("mvp", "invalid", "game-logic-validation-report-web-only-sdk-invalid.json") + ) + ).resolves.toEqual({ ok: false, reasonCode: "WEB_ONLY_SDK_USAGE" }); + }); + + it("accepts the real S0 review_approved transition fixture", async () => { + const gate = new HarnessGateService(); + + await expect( + gate.validateTransition("review_approved", await readFixture("lifecycle", "publish-approved-valid.json")) + ).resolves.toEqual({ ok: true, reasonCode: null }); + }); + + it("parses HARNESS_CLI_TIMEOUT_MS from the API env boundary with a 5000ms default", () => { + expect(parseHarnessGateConfig({})).toEqual({ timeoutMs: 5_000 }); + expect(parseHarnessGateConfig({ HARNESS_CLI_TIMEOUT_MS: "17" })).toEqual({ timeoutMs: 17 }); + expect(() => parseHarnessGateConfig({ HARNESS_CLI_TIMEOUT_MS: "0" })).toThrow(/HARNESS_CLI_TIMEOUT_MS/); + }); + + it("injects non-default env timeout into the harness client", async () => { + const gate = new HarnessGateService(parseHarnessGateConfig({ HARNESS_CLI_TIMEOUT_MS: "1" })); + + await expect( + gate.validateContract("GameIR", await readFixture("mvp", "valid", "simulation-game-ir-valid.json")) + ).resolves.toEqual({ ok: false, reasonCode: "HARNESS_TIMEOUT" }); + }); + + it("delegates CLI runtime ownership to the harness-client runtime subpath", async () => { + const source = await readFile(path.join(repoRoot, "apps/api/src/modules/harness-gate/index.ts"), "utf8"); + + expect(source).toContain('from "@huijing/harness-client/runtime"'); + expect(source).not.toMatch(/node:child_process|mkdtemp|writeFile|validate-harness\.mjs|JSON\.parse/); + }); +}); diff --git a/apps/api/src/modules/harness-gate/index.ts b/apps/api/src/modules/harness-gate/index.ts new file mode 100644 index 00000000..3d375c1e --- /dev/null +++ b/apps/api/src/modules/harness-gate/index.ts @@ -0,0 +1,40 @@ +import type { HarnessClient, HarnessGateResult } from "@huijing/harness-client"; +import { createHarnessClient } from "@huijing/harness-client/runtime"; + +export type { HarnessClient, HarnessGateResult }; + +export type HarnessGateConfig = { + readonly timeoutMs: number; +}; + +const defaultHarnessTimeoutMs = 5_000; + +export function parseHarnessGateConfig(env: { readonly HARNESS_CLI_TIMEOUT_MS?: string } = process.env): HarnessGateConfig { + const rawTimeout = env.HARNESS_CLI_TIMEOUT_MS; + const timeoutMs = rawTimeout === undefined || rawTimeout.trim() === "" ? defaultHarnessTimeoutMs : Number(rawTimeout); + + if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) { + throw new Error("HARNESS_CLI_TIMEOUT_MS must be a positive integer"); + } + + return { timeoutMs }; +} + +export class HarnessGateService implements HarnessClient { + private readonly client: HarnessClient; + + constructor(clientOrConfig?: HarnessClient | HarnessGateConfig) { + this.client = + clientOrConfig && "validateContract" in clientOrConfig + ? clientOrConfig + : createHarnessClient(clientOrConfig ?? parseHarnessGateConfig()); + } + + validateContract(contract: string, payload: unknown): Promise { + return this.client.validateContract(contract, payload); + } + + validateTransition(event: string, payload: unknown): Promise { + return this.client.validateTransition(event, payload); + } +} diff --git a/apps/api/src/modules/jobs/index.ts b/apps/api/src/modules/jobs/index.ts new file mode 100644 index 00000000..bd2f0f4e --- /dev/null +++ b/apps/api/src/modules/jobs/index.ts @@ -0,0 +1,982 @@ +import { randomUUID } from "node:crypto"; +import { readdir, readFile } from "node:fs/promises"; +import path from "node:path"; +import { + Controller, + ForbiddenException, + Get, + Inject, + Injectable, + Module, + NotFoundException, + Param, + Req, + UseGuards, + type OnModuleDestroy +} from "@nestjs/common"; +import { Prisma, type Job } from "../../generated/prisma/client.js"; +import { AuthGuard, AuthModule, type AuthActor } from "../auth/index.js"; +import { AuditService } from "../audit/index.js"; +import { BullMqQueueAdapter, InMemoryQueueAdapter, QueueUnavailableError } from "../queue/index.js"; +import { apiError, S1ApiRuntimeModule, S1PrismaClient } from "../projects/api-runtime.js"; +import type { QueueAdapter } from "../queue/index.js"; + +export type JobTarget = + | { + readonly type: "project"; + readonly id: string; + } + | { + readonly type: "version"; + readonly id: string; + }; + +export type EnqueueScopedJobInput = { + readonly id: string; + readonly actorId: string; + readonly projectId: string; + readonly type: string; + readonly idempotencyKey: string; + readonly target: JobTarget; + readonly payloadJson: Prisma.InputJsonValue; + readonly maxAttempts?: number; + readonly timeoutMs?: number; + readonly onJobEnqueueFailed?: (db: Prisma.TransactionClient, job: Job, error: unknown) => Promise; +}; + +export type EnqueueScopedJobResult = { + readonly job: Job; + readonly created: boolean; + readonly enqueued: boolean; +}; + +export type JobExecutionStoreOptions = { + readonly db: Prisma.TransactionClient; + readonly now?: () => Date; + readonly leaseMs?: number; + readonly retryDelayMs?: number; +}; + +export type JobExecutionErrorCode = + | "TARGET_NOT_FOUND" + | "TARGET_PROJECT_MISMATCH" + | "JOB_NOT_FOUND" + | "STALE_JOB_LEASE" + | "JOB_CANCEL_NOT_ALLOWED" + | "JOB_ENQUEUE_REQUIRES_ROOT_CLIENT"; + +export type JobExecutionBoundaryViolation = { + readonly path: string; + readonly reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE"; +}; + +type RequestWithActor = { + readonly actor: AuthActor; +}; + +export type JobDto = { + readonly id: string; + readonly actorId: string; + readonly projectId: string; + readonly type: string; + readonly status: string; + readonly attempts: number; + readonly maxAttempts: number; + readonly targetType: string; + readonly targetId: string; + readonly payloadJson: unknown; + readonly errorCode: string | null; + readonly createdAt: string; + readonly updatedAt: string; +}; + +type ScanFile = { + readonly path: string; + readonly content: string; +}; + +const jobExecutionStorePath = "apps/api/src/modules/jobs/index.ts"; +const ignoredScanSegments = new Set(["node_modules", "dist", ".vite", "coverage", ".next", "generated"]); +const jobRuntimeFields = [ + "status", + "attempts", + "nextRetryAt", + "errorCode", + "leaseToken", + "leasedBy", + "leaseExpiresAt", + "lockVersion", + "timeoutAt" +]; + +function escapeRegExp(value: string): string { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +export const S1_QUEUE_ADAPTER = Symbol("S1_QUEUE_ADAPTER"); +export const S1_QUEUE_ADAPTER_INNER = Symbol("S1_QUEUE_ADAPTER_INNER"); + +export type QueueEnv = { + readonly QUEUE_ADAPTER?: string; + readonly REDIS_URL?: string; +}; + +class UnavailableQueueAdapter implements QueueAdapter { + constructor(private readonly reason: string) {} + + async enqueue(): Promise { + throw new QueueUnavailableError(this.reason); + } + + async process(): Promise { + throw new QueueUnavailableError(this.reason); + } + + async close(): Promise { + return undefined; + } +} + +export function createQueueAdapterFromEnv(env: QueueEnv = process.env): QueueAdapter { + const adapter = env.QUEUE_ADAPTER?.trim(); + if (!adapter) return new UnavailableQueueAdapter("QUEUE_ADAPTER is required"); + if (adapter === "memory") return new InMemoryQueueAdapter(); + if (adapter === "bullmq") { + if (!env.REDIS_URL || env.REDIS_URL.trim() === "") { + return new UnavailableQueueAdapter("REDIS_URL is required when QUEUE_ADAPTER=bullmq"); + } + return new BullMqQueueAdapter({ queueName: "huijing-s1-jobs", redisUrl: env.REDIS_URL }); + } + return new UnavailableQueueAdapter(`Unsupported QUEUE_ADAPTER: ${adapter}`); +} + +@Injectable() +export class ManagedQueueAdapter implements QueueAdapter, OnModuleDestroy { + constructor(private readonly inner: QueueAdapter) {} + + async enqueue(message: Parameters[0]): Promise { + return this.inner.enqueue(message); + } + + async process(handler: Parameters[0]): Promise { + return this.inner.process(handler); + } + + async close(): Promise { + await this.inner.close(); + } + + async onModuleDestroy(): Promise { + // Nest app.close() 必须关闭底层队列连接;BullMQ/ioredis 不能依赖进程退出回收。 + await this.close(); + } +} + +export class JobExecutionError extends Error { + readonly code: JobExecutionErrorCode; + + constructor(code: JobExecutionErrorCode, message = code) { + super(message); + this.name = "JobExecutionError"; + this.code = code; + } +} + +function targetScopeKey(target: JobTarget): string { + return `${target.type}:${target.id}`; +} + +function terminalOrIdleLeaseData() { + return { + leaseToken: null, + leasedBy: null, + leaseExpiresAt: null + }; +} + +export class JobExecutionStore { + private readonly db: Prisma.TransactionClient; + private readonly now: () => Date; + private readonly leaseMs: number; + private readonly retryDelayMs: number; + + constructor(options: JobExecutionStoreOptions) { + this.db = options.db; + this.now = options.now ?? (() => new Date()); + this.leaseMs = options.leaseMs ?? 30_000; + this.retryDelayMs = options.retryDelayMs ?? 30_000; + } + + async enqueueScopedJob(input: EnqueueScopedJobInput, queue: QueueAdapter): Promise { + if (!this.isRootClient()) { + throw new JobExecutionError("JOB_ENQUEUE_REQUIRES_ROOT_CLIENT"); + } + + const existing = await this.db.job.findUnique({ + where: { + actorId_projectId_type_targetScopeKey_idempotencyKey: { + actorId: input.actorId, + projectId: input.projectId, + type: input.type, + targetScopeKey: targetScopeKey(input.target), + idempotencyKey: input.idempotencyKey + } + } + }); + if (existing) return { job: existing, created: false, enqueued: false }; + + const { job, created } = await this.withTransaction(async (tx) => { + await this.assertTargetMatchesProject(tx, input); + + const inserted = await tx.job.createManyAndReturn({ + data: [ + { + id: input.id, + actorId: input.actorId, + projectId: input.projectId, + type: input.type, + idempotencyKey: input.idempotencyKey, + status: "queued", + attempts: 0, + maxAttempts: input.maxAttempts ?? 3, + timeoutAt: input.timeoutMs ? new Date(this.now().getTime() + input.timeoutMs) : null, + nextRetryAt: null, + errorCode: null, + targetType: input.target.type, + targetId: input.target.id, + targetScopeKey: targetScopeKey(input.target), + gameProjectId: input.target.type === "project" ? input.target.id : null, + gameVersionId: input.target.type === "version" ? input.target.id : null, + payloadJson: input.payloadJson + } + ], + skipDuplicates: true + }); + + const job = + inserted[0] ?? + (await tx.job.findUniqueOrThrow({ + where: { + actorId_projectId_type_targetScopeKey_idempotencyKey: { + actorId: input.actorId, + projectId: input.projectId, + type: input.type, + targetScopeKey: targetScopeKey(input.target), + idempotencyKey: input.idempotencyKey + } + } + })); + + // S1 generic Job enqueue 不暴露 pre-enqueue DB callback;事务只创建 Job,避免 queue 前扩展点制造半成品 target 或错误审计。 + return { job, created: inserted.length > 0 }; + }); + + if (!created) return { job, created: false, enqueued: false }; + + try { + await queue.enqueue({ jobId: job.id, type: job.type, payload: job.payloadJson }); + } catch (error) { + await this.markEnqueueFailed(job.id); + try { + // queue 失败后必须留下可排障事实;若审计自身失败,仍保留原始 QUEUE_UNAVAILABLE 作为 API 失败语义。 + await input.onJobEnqueueFailed?.(this.db, job, error); + } catch { + // 原始 queue failure 比审计失败更接近调用方需要处理的故障边界。 + } + throw error; + } + + return { job, created: true, enqueued: true }; + } + + async claimNext(workerId: string, now = this.now()): Promise { + const candidate = await this.db.job.findFirst({ + where: { + OR: [ + { status: "queued" }, + { + status: "pending_retry", + OR: [{ nextRetryAt: null }, { nextRetryAt: { lte: now } }] + } + ] + }, + orderBy: [{ createdAt: "asc" }, { id: "asc" }] + }); + if (!candidate) return null; + + const leaseToken = randomUUID(); + const claimed = await this.db.job.updateManyAndReturn({ + where: { + id: candidate.id, + lockVersion: candidate.lockVersion, + OR: [ + { status: "queued" }, + { + status: "pending_retry", + OR: [{ nextRetryAt: null }, { nextRetryAt: { lte: now } }] + } + ] + }, + data: { + status: "running", + leaseToken, + leasedBy: workerId, + leaseExpiresAt: new Date(now.getTime() + this.leaseMs), + nextRetryAt: null, + errorCode: null, + lockVersion: { increment: 1 } + } + }); + + return claimed[0] ?? null; + } + + async markSucceeded(jobId: string, leaseToken: string): Promise { + const updated = await this.db.job.updateManyAndReturn({ + where: { id: jobId, status: "running", leaseToken }, + data: { + status: "succeeded", + ...terminalOrIdleLeaseData(), + nextRetryAt: null, + errorCode: null, + lockVersion: { increment: 1 } + } + }); + return this.requireLeaseUpdate(updated); + } + + async markFailedOrRetry(jobId: string, leaseToken: string, errorCode: string): Promise { + const job = await this.db.job.findUnique({ where: { id: jobId } }); + if (!job) throw new JobExecutionError("JOB_NOT_FOUND"); + if (job.status !== "running" || job.leaseToken !== leaseToken) throw new JobExecutionError("STALE_JOB_LEASE"); + + const attempts = job.attempts + 1; + const willRetry = attempts < job.maxAttempts; + const updated = await this.db.job.updateManyAndReturn({ + where: { id: jobId, status: "running", leaseToken, lockVersion: job.lockVersion }, + data: { + status: willRetry ? "pending_retry" : "failed", + attempts, + errorCode, + nextRetryAt: willRetry ? new Date(this.now().getTime() + this.retryDelayMs) : null, + ...terminalOrIdleLeaseData(), + lockVersion: { increment: 1 } + } + }); + return this.requireLeaseUpdate(updated); + } + + async markTimedOut(jobId: string, now = this.now(), errorCode = "JOB_TIMEOUT"): Promise { + const job = await this.db.job.findUnique({ where: { id: jobId } }); + if (!job) throw new JobExecutionError("JOB_NOT_FOUND"); + const leaseTimedOut = job.leaseExpiresAt !== null && job.leaseExpiresAt <= now; + const jobTimedOut = job.timeoutAt !== null && job.timeoutAt <= now; + if (job.status !== "running" || (!leaseTimedOut && !jobTimedOut)) { + throw new JobExecutionError("STALE_JOB_LEASE"); + } + + const attempts = job.attempts + 1; + const willRetry = attempts < job.maxAttempts; + const updated = await this.db.job.updateManyAndReturn({ + where: { id: jobId, status: "running", lockVersion: job.lockVersion }, + data: { + status: willRetry ? "pending_retry" : "failed", + attempts, + errorCode, + nextRetryAt: willRetry ? new Date(now.getTime() + this.retryDelayMs) : null, + ...terminalOrIdleLeaseData(), + lockVersion: { increment: 1 } + } + }); + return this.requireLeaseUpdate(updated); + } + + async cancelQueued(jobId: string, actorId: string): Promise { + const updated = await this.db.job.updateManyAndReturn({ + where: { id: jobId, actorId, status: "queued" }, + data: { + status: "canceled", + ...terminalOrIdleLeaseData(), + lockVersion: { increment: 1 } + } + }); + if (updated[0]) return updated[0]; + + const existing = await this.db.job.findUnique({ where: { id: jobId } }); + if (!existing) throw new JobExecutionError("JOB_NOT_FOUND"); + throw new JobExecutionError("JOB_CANCEL_NOT_ALLOWED"); + } + + private async markEnqueueFailed(jobId: string): Promise { + await this.db.job.updateMany({ + where: { id: jobId, status: "queued" }, + data: { + status: "pending_retry", + errorCode: "QUEUE_ENQUEUE_FAILED", + nextRetryAt: new Date(this.now().getTime() + this.retryDelayMs), + lockVersion: { increment: 1 } + } + }); + } + + private async assertTargetMatchesProject(tx: Prisma.TransactionClient, input: EnqueueScopedJobInput): Promise { + if (input.target.type === "project") { + const project = await tx.gameProject.findUnique({ where: { id: input.target.id } }); + if (!project) throw new JobExecutionError("TARGET_NOT_FOUND"); + if (project.id !== input.projectId) throw new JobExecutionError("TARGET_PROJECT_MISMATCH"); + return; + } + + const version = await tx.gameVersion.findUnique({ where: { id: input.target.id } }); + if (!version) throw new JobExecutionError("TARGET_NOT_FOUND"); + if (version.projectId !== input.projectId) throw new JobExecutionError("TARGET_PROJECT_MISMATCH"); + } + + private requireLeaseUpdate(updated: Job[]): Job { + if (updated[0]) return updated[0]; + throw new JobExecutionError("STALE_JOB_LEASE"); + } + + private async withTransaction(callback: (tx: Prisma.TransactionClient) => Promise): Promise { + const maybeRootClient = this.db as Prisma.TransactionClient & { + $transaction?: (fn: (tx: Prisma.TransactionClient) => Promise) => Promise; + }; + if (typeof maybeRootClient.$transaction === "function") return maybeRootClient.$transaction(callback); + return callback(this.db); + } + + private isRootClient(): boolean { + const candidate = this.db as { $transaction?: unknown; $connect?: unknown; $disconnect?: unknown }; + return ( + typeof candidate.$transaction === "function" && + typeof candidate.$connect === "function" && + typeof candidate.$disconnect === "function" + ); + } +} + +function jobDto(job: Job): JobDto { + return { + id: job.id, + actorId: job.actorId, + projectId: job.projectId, + type: job.type, + status: job.status, + attempts: job.attempts, + maxAttempts: job.maxAttempts, + targetType: job.targetType, + targetId: job.targetId, + payloadJson: job.payloadJson, + errorCode: job.errorCode, + createdAt: job.createdAt.toISOString(), + updatedAt: job.updatedAt.toISOString() + }; +} + +@Injectable() +export class JobApiService { + constructor( + private readonly db: S1PrismaClient, + @Inject(S1_QUEUE_ADAPTER) private readonly queue: QueueAdapter + ) {} + + async getJob(actor: AuthActor, jobId: string): Promise { + const job = await this.db.job.findUnique({ where: { id: jobId } }); + if (!job) throw new NotFoundException(apiError("NOT_FOUND", "Job not found", { jobId })); + if (job.actorId !== actor.id) { + // Job 是 creator 发起的直接对象;S1 不给 operator/admin 暴露未列明的 job 管理读权限。 + throw new ForbiddenException(apiError("FORBIDDEN", "Actor cannot access this job", { jobId })); + } + return jobDto(job); + } + + async enqueueScopedJobForActor(input: EnqueueScopedJobInput): Promise { + const store = new JobExecutionStore({ db: this.db }); + const result = await store.enqueueScopedJob( + { + ...input, + onJobEnqueueFailed: async (db, job) => { + await new AuditService({ db }).append({ + id: randomUUID(), + actorId: input.actorId, + action: "job.enqueue_failed", + targetType: "Job", + targetId: job.id, + eventJson: { + projectId: input.projectId, + type: input.type, + targetType: input.target.type, + targetId: input.target.id, + errorCode: "QUEUE_ENQUEUE_FAILED" + } + }); + } + }, + this.queue + ); + + if (result.created && result.enqueued) { + // job.enqueued 只在 queue side effect 成功后追加;审计失败会向调用方抛出,避免静默成功但缺审计。 + await new AuditService({ db: this.db }).append({ + id: randomUUID(), + actorId: input.actorId, + action: "job.enqueued", + targetType: "Job", + targetId: result.job.id, + eventJson: { + projectId: input.projectId, + type: input.type, + targetType: input.target.type, + targetId: input.target.id, + idempotencyKey: input.idempotencyKey + } + }); + } + + return result.job; + } +} + +@Controller() +@UseGuards(AuthGuard) +export class JobsController { + constructor(private readonly service: JobApiService) {} + + @Get("jobs/:jobId") + getJob(@Req() request: RequestWithActor, @Param("jobId") jobId: string): Promise { + return this.service.getJob(request.actor, jobId); + } +} + +@Module({ + imports: [S1ApiRuntimeModule, AuthModule], + controllers: [JobsController], + providers: [ + JobApiService, + { + provide: S1_QUEUE_ADAPTER_INNER, + useFactory: () => createQueueAdapterFromEnv() + }, + { + provide: S1_QUEUE_ADAPTER, + useFactory: (queue: QueueAdapter) => new ManagedQueueAdapter(queue), + inject: [S1_QUEUE_ADAPTER_INNER] + } + ], + exports: [JobApiService, S1_QUEUE_ADAPTER, S1_QUEUE_ADAPTER_INNER] +}) +export class JobsApiModule {} + +function skipWhitespaceForward(content: string, index: number): number { + let cursor = index; + while (cursor < content.length && /\s/.test(content.charAt(cursor))) cursor += 1; + return cursor; +} + +function skipWhitespaceBackward(content: string, index: number): number { + let cursor = index; + while (cursor >= 0 && /\s/.test(content.charAt(cursor))) cursor -= 1; + return cursor; +} + +function isStaticQuotedPropertyKey(content: string, literalStart: number, literalEnd: number): boolean { + const afterLiteral = skipWhitespaceForward(content, literalEnd); + if (content[afterLiteral] === ":") return true; + + const afterComputedKey = skipWhitespaceForward(content, afterLiteral + 1); + if (content[afterLiteral] !== "]" || content[afterComputedKey] !== ":") return false; + + const beforeLiteral = skipWhitespaceBackward(content, literalStart - 1); + return content[beforeLiteral] === "["; +} + +function stripStringLiteralsExceptPropertyKeys(content: string): string { + let output = ""; + + for (let index = 0; index < content.length; index += 1) { + const quote = content[index]; + if (quote === "/" && isRegexLiteralStart(content, index)) { + const literalEnd = findRegexLiteralEnd(content, index); + if (literalEnd !== -1) { + output += "/".padEnd(literalEnd - index, " ") + "/"; + index = literalEnd; + continue; + } + } + if (quote !== '"' && quote !== "'" && quote !== "`") { + output += quote; + continue; + } + + const literalStart = index; + let literalEnd = literalStart + 1; + while (literalEnd < content.length) { + const char = content[literalEnd]; + if (char === "\\") { + literalEnd += 2; + continue; + } + literalEnd += 1; + if (char === quote) break; + } + + const literal = content.slice(literalStart, literalEnd); + // 只保留对象静态 key,普通字符串值和测试 fixture 字符串仍剥离,避免边界扫描误报。 + output += isStaticQuotedPropertyKey(content, literalStart, literalEnd) ? literal : `${quote}${quote}`; + index = literalEnd - 1; + } + + return output; +} + +function maskCommentsOutsideStringLiterals(content: string): string { + let output = ""; + let index = 0; + + while (index < content.length) { + const char = content[index]; + const next = content[index + 1]; + + if (char === "/" && next === "/") { + output += " "; + index += 2; + while (index < content.length && content[index] !== "\n" && content[index] !== "\r") { + output += " "; + index += 1; + } + continue; + } + + if (char === "/" && next === "*") { + output += " "; + index += 2; + while (index < content.length) { + const blockChar = content[index]; + const blockNext = content[index + 1]; + if (blockChar === "*" && blockNext === "/") { + output += " "; + index += 2; + break; + } + output += blockChar === "\n" || blockChar === "\r" ? blockChar : " "; + index += 1; + } + continue; + } + + if (char === "/" && isRegexLiteralStart(content, index)) { + const literalEnd = findRegexLiteralEnd(content, index); + if (literalEnd !== -1) { + output += content.slice(index, literalEnd + 1); + index = literalEnd + 1; + continue; + } + } + + if (char !== '"' && char !== "'" && char !== "`") { + output += char; + index += 1; + continue; + } + + output += char; + index += 1; + while (index < content.length) { + const stringChar = content[index]; + output += stringChar; + index += 1; + if (stringChar === "\\") { + if (index < content.length) { + output += content[index]; + index += 1; + } + continue; + } + if (stringChar === char) break; + } + } + + return output; +} + +function isRegexLiteralStart(content: string, slashIndex: number): boolean { + const cursor = skipWhitespaceBackward(content, slashIndex - 1); + if (cursor < 0) return true; + + const previous = content.charAt(cursor); + if ("([{:;,=!?&|+-*%^~<>".includes(previous)) return true; + return /\b(?:return|throw|case|delete|typeof|void|new|in|of|yield|await)\b/.test(content.slice(Math.max(0, cursor - 12), cursor + 1)); +} + +function findRegexLiteralEnd(content: string, slashIndex: number): number { + let inCharClass = false; + for (let cursor = slashIndex + 1; cursor < content.length; cursor += 1) { + const char = content[cursor]; + if (char === "\\") { + cursor += 1; + continue; + } + if (char === "[") inCharClass = true; + if (char === "]") inCharClass = false; + if (char === "/" && !inCharClass) { + let end = cursor + 1; + while (end < content.length && /[a-z]/i.test(content.charAt(end))) end += 1; + return end - 1; + } + } + return -1; +} + +function findMatchingParen(content: string, openParenIndex: number): number { + let depth = 0; + for (let index = openParenIndex; index < content.length; index += 1) { + const char = content[index]; + if (char === "(") depth += 1; + if (char === ")") { + depth -= 1; + if (depth === 0) return index; + } + } + return -1; +} + +function findMatchingBrace(content: string, openBraceIndex: number): number { + let depth = 0; + for (let index = openBraceIndex; index < content.length; index += 1) { + const char = content[index]; + if (char === "{") depth += 1; + if (char === "}") { + depth -= 1; + if (depth === 0) return index; + } + } + return -1; +} + +function maskStringLiterals(content: string): string { + let output = ""; + let index = 0; + + while (index < content.length) { + const quote = content[index]; + if (quote === "/" && isRegexLiteralStart(content, index)) { + const literalEnd = findRegexLiteralEnd(content, index); + if (literalEnd !== -1) { + output += "/".padEnd(literalEnd - index, " ") + "/"; + index = literalEnd + 1; + continue; + } + } + if (quote !== '"' && quote !== "'" && quote !== "`") { + output += quote; + index += 1; + continue; + } + + output += quote; + index += 1; + while (index < content.length) { + const char = content[index]; + if (char === "\\") { + output += " "; + index += 1; + if (index < content.length) { + output += " "; + index += 1; + } + continue; + } + if (char === quote) { + output += quote; + index += 1; + break; + } + output += " "; + index += 1; + } + } + + return output; +} + +function findStringLiteralEnd(content: string, literalStart: number): number { + const quote = content[literalStart]; + let cursor = literalStart + 1; + + while (cursor < content.length) { + const char = content[cursor]; + if (char === "\\") { + cursor += 2; + continue; + } + if (char === quote) return cursor; + cursor += 1; + } + + return -1; +} + +function stripSqlComments(content: string): string { + return content + .replace(/\/\*[\s\S]*?\*\//g, "") + .split("\n") + .map((line) => line.replace(/--.*$/, "")) + .join("\n"); +} + +function hasVariableizedOrSpreadJobData(callBody: string): boolean { + return ( + /\bdata\s*(?:[,}])/.test(callBody) || + /\bdata\s*:\s*[A-Za-z_$][\w$]*\b/.test(callBody) || + /\bdata\s*:\s*(?:\{|\[)[\s\S]*\.\.\./.test(callBody) + ); +} + +function hasComputedJobDataKey(callBody: string): boolean { + const dataObjectPattern = /\bdata\s*:\s*\{/g; + for (const match of callBody.matchAll(dataObjectPattern)) { + const openBraceIndex = callBody.indexOf("{", match.index); + if (openBraceIndex === -1) continue; + const closeBraceIndex = findMatchingBrace(callBody, openBraceIndex); + if (closeBraceIndex === -1) continue; + const dataObjectBody = callBody.slice(openBraceIndex, closeBraceIndex + 1); + // Job 运行态字段只能通过 JobExecutionStore 写入;computed key 无法静态证明安全,统一拦截。 + if (/\[[^\]]+\]\s*:/.test(dataObjectBody)) return true; + } + return false; +} + +function hasForbiddenJobWriteCallBody(callBody: string): boolean { + const runtimeFieldPattern = new RegExp(`\\b(?:${jobRuntimeFields.map(escapeRegExp).join("|")})\\b`); + return runtimeFieldPattern.test(callBody) || hasVariableizedOrSpreadJobData(callBody) || hasComputedJobDataKey(callBody); +} + +function hasRawJobRuntimeFieldWrite(sqlSource: string): boolean { + const sql = stripSqlComments(sqlSource) + .replace(/\\(["'`])/g, "$1") + .replace(/\\n/g, "\n") + .replace(/\\r/g, "\r") + .replace(/\\t/g, "\t"); + const quotedJob = String.raw`["'\`]?Job["'\`]?`; + const runtimeField = String.raw`["'\`]?(?:${jobRuntimeFields.map(escapeRegExp).join("|")})["'\`]?`; + return ( + new RegExp(String.raw`\bUPDATE\s+${quotedJob}\s+SET\b[\s\S]*?${runtimeField}\s*=`, "i").test(sql) || + new RegExp(String.raw`\bINSERT\s+INTO\s+${quotedJob}\s*\([^)]*${runtimeField}[\s\S]*?\)\s*VALUES\b`, "i").test(sql) + ); +} + +function hasRawJobStatusWrite(content: string): boolean { + // raw SQL 检测仍从原始 content 切片读取 SQL 字符串;structure 只负责可靠找到调用边界。 + const structure = maskStringLiterals(maskCommentsOutsideStringLiterals(content)); + const rawCallPattern = /\.\$(?:executeRawUnsafe|executeRaw|queryRawUnsafe|queryRaw)\s*(?:<[^>()`]*>)?\s*/g; + + for (const match of structure.matchAll(rawCallPattern)) { + const callStart = skipWhitespaceForward(structure, match.index + match[0].length); + if (structure[callStart] === "(") { + const closeParenIndex = findMatchingParen(structure, callStart); + if (closeParenIndex !== -1 && hasRawJobRuntimeFieldWrite(content.slice(callStart, closeParenIndex + 1))) return true; + continue; + } + + if (structure[callStart] === "`") { + const templateEnd = findStringLiteralEnd(content, callStart); + if (templateEnd !== -1 && hasRawJobRuntimeFieldWrite(content.slice(callStart, templateEnd + 1))) return true; + } + } + + return false; +} + +function jobExecutionStoreClassSpans(content: string): Array<{ readonly start: number; readonly end: number }> { + const spans: Array<{ readonly start: number; readonly end: number }> = []; + const structure = maskStringLiterals(maskCommentsOutsideStringLiterals(content)); + const classPattern = /\b(?:export\s+)?class\s+JobExecutionStore\b/g; + + for (const match of structure.matchAll(classPattern)) { + if (typeof match.index !== "number") continue; + const openBraceIndex = structure.indexOf("{", match.index + match[0].length); + if (openBraceIndex === -1) continue; + const closeBraceIndex = findMatchingBrace(structure, openBraceIndex); + if (closeBraceIndex === -1) continue; + spans.push({ start: match.index, end: closeBraceIndex + 1 }); + } + + return spans; +} + +function maskSpans(content: string, spans: ReadonlyArray<{ readonly start: number; readonly end: number }>): string { + if (spans.length === 0) return content; + let output = ""; + let cursor = 0; + + for (const span of [...spans].sort((left, right) => left.start - right.start)) { + if (span.start < cursor) continue; + output += content.slice(cursor, span.start); + output += " ".repeat(span.end - span.start); + cursor = span.end; + } + + return output + content.slice(cursor); +} + +function maskJobExecutionStoreClassBodies(content: string): string { + // 本地静态边界只豁免 JobExecutionStore 类体;同文件其他 class 仍按外部写入处理。 + return maskSpans(content, jobExecutionStoreClassSpans(content)); +} + +function hasJobStatusWrite(content: string): boolean { + // 逐个 Prisma Job 写调用检查调用体,避免测试中的字符串 fixture 或后续断言文本造成跨调用误报。 + const scanContent = stripStringLiteralsExceptPropertyKeys(maskCommentsOutsideStringLiterals(content)); + const callPattern = /\.job\.(?:create|createMany|createManyAndReturn|update|updateMany|updateManyAndReturn|upsert)\s*\(/g; + for (const match of scanContent.matchAll(callPattern)) { + const openParenIndex = scanContent.indexOf("(", match.index); + if (openParenIndex === -1) continue; + const closeParenIndex = findMatchingParen(scanContent, openParenIndex); + if (closeParenIndex === -1) continue; + const callBody = scanContent.slice(openParenIndex, closeParenIndex + 1); + if (hasForbiddenJobWriteCallBody(callBody)) return true; + } + return hasRawJobStatusWrite(content); +} + +function isIgnoredScanPath(filePath: string): boolean { + return filePath.split("/").some((segment) => ignoredScanSegments.has(segment)); +} + +export function findJobExecutionBoundaryViolations(files: readonly ScanFile[]): JobExecutionBoundaryViolation[] { + const violations: JobExecutionBoundaryViolation[] = []; + for (const file of files) { + const normalizedPath = file.path.split(path.sep).join("/"); + if (isIgnoredScanPath(normalizedPath)) continue; + const scanContent = normalizedPath === jobExecutionStorePath ? maskJobExecutionStoreClassBodies(file.content) : file.content; + if (hasJobStatusWrite(scanContent)) { + violations.push({ path: normalizedPath, reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" }); + } + } + return violations; +} + +async function collectFiles(root: string, relativeDir: string): Promise { + const absoluteDir = path.join(root, relativeDir); + const entries = await readdir(absoluteDir, { withFileTypes: true }).catch(() => []); + const files: ScanFile[] = []; + + for (const entry of entries) { + if (entry.isDirectory() && ignoredScanSegments.has(entry.name)) continue; + const relativePath = path.join(relativeDir, entry.name); + const absolutePath = path.join(root, relativePath); + if (entry.isDirectory()) files.push(...(await collectFiles(root, relativePath))); + if (entry.isFile() && /\.(?:ts|tsx|js|mjs|cjs)$/.test(entry.name)) { + files.push({ path: relativePath, content: await readFile(absolutePath, "utf8") }); + } + } + + return files; +} + +export async function scanJobExecutionBoundary(repoRoot: string): Promise { + return findJobExecutionBoundaryViolations([ + ...(await collectFiles(repoRoot, "apps/api/src")), + ...(await collectFiles(repoRoot, "apps/worker/src")) + ]); +} diff --git a/apps/api/src/modules/jobs/jobs.api.spec.ts b/apps/api/src/modules/jobs/jobs.api.spec.ts new file mode 100644 index 00000000..bf4f18a7 --- /dev/null +++ b/apps/api/src/modules/jobs/jobs.api.spec.ts @@ -0,0 +1,449 @@ +import { type INestApplication } from "@nestjs/common"; +import { Test } from "@nestjs/testing"; +import { PrismaPg } from "@prisma/adapter-pg"; +import pg from "pg"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { AppModule } from "../../app.module.js"; +import { Prisma, PrismaClient } from "../../generated/prisma/client.js"; +import { BullMqQueueAdapter, InMemoryQueueAdapter, QueueUnavailableError, type QueueAdapter, type QueueMessage } from "../queue/index.js"; +import { StateTransitionService } from "../state-transition/index.js"; +import { + JobApiService, + JobExecutionStore, + ManagedQueueAdapter, + S1_QUEUE_ADAPTER, + S1_QUEUE_ADAPTER_INNER, + createQueueAdapterFromEnv +} from "./index.js"; + +const databaseUrl = process.env.DATABASE_URL ?? "postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public"; +const adapter = new PrismaPg({ connectionString: databaseUrl }); +const prisma = new PrismaClient({ adapter }); +const runId = `task8-jobs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; +const jobTestIsolationLockKey = 810_008; +let lockClient: pg.Client | undefined; + +type DbClient = Prisma.TransactionClient; + +class RecordingQueue implements QueueAdapter { + readonly messages: QueueMessage[] = []; + + async enqueue(message: QueueMessage): Promise { + this.messages.push(message); + } + + async process(): Promise { + return undefined; + } + + async close(): Promise { + return undefined; + } +} + +class FailingQueue implements QueueAdapter { + async enqueue(): Promise { + throw new QueueUnavailableError("test queue unavailable"); + } + + async process(): Promise { + return undefined; + } + + async close(): Promise { + return undefined; + } +} + +class CloseCountingQueue implements QueueAdapter { + closeCalls = 0; + + async enqueue(): Promise { + return undefined; + } + + async process(): Promise { + return undefined; + } + + async close(): Promise { + this.closeCalls += 1; + } +} + +class CompletingQueue extends RecordingQueue { + async enqueue(message: QueueMessage): Promise { + // 测试队列模拟 worker 完成时也必须走 JobExecutionStore,避免 spec 夹具绕过 Job 状态单写入口。 + const store = new JobExecutionStore({ db: prisma }); + await expectOnlyEligibleJob(message.jobId); + const claimed = await store.claimNext(`completing-queue-${runId}`); + expect(claimed).toMatchObject({ id: message.jobId, leaseToken: expect.any(String) }); + await store.markSucceeded(message.jobId, claimed?.leaseToken ?? "missing"); + await super.enqueue(message); + } +} + +type TestApp = { + readonly app: INestApplication; + readonly baseUrl: string; + readonly jobApiService: JobApiService; + readonly queue: RecordingQueue; +}; + +async function createTestApp(queue: RecordingQueue = new RecordingQueue()): Promise { + const moduleRef = await Test.createTestingModule({ + imports: [AppModule] + }) + .overrideProvider(S1_QUEUE_ADAPTER) + .useValue(queue) + .compile(); + const app = moduleRef.createNestApplication(); + await app.init(); + const server = await app.listen(0); + const address = server.address(); + if (address === null || typeof address === "string") throw new Error("Nest test server did not expose a TCP port"); + return { + app, + baseUrl: `http://127.0.0.1:${address.port}`, + jobApiService: moduleRef.get(JobApiService), + queue + }; +} + +async function requestJson(testApp: TestApp, requestPath: string, init: RequestInit = {}) { + const response = await fetch(`${testApp.baseUrl}${requestPath}`, { + ...init, + headers: { + "content-type": "application/json", + ...init.headers + } + }); + const body = (await response.json().catch(() => null)) as unknown; + return { response, body }; +} + +async function login(testApp: TestApp, email: string): Promise { + const response = await requestJson(testApp, "/auth/login", { + method: "POST", + body: JSON.stringify({ email }) + }); + expect(response.response.status).toBe(201); + return (response.body as { token: string }).token; +} + +async function ensureSeedUsers(db: DbClient): Promise { + await db.user.upsert({ + where: { id: "seed-creator" }, + update: {}, + create: { id: "seed-creator", email: "creator@example.test", displayName: "Seed Creator" } + }); + await db.user.upsert({ + where: { id: "seed-creator-other" }, + update: {}, + create: { id: "seed-creator-other", email: "creator-other@example.test", displayName: "Seed Other Creator" } + }); +} + +async function seedProject(db: DbClient, suffix: string, ownerId: string) { + return db.gameProject.create({ + data: { id: `${runId}-${suffix}-project`, ownerId, slug: `${runId}-${suffix}`, title: `${suffix} project` } + }); +} + +async function seedDraftVersion(db: DbClient, projectId: string, suffix: string) { + const service = new StateTransitionService({ + db, + blockedAuditDb: db, + harnessGate: { + validateContract: async () => ({ ok: true, reasonCode: null }), + validateTransition: async () => ({ ok: true, reasonCode: null }) + } + }); + return service.createDraftVersion({ + id: `${runId}-${suffix}-version`, + projectId, + versionNumber: 1, + configJson: { suffix } + }); +} + +async function seedCompletedProjectJob(db: PrismaClient, suffix: string, actorId: string, projectId: string) { + const store = new JobExecutionStore({ db }); + const result = await store.enqueueScopedJob( + { + id: `${runId}-${suffix}`, + actorId, + projectId, + type: "noop", + idempotencyKey: suffix, + target: { type: "project", id: projectId }, + payloadJson: { ok: true } + }, + new RecordingQueue() + ); + await expectOnlyEligibleJob(result.job.id); + const claimed = await store.claimNext(`completed-fixture-${suffix}`); + expect(claimed).toMatchObject({ id: result.job.id, leaseToken: expect.any(String) }); + return store.markSucceeded(result.job.id, claimed?.leaseToken ?? "missing"); +} + +async function expectOnlyEligibleJob(jobId: string): Promise { + const now = new Date(); + const externalJobs = await prisma.job.findMany({ + where: { + id: { not: jobId }, + OR: [ + { status: "queued" }, + { + status: "pending_retry", + OR: [{ nextRetryAt: null }, { nextRetryAt: { lte: now } }] + } + ] + }, + select: { id: true, status: true, createdAt: true }, + take: 5, + orderBy: [{ createdAt: "asc" }, { id: "asc" }] + }); + + // claimNext 是全局领取;测试只能在确认没有外部 eligible job 时模拟 worker 完成。 + expect(externalJobs, "external eligible jobs would make this API fixture mutate data outside the current runId").toEqual([]); +} + +async function cleanup(): Promise { + await prisma.job.deleteMany({ where: { id: { startsWith: runId } } }); + await prisma.gameProject.deleteMany({ where: { id: { startsWith: runId } } }); +} + +describe("Job HTTP APIs", () => { + let testApp: TestApp | undefined; + + beforeEach(async () => { + await acquireJobTestIsolationLock(); + await cleanup(); + await ensureSeedUsers(prisma); + testApp = await createTestApp(); + }); + + afterEach(async () => { + await testApp?.app.close(); + testApp = undefined; + await cleanup(); + await releaseJobTestIsolationLock(); + }); + + it("GET /jobs/:jobId returns own job state", async () => { + const project = await seedProject(prisma, "own-job", "seed-creator"); + const job = await seedCompletedProjectJob(prisma, "own-job", "seed-creator", project.id); + const token = await login(testApp!, "creator@example.test"); + + const read = await requestJson(testApp!, `/jobs/${job.id}`, { + headers: { authorization: `Bearer ${token}` } + }); + + expect(read.response.status).toBe(200); + expect(read.body).toMatchObject({ + id: job.id, + actorId: "seed-creator", + projectId: project.id, + status: "succeeded", + targetType: "project", + targetId: project.id + }); + }); + + it("GET /jobs/:jobId rejects foreign job access", async () => { + const project = await seedProject(prisma, "foreign-job", "seed-creator-other"); + const job = await seedCompletedProjectJob(prisma, "foreign-job", "seed-creator-other", project.id); + const token = await login(testApp!, "creator@example.test"); + + const denied = await requestJson(testApp!, `/jobs/${job.id}`, { + headers: { authorization: `Bearer ${token}` } + }); + + expect(denied.response.status).toBe(403); + expect(denied.body).toEqual({ + code: "FORBIDDEN", + message: expect.any(String), + requestId: null, + details: expect.anything() + }); + }); + + it("rejects target project/version mismatch from the service layer before enqueue", async () => { + const project = await seedProject(prisma, "mismatch-project", "seed-creator"); + const otherProject = await seedProject(prisma, "mismatch-other-project", "seed-creator"); + const otherVersion = await prisma.$transaction((tx) => seedDraftVersion(tx, otherProject.id, "mismatch-other")); + + await expect( + testApp!.jobApiService.enqueueScopedJobForActor({ + id: `${runId}-mismatch-job`, + actorId: "seed-creator", + projectId: project.id, + type: "noop", + idempotencyKey: "mismatch", + target: { type: "version", id: otherVersion.id }, + payloadJson: { mismatch: true } + }) + ).rejects.toMatchObject({ code: "TARGET_PROJECT_MISMATCH" }); + + expect(testApp!.queue.messages).toHaveLength(0); + await expect(prisma.job.findUnique({ where: { id: `${runId}-mismatch-job` } })).resolves.toBeNull(); + }); + + it("writes job.enqueue_failed audit and keeps stable errorCode when queue enqueue fails", async () => { + await testApp?.app.close(); + const failingQueue = new FailingQueue(); + const moduleRef = await Test.createTestingModule({ + imports: [AppModule] + }) + .overrideProvider(S1_QUEUE_ADAPTER) + .useValue(failingQueue) + .compile(); + const app = moduleRef.createNestApplication(); + await app.init(); + const server = await app.listen(0); + const address = server.address(); + if (address === null || typeof address === "string") throw new Error("Nest test server did not expose a TCP port"); + testApp = { + app, + baseUrl: `http://127.0.0.1:${address.port}`, + jobApiService: moduleRef.get(JobApiService), + queue: new RecordingQueue() + }; + const project = await seedProject(prisma, "queue-failure", "seed-creator"); + const jobId = `${runId}-queue-failure-job`; + + await expect( + testApp.jobApiService.enqueueScopedJobForActor({ + id: jobId, + actorId: "seed-creator", + projectId: project.id, + type: "noop", + idempotencyKey: "queue-failure", + target: { type: "project", id: project.id }, + payloadJson: { ok: true } + }) + ).rejects.toMatchObject({ code: "QUEUE_UNAVAILABLE" }); + + await expect(prisma.job.findUnique({ where: { id: jobId } })).resolves.toMatchObject({ + status: "pending_retry", + errorCode: "QUEUE_ENQUEUE_FAILED" + }); + await expect(prisma.auditLog.findFirst({ where: { targetId: jobId, action: "job.enqueue_failed" } })).resolves.toMatchObject({ + actorId: "seed-creator", + targetType: "Job", + eventJson: expect.objectContaining({ errorCode: "QUEUE_ENQUEUE_FAILED" }) + }); + await expect(prisma.auditLog.count({ where: { targetId: jobId, action: "job.enqueued" } })).resolves.toBe(0); + }); + + it("writes job.enqueued audit only once for the idempotent winner after enqueue succeeds", async () => { + await testApp?.app.close(); + testApp = await createTestApp(new CompletingQueue()); + const project = await seedProject(prisma, "duplicate-success", "seed-creator"); + const firstJobId = `${runId}-duplicate-success-a-job`; + const secondJobId = `${runId}-duplicate-success-b-job`; + + const [first, second] = await Promise.all([ + testApp!.jobApiService.enqueueScopedJobForActor({ + id: firstJobId, + actorId: "seed-creator", + projectId: project.id, + type: "noop", + idempotencyKey: "duplicate-success", + target: { type: "project", id: project.id }, + payloadJson: { attempt: "a" } + }), + testApp!.jobApiService.enqueueScopedJobForActor({ + id: secondJobId, + actorId: "seed-creator", + projectId: project.id, + type: "noop", + idempotencyKey: "duplicate-success", + target: { type: "project", id: project.id }, + payloadJson: { attempt: "b" } + }) + ]); + + expect(second.id).toBe(first.id); + expect(testApp!.queue.messages).toHaveLength(1); + await expect(prisma.auditLog.count({ where: { targetId: first.id, action: "job.enqueued" } })).resolves.toBe(1); + await expect(prisma.auditLog.count({ where: { targetId: first.id, action: "job.enqueue_failed" } })).resolves.toBe(0); + }); +}); + +async function acquireJobTestIsolationLock(): Promise { + // 仅测试隔离:本 spec 的 queue failure 会短暂产生 eligible pending_retry,需与 store claimNext 用例错开。 + lockClient = new pg.Client({ connectionString: databaseUrl }); + await lockClient.connect(); + await lockClient.query("SELECT pg_advisory_lock($1)", [jobTestIsolationLockKey]); +} + +async function releaseJobTestIsolationLock(): Promise { + if (!lockClient) return; + try { + await lockClient.query("SELECT pg_advisory_unlock($1)", [jobTestIsolationLockKey]); + } finally { + await lockClient.end(); + lockClient = undefined; + } +} + +describe("Task 8 queue provider factory", () => { + it("uses memory adapter only when QUEUE_ADAPTER=memory", async () => { + expect(createQueueAdapterFromEnv({ QUEUE_ADAPTER: "memory" })).toBeInstanceOf(InMemoryQueueAdapter); + }); + + it("fails closed when QUEUE_ADAPTER is missing instead of falling back to memory", async () => { + const adapter = createQueueAdapterFromEnv({}); + + expect(adapter).not.toBeInstanceOf(InMemoryQueueAdapter); + await expect(adapter.enqueue({ jobId: "missing-adapter", type: "noop", payload: {} })).rejects.toMatchObject({ + code: "QUEUE_UNAVAILABLE" + }); + }); + + it("fails closed when QUEUE_ADAPTER is unsupported instead of falling back to memory", async () => { + const adapter = createQueueAdapterFromEnv({ QUEUE_ADAPTER: "sidekiq" }); + + expect(adapter).not.toBeInstanceOf(InMemoryQueueAdapter); + await expect(adapter.enqueue({ jobId: "unsupported-adapter", type: "noop", payload: {} })).rejects.toMatchObject({ + code: "QUEUE_UNAVAILABLE" + }); + }); + + it("uses BullMQ when QUEUE_ADAPTER=bullmq and REDIS_URL is present", async () => { + expect(createQueueAdapterFromEnv({ QUEUE_ADAPTER: "bullmq", REDIS_URL: "redis://localhost:6379" })).toBeInstanceOf( + BullMqQueueAdapter + ); + }); + + it("does not silently fallback to memory when QUEUE_ADAPTER=bullmq lacks REDIS_URL", async () => { + const adapter = createQueueAdapterFromEnv({ QUEUE_ADAPTER: "bullmq" }); + + expect(adapter).not.toBeInstanceOf(InMemoryQueueAdapter); + await expect(adapter.enqueue({ jobId: "missing-redis", type: "noop", payload: {} })).rejects.toMatchObject({ + code: "QUEUE_UNAVAILABLE" + }); + }); + + it("closes the wrapped queue adapter when the Nest app closes", async () => { + const closeCountingQueue = new CloseCountingQueue(); + const moduleRef = await Test.createTestingModule({ + providers: [ + { provide: S1_QUEUE_ADAPTER_INNER, useValue: closeCountingQueue }, + { + provide: S1_QUEUE_ADAPTER, + useFactory: (queue: QueueAdapter) => new ManagedQueueAdapter(queue), + inject: [S1_QUEUE_ADAPTER_INNER] + } + ] + }).compile(); + const app = moduleRef.createNestApplication(); + await app.init(); + + await app.close(); + + expect(closeCountingQueue.closeCalls).toBe(1); + }); +}); diff --git a/apps/api/src/modules/jobs/jobs.spec.ts b/apps/api/src/modules/jobs/jobs.spec.ts new file mode 100644 index 00000000..ca3dcd38 --- /dev/null +++ b/apps/api/src/modules/jobs/jobs.spec.ts @@ -0,0 +1,660 @@ +import { readFile } from "node:fs/promises"; +import { PrismaPg } from "@prisma/adapter-pg"; +import pg from "pg"; +import { Prisma, PrismaClient } from "../../generated/prisma/client.js"; +import type { QueueAdapter, QueueMessage } from "../queue/index.js"; +import { StateTransitionService } from "../state-transition/index.js"; +import { + JobExecutionError, + JobExecutionStore, + findJobExecutionBoundaryViolations, + scanJobExecutionBoundary +} from "./index.js"; +import { afterAll, afterEach, beforeEach, describe, expect, it } from "vitest"; + +const databaseUrl = process.env.DATABASE_URL ?? "postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public"; +const adapter = new PrismaPg({ connectionString: databaseUrl }); +const prisma = new PrismaClient({ adapter }); +const runId = `task7-jobs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; +const fixedNow = new Date("2026-06-01T09:00:00.000Z"); +const claimIsolationBase = new Date("2000-01-01T00:00:00.000Z"); +const jobTestIsolationLockKey = 810_008; +let claimIsolationSequence = 0; +let lockClient: pg.Client | undefined; + +type DbClient = Prisma.TransactionClient; + +class RecordingQueue implements QueueAdapter { + readonly messages: QueueMessage[] = []; + readonly observedJobs: Array<{ readonly id: string; readonly status: string }> = []; + private readonly fail: boolean; + private readonly db?: PrismaClient; + + constructor(options: { fail?: boolean; db?: PrismaClient } = {}) { + this.fail = options.fail ?? false; + this.db = options.db; + } + + async enqueue(message: QueueMessage): Promise { + const observed = await this.db?.job.findUnique({ where: { id: message.jobId } }); + if (observed) this.observedJobs.push({ id: observed.id, status: observed.status }); + if (this.fail) throw new Error("QUEUE_DOWN"); + this.messages.push(message); + } + + async process(): Promise { + return undefined; + } + + async close(): Promise { + return undefined; + } +} + +async function seedProjectSet(db: DbClient, suffix: string) { + const actor = await db.user.create({ + data: { + id: `${runId}-${suffix}-actor`, + email: `${runId}-${suffix}-actor@example.test`, + displayName: `${suffix} actor` + } + }); + const otherActor = await db.user.create({ + data: { + id: `${runId}-${suffix}-other-actor`, + email: `${runId}-${suffix}-other-actor@example.test`, + displayName: `${suffix} other actor` + } + }); + const project = await db.gameProject.create({ + data: { + id: `${runId}-${suffix}-project`, + ownerId: actor.id, + slug: `${runId}-${suffix}-project`, + title: `${suffix} project` + } + }); + const otherProject = await db.gameProject.create({ + data: { + id: `${runId}-${suffix}-other-project`, + ownerId: otherActor.id, + slug: `${runId}-${suffix}-other-project`, + title: `${suffix} other project` + } + }); + const versionService = new StateTransitionService({ + db, + blockedAuditDb: db, + harnessGate: { + validateContract: async () => ({ ok: true, reasonCode: null }), + validateTransition: async () => ({ ok: true, reasonCode: null }) + } + }); + const version = await versionService.createDraftVersion({ + id: `${runId}-${suffix}-version`, + projectId: project.id, + versionNumber: 1, + configJson: { suffix } + }); + const otherVersion = await versionService.createDraftVersion({ + id: `${runId}-${suffix}-other-version`, + projectId: otherProject.id, + versionNumber: 1, + configJson: { suffix, other: true } + }); + + return { actor, otherActor, project, otherProject, version, otherVersion }; +} + +function enqueueInput(seed: Awaited>, suffix: string) { + return { + id: `${runId}-${suffix}-job`, + actorId: seed.actor.id, + projectId: seed.project.id, + type: "noop", + idempotencyKey: "same-key", + target: { type: "version" as const, id: seed.version.id }, + payloadJson: { suffix } + }; +} + +async function enqueueJob(store: JobExecutionStore, input: Parameters[0], queue: QueueAdapter) { + return (await store.enqueueScopedJob(input, queue)).job; +} + +async function prepareClaimFixture(jobId: string): Promise { + const createdAt = new Date(claimIsolationBase.getTime() + claimIsolationSequence++); + await prisma.job.update({ where: { id: jobId }, data: { createdAt } }); + await expectNoExternalEligibleJobs(); +} + +async function expectNoExternalEligibleJobs(): Promise { + const externalJobs = await prisma.job.findMany({ + where: { + id: { not: { startsWith: runId } }, + OR: [ + { status: "queued" }, + { + status: "pending_retry", + OR: [{ nextRetryAt: null }, { nextRetryAt: { lte: fixedNow } }] + } + ] + }, + select: { id: true, status: true, createdAt: true }, + take: 5, + orderBy: [{ createdAt: "asc" }, { id: "asc" }] + }); + + // claimNext 的业务语义是全局领取;测试隔离只能检测外部 eligible job,不能把其他 spec/dev 数据改成终态。 + expect(externalJobs, "external eligible jobs would make this claimNext test mutate data outside the current runId").toEqual([]); +} + +describe("JobExecutionStore", () => { + beforeEach(async () => { + await acquireJobTestIsolationLock(); + await cleanupTask7JobRows(); + }); + + afterEach(async () => { + await cleanupTask7JobRows(); + await releaseJobTestIsolationLock(); + }); + + afterAll(async () => { + await prisma.$disconnect(); + }); + + it("scopes idempotency by actor/project/type/target/idempotencyKey", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "idempotency")); + const queue = new RecordingQueue(); + const store = new JobExecutionStore({ db: prisma, now: () => fixedNow }); + + const first = await enqueueJob(store, enqueueInput(seed, "first"), queue); + const duplicate = await enqueueJob( + store, + { ...enqueueInput(seed, "duplicate"), id: `${runId}-idempotency-duplicate-job` }, + queue + ); + const otherCreator = await enqueueJob( + store, + { + ...enqueueInput(seed, "other-creator"), + id: `${runId}-idempotency-other-creator-job`, + actorId: seed.otherActor.id + }, + queue + ); + + expect(duplicate.id).toBe(first.id); + expect(otherCreator.id).not.toBe(first.id); + expect(queue.messages).toHaveLength(2); + }); + + it("rejects enqueueScopedJob when constructed with an outer transaction client", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "tx-enqueue-rejected")); + const queue = new RecordingQueue(); + + await expect( + prisma.$transaction(async (tx) => { + const store = new JobExecutionStore({ db: tx, now: () => fixedNow }); + await store.enqueueScopedJob(enqueueInput(seed, "tx-enqueue-rejected"), queue); + }) + ).rejects.toMatchObject({ code: "JOB_ENQUEUE_REQUIRES_ROOT_CLIENT" }); + + expect(queue.messages).toHaveLength(0); + await expect(prisma.job.findUnique({ where: { id: `${runId}-tx-enqueue-rejected-job` } })).resolves.toBeNull(); + }); + + it("rejects target project mismatch before enqueue and leaves target unchanged when enqueue fails", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "enqueue-failure")); + const store = new JobExecutionStore({ db: prisma, now: () => fixedNow }); + const queue = new RecordingQueue({ fail: true }); + + await expect( + store.enqueueScopedJob( + { + id: `${runId}-mismatch-job`, + actorId: seed.actor.id, + projectId: seed.project.id, + type: "noop", + idempotencyKey: "mismatch", + target: { type: "version", id: seed.otherVersion.id }, + payloadJson: {} + }, + queue + ) + ).rejects.toMatchObject({ code: "TARGET_PROJECT_MISMATCH" }); + expect(queue.messages).toHaveLength(0); + + await expect( + store.enqueueScopedJob( + { + id: `${runId}-failed-enqueue-job`, + actorId: seed.actor.id, + projectId: seed.project.id, + type: "noop", + idempotencyKey: "failed-enqueue", + target: { type: "project", id: seed.project.id }, + payloadJson: {} + }, + queue + ) + ).rejects.toThrow(/QUEUE_DOWN/); + + await expect(prisma.job.findUnique({ where: { id: `${runId}-failed-enqueue-job` } })).resolves.toMatchObject({ + status: "pending_retry", + errorCode: "QUEUE_ENQUEUE_FAILED" + }); + await expect(prisma.gameProject.findUniqueOrThrow({ where: { id: seed.project.id } })).resolves.toMatchObject({ + title: "enqueue-failure project" + }); + }); + + it("concurrent duplicate idempotency requests persist only one job while creator scopes stay isolated", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "concurrent-idempotency")); + const queue = new RecordingQueue(); + const store = new JobExecutionStore({ db: prisma, now: () => fixedNow }); + + const [first, second, isolated] = await Promise.all([ + enqueueJob(store, enqueueInput(seed, "concurrent-a"), queue), + enqueueJob(store, { ...enqueueInput(seed, "concurrent-b"), id: `${runId}-concurrent-b-job` }, queue), + enqueueJob( + store, + { + ...enqueueInput(seed, "concurrent-other"), + id: `${runId}-concurrent-other-job`, + actorId: seed.otherActor.id + }, + queue + ) + ]); + + expect(second.id).toBe(first.id); + expect(isolated.id).not.toBe(first.id); + await expect( + prisma.job.count({ + where: { + projectId: seed.project.id, + type: "noop", + targetScopeKey: `version:${seed.version.id}`, + idempotencyKey: "same-key" + } + }) + ).resolves.toBe(2); + }); + + it("reports created only for the idempotent winner under concurrent duplicate requests", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "winner-outcome-once")); + const queue = new RecordingQueue(); + const store = new JobExecutionStore({ db: prisma, now: () => fixedNow }); + const withDuplicateKey = (id: string) => ({ + ...enqueueInput(seed, "winner-outcome-once"), + id, + idempotencyKey: "winner-outcome-once" + }); + + const [first, second] = await Promise.all([ + store.enqueueScopedJob(withDuplicateKey(`${runId}-winner-outcome-once-a-job`), queue), + store.enqueueScopedJob(withDuplicateKey(`${runId}-winner-outcome-once-b-job`), queue) + ]); + + expect(second.job.id).toBe(first.job.id); + expect([first.created, second.created].filter(Boolean)).toHaveLength(1); + expect([first.enqueued, second.enqueued].filter(Boolean)).toHaveLength(1); + expect(queue.messages).toHaveLength(1); + }); + + it("enqueues after DB commit and marks the job recoverable when enqueue fails", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "enqueue-after-commit")); + const store = new JobExecutionStore({ db: prisma, now: () => fixedNow, retryDelayMs: 15_000 }); + const queue = new RecordingQueue({ fail: true, db: prisma }); + + await expect( + store.enqueueScopedJob( + { + ...enqueueInput(seed, "enqueue-after-commit"), + idempotencyKey: "enqueue-after-commit" + }, + queue + ) + ).rejects.toThrow(/QUEUE_DOWN/); + + expect(queue.observedJobs).toEqual([{ id: `${runId}-enqueue-after-commit-job`, status: "queued" }]); + await expect(prisma.gameProject.findUniqueOrThrow({ where: { id: seed.project.id } })).resolves.toMatchObject({ + title: "enqueue-after-commit project" + }); + await expect(prisma.job.findUniqueOrThrow({ where: { id: `${runId}-enqueue-after-commit-job` } })).resolves.toMatchObject({ + status: "pending_retry", + errorCode: "QUEUE_ENQUEUE_FAILED", + nextRetryAt: new Date(fixedNow.getTime() + 15_000) + }); + }); + + it("claims exactly one eligible job and prevents concurrent workers from claiming the same row", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "claim")); + const queue = new RecordingQueue(); + const store = new JobExecutionStore({ db: prisma, now: () => fixedNow }); + const job = await enqueueJob(store, enqueueInput(seed, "claim"), queue); + await prepareClaimFixture(job.id); + + const [first, second] = await Promise.all([store.claimNext("worker-a", fixedNow), store.claimNext("worker-b", fixedNow)]); + const claimed = [first, second].filter((value) => value !== null); + + expect(claimed).toHaveLength(1); + expect(claimed[0]).toMatchObject({ id: job.id, status: "running", leasedBy: expect.stringMatching(/^worker-/) }); + expect(claimed[0]?.leaseToken).toEqual(expect.any(String)); + await expect(prisma.job.findUniqueOrThrow({ where: { id: job.id } })).resolves.toMatchObject({ + status: "running", + lockVersion: 1 + }); + }); + + it("rejects stale completion after lease/version changes", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "stale-complete")); + const store = new JobExecutionStore({ db: prisma, now: () => fixedNow, retryDelayMs: 1000 }); + const job = await enqueueJob(store, enqueueInput(seed, "stale-complete"), new RecordingQueue()); + await prepareClaimFixture(job.id); + const claimed = await store.claimNext("worker-a", fixedNow); + + expect(claimed?.id).toBe(job.id); + await store.markTimedOut(job.id, new Date(fixedNow.getTime() + 31_000), "JOB_TIMEOUT"); + + await expect(store.markSucceeded(job.id, claimed?.leaseToken ?? "missing")).rejects.toMatchObject({ + code: "STALE_JOB_LEASE" + }); + }); + + it("ensures API cancel and worker completion cannot both win", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "cancel-complete")); + const store = new JobExecutionStore({ db: prisma, now: () => fixedNow }); + const queued = await enqueueJob(store, enqueueInput(seed, "cancel-first"), new RecordingQueue()); + + await expect(store.cancelQueued(queued.id, seed.actor.id)).resolves.toMatchObject({ status: "canceled" }); + await expect(prisma.job.findUniqueOrThrow({ where: { id: queued.id } })).resolves.toMatchObject({ status: "canceled" }); + + const running = await enqueueJob( + store, + { ...enqueueInput(seed, "complete-first"), id: `${runId}-complete-first-job`, idempotencyKey: "complete-first" }, + new RecordingQueue() + ); + await prepareClaimFixture(running.id); + const claimed = await store.claimNext("worker-b", fixedNow); + expect(claimed?.id).toBe(running.id); + + await expect(store.cancelQueued(running.id, seed.actor.id)).rejects.toMatchObject({ + code: "JOB_CANCEL_NOT_ALLOWED" + }); + await expect(store.markSucceeded(running.id, claimed?.leaseToken ?? "missing")).resolves.toMatchObject({ + status: "succeeded" + }); + }); + + it("marks timeout and retry outcomes with attempts, nextRetryAt, and errorCode", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "retry-timeout")); + const store = new JobExecutionStore({ db: prisma, now: () => fixedNow, retryDelayMs: 60_000 }); + + const retryJob = await enqueueJob( + store, + { ...enqueueInput(seed, "retry"), idempotencyKey: "retry", maxAttempts: 2 }, + new RecordingQueue() + ); + await prepareClaimFixture(retryJob.id); + const retryClaim = await store.claimNext("worker-retry", fixedNow); + expect(retryClaim?.id).toBe(retryJob.id); + await expect(store.markFailedOrRetry(retryJob.id, retryClaim?.leaseToken ?? "missing", "WORKER_FAILED")).resolves.toMatchObject({ + status: "pending_retry", + attempts: 1, + errorCode: "WORKER_FAILED", + nextRetryAt: new Date(fixedNow.getTime() + 60_000) + }); + + const timeoutJob = await enqueueJob( + store, + { ...enqueueInput(seed, "timeout"), id: `${runId}-timeout-job`, idempotencyKey: "timeout", maxAttempts: 1 }, + new RecordingQueue() + ); + await prepareClaimFixture(timeoutJob.id); + const timeoutClaim = await store.claimNext("worker-timeout", fixedNow); + expect(timeoutClaim?.id).toBe(timeoutJob.id); + await expect(store.markTimedOut(timeoutJob.id, new Date(fixedNow.getTime() + 31_000), "JOB_TIMEOUT")).resolves.toMatchObject({ + status: "failed", + attempts: 1, + errorCode: "JOB_TIMEOUT", + nextRetryAt: null + }); + }); + + it("marks jobs timed out by persisted timeoutAt even when lease has not expired", async () => { + const seed = await prisma.$transaction((tx) => seedProjectSet(tx, "persisted-timeout")); + const store = new JobExecutionStore({ db: prisma, now: () => fixedNow, leaseMs: 60_000, retryDelayMs: 10_000 }); + const job = await enqueueJob( + store, + { + ...enqueueInput(seed, "persisted-timeout"), + timeoutMs: -1, + maxAttempts: 2 + }, + new RecordingQueue() + ); + await prepareClaimFixture(job.id); + const claim = await store.claimNext("worker-persisted-timeout", fixedNow); + + expect(claim).toMatchObject({ + id: job.id, + status: "running", + leaseExpiresAt: new Date(fixedNow.getTime() + 60_000) + }); + await expect(store.markTimedOut(job.id, fixedNow, "JOB_TIMEOUT")).resolves.toMatchObject({ + status: "pending_retry", + attempts: 1, + errorCode: "JOB_TIMEOUT", + nextRetryAt: new Date(fixedNow.getTime() + 10_000) + }); + }); + + it("keeps Job runtime field writes inside JobExecutionStore", async () => { + expect( + findJobExecutionBoundaryViolations([ + { + path: "apps/api/src/modules/projects/project.service.ts", + content: "await db.job.update({ where: { id }, data: { status: 'failed' } });" + }, + { + path: "apps/api/src/modules/projects/comment-paren-job.service.ts", + content: ` +await db.job.update({ // ) + where: { id }, + data: { status: "failed" } +}); +` + }, + { + path: "apps/api/src/modules/jobs/index.ts", + content: + "export class JobExecutionStore { async ok(db: Prisma.TransactionClient) { await db.job.update({ where: { id }, data: { status: 'failed', attempts: { increment: 1 } } }); } }" + }, + { + path: "apps/api/src/modules/jobs/index.ts", + content: ` +export class JobExecutionStore { + async ok(db: Prisma.TransactionClient): Promise { + await db.job.update({ where: { id: "ok" }, data: { status: "running" } }); + } +} + +export class JobApiService { + async bad(db: Prisma.TransactionClient): Promise { + await db.job.update({ where: { id: "bad" }, data: { status: "failed" } }); + } +} +` + }, + { + path: "apps/api/src/modules/jobs/bad.ts", + content: + "await db.job.create({ data: { projectId, actorId, status: 'queued', attempts: 0, nextRetryAt: null } });" + }, + { + path: "apps/api/src/modules/projects/quoted-job.service.ts", + content: + "await db.job.update({ where: { id }, data: { \"status\": \"failed\", 'attempts': 1, [`nextRetryAt`]: null } });" + }, + { + path: "apps/api/src/modules/projects/lease-token-job.service.ts", + content: 'await db.job.update({ where: { id }, data: { leaseToken: "stolen" } });' + }, + { + path: "apps/api/src/modules/projects/timeout-at-job.service.ts", + content: "await db.job.update({ where: { id }, data: { timeoutAt: new Date() } });" + }, + { + path: "apps/api/src/modules/projects/computed-job.service.ts", + content: 'const field = "status"; await db.job.update({ where: { id }, data: { [field]: "failed" } });' + }, + { + path: "apps/api/src/modules/projects/variable-job.service.ts", + content: 'const data = { status: "failed" }; await db.job.update({ where: { id }, data });' + }, + { + path: "apps/api/src/modules/projects/spread-job.service.ts", + content: 'const patch = { attempts: 1 }; await db.job.update({ where: { id }, data: { ...patch } });' + }, + { + path: "apps/api/src/modules/projects/raw-status-job.service.ts", + content: `await db.$executeRawUnsafe("UPDATE \\"Job\\" SET \\"status\\" = 'failed' WHERE id = $1", id);` + }, + { + path: "apps/api/src/modules/projects/raw-comment-paren-job.service.ts", + content: ` +await db.$executeRawUnsafe( // ) + "UPDATE \\"Job\\" SET \\"status\\" = 'failed' WHERE id = $1", + id +); +` + }, + { + path: "apps/api/src/modules/projects/raw-attempts-job.service.ts", + content: 'await db.$executeRawUnsafe("UPDATE Job SET attempts = attempts + 1 WHERE id = $1", id);' + }, + { + path: "apps/api/src/modules/projects/raw-next-retry-job.service.ts", + content: 'await db.$executeRawUnsafe("UPDATE \\"Job\\" SET \\"nextRetryAt\\" = NULL WHERE id = $1", id);' + }, + { + path: "apps/api/src/modules/projects/raw-insert-status-job.service.ts", + content: 'await db.$executeRawUnsafe("INSERT INTO \\"Job\\" (\\"id\\", \\"status\\") VALUES ($1, \'queued\')", id);' + }, + { + path: "apps/api/src/modules/projects/raw-lease-job.service.ts", + content: + 'await db.$executeRawUnsafe("UPDATE \\"Job\\" SET \\"leaseToken\\" = $1, \\"lockVersion\\" = \\"lockVersion\\" + 1 WHERE id = $2", token, id);' + }, + { + path: "apps/api/src/modules/projects/raw-timeout-job.service.ts", + content: 'await db.$executeRawUnsafe("INSERT INTO Job (id, timeoutAt) VALUES ($1, NOW())", id);' + } + ]) + ).toEqual([ + { + path: "apps/api/src/modules/projects/project.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/comment-paren-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/jobs/index.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/jobs/bad.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/quoted-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/lease-token-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/timeout-at-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/computed-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/variable-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/spread-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/raw-status-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/raw-comment-paren-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/raw-attempts-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/raw-next-retry-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/raw-insert-status-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/raw-lease-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + }, + { + path: "apps/api/src/modules/projects/raw-timeout-job.service.ts", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE" + } + ]); + + await expect(scanJobExecutionBoundary(process.cwd())).resolves.toEqual([]); + }); + + it("does not expose pre-enqueue mutation hooks from the Task 8 job runtime", async () => { + const runtime = await readFile(new URL("./index.ts", import.meta.url), "utf8"); + + expect(runtime).not.toMatch(/\bonJobCreated\b/); + expect(runtime).not.toMatch(/\bmutateTarget\b/); + }); +}); + +async function cleanupTask7JobRows(): Promise { + await prisma.job.deleteMany({ where: { id: { startsWith: runId } } }); + await prisma.gameProject.deleteMany({ where: { id: { startsWith: runId } } }); + await prisma.user.deleteMany({ where: { id: { startsWith: runId } } }); +} + +async function acquireJobTestIsolationLock(): Promise { + // 仅测试隔离:claimNext 是全局领取,跨 spec 并发时用 DB advisory lock 缩小测试窗口,不改写外部 Job。 + lockClient = new pg.Client({ connectionString: databaseUrl }); + await lockClient.connect(); + await lockClient.query("SELECT pg_advisory_lock($1)", [jobTestIsolationLockKey]); +} + +async function releaseJobTestIsolationLock(): Promise { + if (!lockClient) return; + try { + await lockClient.query("SELECT pg_advisory_unlock($1)", [jobTestIsolationLockKey]); + } finally { + await lockClient.end(); + lockClient = undefined; + } +} diff --git a/apps/api/src/modules/projects/api-runtime.spec.ts b/apps/api/src/modules/projects/api-runtime.spec.ts new file mode 100644 index 00000000..00c50c14 --- /dev/null +++ b/apps/api/src/modules/projects/api-runtime.spec.ts @@ -0,0 +1,49 @@ +import { Prisma } from "../../generated/prisma/client.js"; +import { JobExecutionError } from "../jobs/index.js"; +import { QueueUnavailableError } from "../queue/index.js"; +import { StateTransitionDomainError } from "../state-transition/index.js"; +import { mapExceptionToHttpError } from "./api-runtime.js"; +import { describe, expect, it } from "vitest"; + +describe("Structured API exception mapping", () => { + it("maps Prisma unique and missing-row errors to stable structured statuses", () => { + const unique = new Prisma.PrismaClientKnownRequestError("Unique constraint failed", { + code: "P2002", + clientVersion: "task8-test", + meta: { target: ["slug"] } + }); + const missing = new Prisma.PrismaClientKnownRequestError("Record not found", { + code: "P2025", + clientVersion: "task8-test" + }); + + expect(mapExceptionToHttpError(unique, "req-1")).toEqual({ + status: 409, + body: { code: "CONFLICT", message: expect.any(String), requestId: "req-1", details: expect.anything() } + }); + expect(mapExceptionToHttpError(missing, "req-2")).toEqual({ + status: 404, + body: { code: "NOT_FOUND", message: expect.any(String), requestId: "req-2", details: expect.anything() } + }); + }); + + it("maps queue, job, and state-transition domain errors without leaking raw 500s", () => { + expect(mapExceptionToHttpError(new QueueUnavailableError("redis unavailable"), null)).toEqual({ + status: 503, + body: { code: "QUEUE_UNAVAILABLE", message: expect.any(String), requestId: null, details: expect.anything() } + }); + expect(mapExceptionToHttpError(new JobExecutionError("TARGET_PROJECT_MISMATCH"), null)).toEqual({ + status: 422, + body: { code: "TARGET_PROJECT_MISMATCH", message: expect.any(String), requestId: null, details: expect.anything() } + }); + expect(mapExceptionToHttpError(new StateTransitionDomainError("HARNESS_INVALID_OUTPUT"), null)).toEqual({ + status: 422, + body: { + code: "STATE_TRANSITION_REJECTED", + message: expect.any(String), + requestId: null, + details: expect.objectContaining({ reasonCode: "HARNESS_INVALID_OUTPUT" }) + } + }); + }); +}); diff --git a/apps/api/src/modules/projects/api-runtime.ts b/apps/api/src/modules/projects/api-runtime.ts new file mode 100644 index 00000000..4cfabe9b --- /dev/null +++ b/apps/api/src/modules/projects/api-runtime.ts @@ -0,0 +1,182 @@ +import { Catch, Global, HttpException, HttpStatus, Injectable, Module, type ArgumentsHost, type ExceptionFilter } from "@nestjs/common"; +import { APP_FILTER } from "@nestjs/core"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { Prisma, PrismaClient } from "../../generated/prisma/client.js"; + +export type StructuredApiError = { + readonly code: string; + readonly message: string; + readonly requestId: string | null; + readonly details: unknown; +}; + +type HttpRequestLike = { + readonly headers?: { + readonly "x-request-id"?: string | readonly string[]; + }; +}; + +type HttpResponseLike = { + status(statusCode: number): { + json(body: StructuredApiError): void; + }; +}; + +export type MappedHttpError = { + readonly status: number; + readonly body: StructuredApiError; +}; + +const databaseUrl = process.env.DATABASE_URL ?? "postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public"; + +export function apiError(code: string, message: string, details: unknown = {}): StructuredApiError { + return { + code, + message, + requestId: null, + details: details ?? {} + }; +} + +function requestIdFrom(request: HttpRequestLike): string | null { + const value = request.headers?.["x-request-id"]; + if (typeof value === "string" && value.trim() !== "") return value; + if (Array.isArray(value) && typeof value[0] === "string" && value[0].trim() !== "") return value[0]; + return null; +} + +function isNamedDomainError(exception: unknown, name: string): boolean { + return exception instanceof Error && exception.name === name; +} + +function errorCodeOf(exception: unknown): string | undefined { + if (typeof exception === "object" && exception !== null && "code" in exception && typeof exception.code === "string") { + return exception.code; + } + return undefined; +} + +function reasonCodeOf(exception: unknown): string | undefined { + if (typeof exception === "object" && exception !== null && "reasonCode" in exception && typeof exception.reasonCode === "string") { + return exception.reasonCode; + } + return undefined; +} + +function mappedBody(code: string, message: string, requestId: string | null, details: unknown = {}): StructuredApiError { + return { code, message, requestId, details: details ?? {} }; +} + +function mapJobExecutionError(exception: unknown, requestId: string | null): MappedHttpError | null { + if (!isNamedDomainError(exception, "JobExecutionError")) return null; + + const code = errorCodeOf(exception) ?? "JOB_EXECUTION_ERROR"; + const status = + code === "TARGET_NOT_FOUND" || code === "JOB_NOT_FOUND" + ? HttpStatus.NOT_FOUND + : code === "TARGET_PROJECT_MISMATCH" + ? HttpStatus.UNPROCESSABLE_ENTITY + : code === "JOB_ENQUEUE_REQUIRES_ROOT_CLIENT" + ? HttpStatus.INTERNAL_SERVER_ERROR + : HttpStatus.CONFLICT; + return { + status, + body: mappedBody(code, "Job execution boundary rejected the request", requestId, { code }) + }; +} + +export function mapExceptionToHttpError(exception: unknown, requestId: string | null): MappedHttpError { + if (exception instanceof HttpException) { + const response = exception.getResponse(); + if (typeof response === "object" && response !== null && "code" in response) { + const body = response as Partial; + return { + status: exception.getStatus(), + body: { + code: typeof body.code === "string" ? body.code : "HTTP_ERROR", + message: typeof body.message === "string" ? body.message : exception.message, + requestId, + details: body.details ?? {} + } + }; + } + + return { + status: exception.getStatus(), + body: mappedBody(exception.getStatus() === HttpStatus.NOT_FOUND ? "NOT_FOUND" : "HTTP_ERROR", exception.message, requestId) + }; + } + + if (exception instanceof Prisma.PrismaClientKnownRequestError) { + if (exception.code === "P2002") { + return { + status: HttpStatus.CONFLICT, + body: mappedBody("CONFLICT", "Unique constraint conflict", requestId, { prismaCode: exception.code, meta: exception.meta }) + }; + } + if (exception.code === "P2025") { + return { + status: HttpStatus.NOT_FOUND, + body: mappedBody("NOT_FOUND", "Requested record was not found", requestId, { prismaCode: exception.code }) + }; + } + } + + if (isNamedDomainError(exception, "QueueUnavailableError") || errorCodeOf(exception) === "QUEUE_UNAVAILABLE") { + return { + status: HttpStatus.SERVICE_UNAVAILABLE, + body: mappedBody("QUEUE_UNAVAILABLE", "Queue is unavailable", requestId, { queue: true }) + }; + } + + const jobError = mapJobExecutionError(exception, requestId); + if (jobError) return jobError; + + if (isNamedDomainError(exception, "StateTransitionDomainError")) { + const reasonCode = reasonCodeOf(exception) ?? "HARNESS_INVALID_OUTPUT"; + return { + status: HttpStatus.UNPROCESSABLE_ENTITY, + body: mappedBody("STATE_TRANSITION_REJECTED", "State transition rejected by harness", requestId, { reasonCode }) + }; + } + + return { + status: HttpStatus.INTERNAL_SERVER_ERROR, + body: mappedBody("INTERNAL_ERROR", "Internal server error", requestId) + }; +} + +@Catch() +export class StructuredApiExceptionFilter implements ExceptionFilter { + catch(exception: unknown, host: ArgumentsHost): void { + const http = host.switchToHttp(); + const request = http.getRequest(); + const response = http.getResponse(); + const mapped = mapExceptionToHttpError(exception, requestIdFrom(request)); + response.status(mapped.status).json(mapped.body); + } +} + +@Injectable() +export class S1PrismaClient extends PrismaClient { + constructor() { + super({ adapter: new PrismaPg({ connectionString: databaseUrl }) }); + } + + async onModuleDestroy(): Promise { + await this.$disconnect(); + } +} + +@Global() +@Module({ + providers: [ + S1PrismaClient, + { + provide: APP_FILTER, + useClass: StructuredApiExceptionFilter + } + ], + exports: [S1PrismaClient] +}) +export class S1ApiRuntimeModule {} diff --git a/apps/api/src/modules/projects/index.ts b/apps/api/src/modules/projects/index.ts new file mode 100644 index 00000000..c5b29a98 --- /dev/null +++ b/apps/api/src/modules/projects/index.ts @@ -0,0 +1,284 @@ +import { randomUUID } from "node:crypto"; +import { + BadRequestException, + Body, + Controller, + ForbiddenException, + Get, + Injectable, + Module, + NotFoundException, + Param, + Post, + Req, + UseGuards +} from "@nestjs/common"; +import { Prisma, type GameProject, type GameVersion } from "../../generated/prisma/client.js"; +import { AuthGuard, AuthModule, type AuthActor } from "../auth/index.js"; +import { AuditService } from "../audit/index.js"; +import { canReadReviewFoundationData, creatorOwnsResource, hasRole } from "../rbac/index.js"; +import { StateTransitionService } from "../state-transition/index.js"; +import { apiError, S1ApiRuntimeModule, S1PrismaClient } from "./api-runtime.js"; + +type RequestWithActor = { + readonly actor: AuthActor; +}; + +type CreateProjectBody = { + readonly title?: unknown; + readonly slug?: unknown; +}; + +type CreateVersionBody = { + readonly configJson?: unknown; +}; + +export type ProjectDto = { + readonly id: string; + readonly ownerId: string; + readonly slug: string; + readonly title: string; + readonly status: string; + readonly createdAt: string; + readonly updatedAt: string; +}; + +export type VersionDto = { + readonly id: string; + readonly projectId: string; + readonly versionNumber: number; + readonly status: string; + readonly configJson: unknown; + readonly createdAt: string; + readonly updatedAt: string; +}; + +function projectDto(project: GameProject): ProjectDto { + return { + id: project.id, + ownerId: project.ownerId, + slug: project.slug, + title: project.title, + status: project.status, + createdAt: project.createdAt.toISOString(), + updatedAt: project.updatedAt.toISOString() + }; +} + +function versionDto(version: GameVersion): VersionDto { + return { + id: version.id, + projectId: version.projectId, + versionNumber: version.versionNumber, + status: version.status, + configJson: version.configJson, + createdAt: version.createdAt.toISOString(), + updatedAt: version.updatedAt.toISOString() + }; +} + +function requireNonEmptyString(value: unknown, field: string): string { + if (typeof value !== "string" || value.trim() === "") { + throw new BadRequestException(apiError("INVALID_REQUEST", `${field} must be a non-empty string`, { field })); + } + return value.trim(); +} + +function optionalSafeSlug(value: unknown, fallbackId: string): string { + if (value === undefined) return `project-${fallbackId.slice(0, 8)}`; + const slug = requireNonEmptyString(value, "slug"); + if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,80}$/.test(slug)) { + throw new BadRequestException(apiError("INVALID_REQUEST", "slug contains unsafe characters", { field: "slug" })); + } + return slug; +} + +function inputJson(value: unknown): Prisma.InputJsonValue { + if (value === undefined) return {}; + if (value === null || typeof value !== "object" || Array.isArray(value)) { + throw new BadRequestException(apiError("INVALID_REQUEST", "configJson must be a JSON object", { field: "configJson" })); + } + return value as Prisma.InputJsonObject; +} + +@Injectable() +export class ProjectsApiService { + constructor(private readonly db: S1PrismaClient) {} + + async createProject(actor: AuthActor, body: CreateProjectBody): Promise { + if (!hasRole(actor, "creator")) { + // S1 只有 creator 可以创建项目;operator/admin 在 Task 8 仅有 foundation read,不是管理 CRUD。 + throw new ForbiddenException(apiError("FORBIDDEN", "Creator role is required to create a project", { requiredRole: "creator" })); + } + + const title = requireNonEmptyString(body.title, "title"); + const id = randomUUID(); + const slug = optionalSafeSlug(body.slug, id); + + const project = await this.db.$transaction(async (tx) => { + await this.ensureActorUser(tx, actor); + const created = await tx.gameProject.create({ + data: { + id, + ownerId: actor.id, + slug, + title + } + }); + + await new AuditService({ db: tx }).append({ + id: randomUUID(), + actorId: actor.id, + action: "project.created", + targetType: "GameProject", + targetId: created.id, + eventJson: { + // 项目创建改变 ownership 边界,审计记录只写事实,不包含可变业务状态。 + ownerId: actor.id, + slug: created.slug + } + }); + + return created; + }); + + return projectDto(project); + } + + async listProjects(actor: AuthActor): Promise { + const where = canReadReviewFoundationData(actor, "project") ? {} : { ownerId: actor.id }; + const projects = await this.db.gameProject.findMany({ + where, + orderBy: [{ createdAt: "asc" }, { id: "asc" }] + }); + return projects.map(projectDto); + } + + async getProject(actor: AuthActor, projectId: string): Promise { + const project = await this.requireReadableProject(actor, projectId, "project"); + return projectDto(project); + } + + async createDraftVersion(actor: AuthActor, projectId: string, body: CreateVersionBody): Promise { + const project = await this.requireReadableProject(actor, projectId, "project"); + if (!creatorOwnsResource(actor, project)) { + // 版本创建是 owner 写路径;operator/admin 在 S1 只有 foundation read,没有管理写权限。 + throw new ForbiddenException(apiError("FORBIDDEN", "Only the owning creator can create a draft version", { projectId })); + } + + const configJson = inputJson(body.configJson); + const version = await this.db.$transaction(async (tx) => { + const latest = await tx.gameVersion.findFirst({ + where: { projectId }, + orderBy: { versionNumber: "desc" } + }); + const service = new StateTransitionService({ + db: tx, + blockedAuditDb: tx, + harnessGate: { + validateContract: async () => ({ ok: true, reasonCode: null }), + validateTransition: async () => ({ ok: true, reasonCode: null }) + } + }); + const created = await service.createDraftVersion({ + id: randomUUID(), + projectId, + versionNumber: (latest?.versionNumber ?? 0) + 1, + configJson + }); + + await new AuditService({ db: tx }).append({ + id: randomUUID(), + actorId: actor.id, + action: "version.created", + targetType: "GameVersion", + targetId: created.id, + eventJson: { + // draft 状态写入必须走 StateTransitionService;审计只记录边界调用事实。 + projectId, + versionNumber: created.versionNumber, + status: created.status + } + }); + + return created; + }); + + return versionDto(version); + } + + async listVersions(actor: AuthActor, projectId: string): Promise { + await this.requireReadableProject(actor, projectId, "version"); + const versions = await this.db.gameVersion.findMany({ + where: { projectId }, + orderBy: [{ versionNumber: "asc" }, { id: "asc" }] + }); + return versions.map(versionDto); + } + + private async requireReadableProject( + actor: AuthActor, + projectId: string, + category: "project" | "version" + ): Promise { + const project = await this.db.gameProject.findUnique({ where: { id: projectId } }); + if (!project) throw new NotFoundException(apiError("NOT_FOUND", "Project not found", { projectId })); + if (creatorOwnsResource(actor, project) || canReadReviewFoundationData(actor, category)) return project; + throw new ForbiddenException(apiError("FORBIDDEN", "Actor cannot access this project", { projectId })); + } + + private async ensureActorUser(tx: Prisma.TransactionClient, actor: AuthActor): Promise { + await tx.user.upsert({ + where: { id: actor.id }, + update: {}, + create: { + id: actor.id, + email: actor.email, + displayName: actor.displayName + } + }); + } +} + +@Controller() +@UseGuards(AuthGuard) +export class ProjectsController { + constructor(private readonly service: ProjectsApiService) {} + + @Post("projects") + createProject(@Req() request: RequestWithActor, @Body() body: CreateProjectBody): Promise { + return this.service.createProject(request.actor, body); + } + + @Get("projects") + listProjects(@Req() request: RequestWithActor): Promise { + return this.service.listProjects(request.actor); + } + + @Get("projects/:projectId") + getProject(@Req() request: RequestWithActor, @Param("projectId") projectId: string): Promise { + return this.service.getProject(request.actor, projectId); + } + + @Post("projects/:projectId/versions") + createDraftVersion( + @Req() request: RequestWithActor, + @Param("projectId") projectId: string, + @Body() body: CreateVersionBody + ): Promise { + return this.service.createDraftVersion(request.actor, projectId, body); + } + + @Get("projects/:projectId/versions") + listVersions(@Req() request: RequestWithActor, @Param("projectId") projectId: string): Promise { + return this.service.listVersions(request.actor, projectId); + } +} + +@Module({ + imports: [S1ApiRuntimeModule, AuthModule], + controllers: [ProjectsController], + providers: [ProjectsApiService], + exports: [ProjectsApiService] +}) +export class ProjectsModule {} diff --git a/apps/api/src/modules/projects/projects.api.spec.ts b/apps/api/src/modules/projects/projects.api.spec.ts new file mode 100644 index 00000000..84c76a28 --- /dev/null +++ b/apps/api/src/modules/projects/projects.api.spec.ts @@ -0,0 +1,323 @@ +import { type INestApplication } from "@nestjs/common"; +import { Test } from "@nestjs/testing"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { AppModule } from "../../app.module.js"; +import { Prisma, PrismaClient } from "../../generated/prisma/client.js"; +import { StateTransitionService } from "../state-transition/index.js"; + +const databaseUrl = process.env.DATABASE_URL ?? "postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public"; +const adapter = new PrismaPg({ connectionString: databaseUrl }); +const prisma = new PrismaClient({ adapter }); +const runId = `task8-projects-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; + +type DbClient = Prisma.TransactionClient; + +type TestApp = { + readonly app: INestApplication; + readonly baseUrl: string; +}; + +async function createTestApp(): Promise { + const moduleRef = await Test.createTestingModule({ + imports: [AppModule] + }).compile(); + const app = moduleRef.createNestApplication(); + await app.init(); + const server = await app.listen(0); + const address = server.address(); + if (address === null || typeof address === "string") throw new Error("Nest test server did not expose a TCP port"); + return { app, baseUrl: `http://127.0.0.1:${address.port}` }; +} + +async function requestJson(testApp: TestApp, path: string, init: RequestInit = {}) { + const response = await fetch(`${testApp.baseUrl}${path}`, { + ...init, + headers: { + "content-type": "application/json", + ...init.headers + } + }); + const body = (await response.json().catch(() => null)) as unknown; + return { response, body }; +} + +async function login(testApp: TestApp, email: string): Promise { + const response = await requestJson(testApp, "/auth/login", { + method: "POST", + body: JSON.stringify({ email }) + }); + expect(response.response.status).toBe(201); + return (response.body as { token: string }).token; +} + +async function ensureSeedUsers(db: DbClient): Promise { + await db.user.upsert({ + where: { id: "seed-creator" }, + update: {}, + create: { id: "seed-creator", email: "creator@example.test", displayName: "Seed Creator" } + }); + await db.user.upsert({ + where: { id: "seed-creator-other" }, + update: {}, + create: { id: "seed-creator-other", email: "creator-other@example.test", displayName: "Seed Other Creator" } + }); + await db.user.upsert({ + where: { id: "seed-operator" }, + update: {}, + create: { id: "seed-operator", email: "operator@example.test", displayName: "Seed Operator" } + }); + await db.user.upsert({ + where: { id: "seed-admin" }, + update: {}, + create: { id: "seed-admin", email: "admin@example.test", displayName: "Seed Admin" } + }); + await db.user.upsert({ + where: { id: "seed-player" }, + update: {}, + create: { id: "seed-player", email: "player@example.test", displayName: "Seed Player" } + }); +} + +async function seedProject(db: DbClient, suffix: string, ownerId = "seed-creator") { + return db.gameProject.create({ + data: { + id: `${runId}-${suffix}-project`, + ownerId, + slug: `${runId}-${suffix}`, + title: `${suffix} project` + } + }); +} + +async function seedDraftVersion(db: DbClient, projectId: string, suffix: string, versionNumber = 1) { + const service = new StateTransitionService({ + db, + blockedAuditDb: db, + harnessGate: { + validateContract: async () => ({ ok: true, reasonCode: null }), + validateTransition: async () => ({ ok: true, reasonCode: null }) + } + }); + return service.createDraftVersion({ + id: `${runId}-${suffix}-version`, + projectId, + versionNumber, + configJson: { suffix } + }); +} + +async function cleanup(): Promise { + await prisma.job.deleteMany({ where: { id: { startsWith: runId } } }); + await prisma.gameProject.deleteMany({ where: { OR: [{ id: { startsWith: runId } }, { slug: { startsWith: runId } }] } }); +} + +describe("Project and version HTTP APIs", () => { + let testApp: TestApp | undefined; + + beforeEach(async () => { + await cleanup(); + await ensureSeedUsers(prisma); + testApp = await createTestApp(); + }); + + afterEach(async () => { + await testApp?.app.close(); + testApp = undefined; + await cleanup(); + }); + + it("POST /projects creates a creator-owned project and appends an audit fact", async () => { + const token = await login(testApp!, "creator@example.test"); + + const created = await requestJson(testApp!, "/projects", { + method: "POST", + headers: { authorization: `Bearer ${token}` }, + body: JSON.stringify({ title: "Task 8 Project", slug: `${runId}-created` }) + }); + + expect(created.response.status).toBe(201); + expect(created.body).toMatchObject({ + slug: `${runId}-created`, + title: "Task 8 Project", + ownerId: "seed-creator", + status: "active" + }); + + const projectId = (created.body as { id: string }).id; + await expect(prisma.gameProject.findUnique({ where: { id: projectId } })).resolves.toMatchObject({ + ownerId: "seed-creator" + }); + await expect(prisma.auditLog.findFirst({ where: { targetId: projectId, action: "project.created" } })).resolves.toMatchObject({ + actorId: "seed-creator", + targetType: "GameProject" + }); + }); + + it.each([ + ["operator", "operator@example.test", "seed-operator"], + ["admin", "admin@example.test", "seed-admin"], + ["player", "player@example.test", "seed-player"] + ])("POST /projects rejects authenticated non-creator %s without project or audit mutation", async (_label, email, actorId) => { + const token = await login(testApp!, email); + const slug = `${runId}-non-creator-${actorId}`; + const beforeAuditCount = await prisma.auditLog.count({ + where: { actorId, action: "project.created", targetType: "GameProject" } + }); + + const denied = await requestJson(testApp!, "/projects", { + method: "POST", + headers: { authorization: `Bearer ${token}` }, + body: JSON.stringify({ title: "Blocked Project", slug }) + }); + + expect(denied.response.status).toBe(403); + expect(denied.body).toEqual({ + code: "FORBIDDEN", + message: expect.any(String), + requestId: null, + details: expect.anything() + }); + await expect(prisma.gameProject.count({ where: { slug } })).resolves.toBe(0); + await expect( + prisma.auditLog.count({ where: { actorId, action: "project.created", targetType: "GameProject" } }) + ).resolves.toBe(beforeAuditCount); + }); + + it("POST /projects rejects anonymous callers with structured 403 before mutation", async () => { + const slug = `${runId}-anonymous-create`; + const beforeAuditCount = await prisma.auditLog.count({ where: { action: "project.created", targetType: "GameProject" } }); + + const denied = await requestJson(testApp!, "/projects", { + method: "POST", + body: JSON.stringify({ title: "Blocked Anonymous Project", slug }) + }); + + expect(denied.response.status).toBe(403); + expect(denied.body).toEqual({ + code: "FORBIDDEN", + message: expect.any(String), + requestId: null, + details: expect.anything() + }); + await expect(prisma.gameProject.count({ where: { slug } })).resolves.toBe(0); + await expect(prisma.auditLog.count({ where: { action: "project.created", targetType: "GameProject" } })).resolves.toBe( + beforeAuditCount + ); + }); + + it("GET /projects returns only owned projects for creators", async () => { + await seedProject(prisma, "owned", "seed-creator"); + await seedProject(prisma, "foreign", "seed-creator-other"); + const token = await login(testApp!, "creator@example.test"); + + const listed = await requestJson(testApp!, "/projects", { + headers: { authorization: `Bearer ${token}` } + }); + + expect(listed.response.status).toBe(200); + const projects = listed.body as Array<{ id: string; ownerId: string }>; + expect(projects).toContainEqual(expect.objectContaining({ id: `${runId}-owned-project`, ownerId: "seed-creator" })); + expect(projects).not.toContainEqual(expect.objectContaining({ id: `${runId}-foreign-project` })); + expect(projects.every((project) => project.ownerId === "seed-creator")).toBe(true); + }); + + it("GET /projects/:projectId rejects foreign creators and allows operator/admin foundation reads", async () => { + const foreignProject = await seedProject(prisma, "foreign-detail", "seed-creator-other"); + const creatorToken = await login(testApp!, "creator@example.test"); + const operatorToken = await login(testApp!, "operator@example.test"); + const adminToken = await login(testApp!, "admin@example.test"); + + const denied = await requestJson(testApp!, `/projects/${foreignProject.id}`, { + headers: { authorization: `Bearer ${creatorToken}` } + }); + expect(denied.response.status).toBe(403); + expect(denied.body).toEqual({ + code: "FORBIDDEN", + message: expect.any(String), + requestId: null, + details: expect.anything() + }); + + const operatorRead = await requestJson(testApp!, `/projects/${foreignProject.id}`, { + headers: { authorization: `Bearer ${operatorToken}` } + }); + expect(operatorRead.response.status).toBe(200); + expect(operatorRead.body).toMatchObject({ id: foreignProject.id, ownerId: "seed-creator-other" }); + + const adminRead = await requestJson(testApp!, `/projects/${foreignProject.id}`, { + headers: { authorization: `Bearer ${adminToken}` } + }); + expect(adminRead.response.status).toBe(200); + expect(adminRead.body).toMatchObject({ id: foreignProject.id, ownerId: "seed-creator-other" }); + }); + + it("POST /projects/:projectId/versions creates a draft version for the owner through the state boundary", async () => { + const project = await seedProject(prisma, "version-owner", "seed-creator"); + const token = await login(testApp!, "creator@example.test"); + + const created = await requestJson(testApp!, `/projects/${project.id}/versions`, { + method: "POST", + headers: { authorization: `Bearer ${token}` }, + body: JSON.stringify({ configJson: { source: "task8" } }) + }); + + expect(created.response.status).toBe(201); + expect(created.body).toMatchObject({ + projectId: project.id, + versionNumber: 1, + status: "draft", + configJson: { source: "task8" } + }); + await expect( + prisma.auditLog.findFirst({ where: { targetId: (created.body as { id: string }).id, action: "version.created" } }) + ).resolves.toMatchObject({ actorId: "seed-creator", targetType: "GameVersion" }); + }); + + it("POST /projects/:projectId/versions rejects foreign creators without mutation", async () => { + const project = await seedProject(prisma, "version-foreign", "seed-creator-other"); + const token = await login(testApp!, "creator@example.test"); + + const denied = await requestJson(testApp!, `/projects/${project.id}/versions`, { + method: "POST", + headers: { authorization: `Bearer ${token}` }, + body: JSON.stringify({ configJson: { blocked: true } }) + }); + + expect(denied.response.status).toBe(403); + expect(denied.body).toMatchObject({ code: "FORBIDDEN", requestId: null, details: expect.anything() }); + await expect(prisma.gameVersion.count({ where: { projectId: project.id } })).resolves.toBe(0); + await expect(prisma.auditLog.count({ where: { targetId: project.id } })).resolves.toBe(0); + }); + + it("GET /projects/:projectId/versions returns only authorized versions and allows operator/admin reads", async () => { + const ownedProject = await seedProject(prisma, "versions-owned", "seed-creator"); + const foreignProject = await seedProject(prisma, "versions-foreign", "seed-creator-other"); + await prisma.$transaction(async (tx) => { + await seedDraftVersion(tx, ownedProject.id, "versions-owned", 1); + await seedDraftVersion(tx, foreignProject.id, "versions-foreign", 1); + }); + const creatorToken = await login(testApp!, "creator@example.test"); + const operatorToken = await login(testApp!, "operator@example.test"); + + const owned = await requestJson(testApp!, `/projects/${ownedProject.id}/versions`, { + headers: { authorization: `Bearer ${creatorToken}` } + }); + expect(owned.response.status).toBe(200); + expect((owned.body as Array<{ id: string }>).map((version) => version.id)).toEqual([`${runId}-versions-owned-version`]); + + const denied = await requestJson(testApp!, `/projects/${foreignProject.id}/versions`, { + headers: { authorization: `Bearer ${creatorToken}` } + }); + expect(denied.response.status).toBe(403); + expect(denied.body).toMatchObject({ code: "FORBIDDEN", message: expect.any(String), requestId: null }); + + const operatorRead = await requestJson(testApp!, `/projects/${foreignProject.id}/versions`, { + headers: { authorization: `Bearer ${operatorToken}` } + }); + expect(operatorRead.response.status).toBe(200); + expect(operatorRead.body).toEqual([ + expect.objectContaining({ id: `${runId}-versions-foreign-version`, projectId: foreignProject.id, status: "draft" }) + ]); + }); +}); diff --git a/apps/api/src/modules/queue/index.ts b/apps/api/src/modules/queue/index.ts new file mode 100644 index 00000000..bca7380f --- /dev/null +++ b/apps/api/src/modules/queue/index.ts @@ -0,0 +1,210 @@ +import { EventEmitter } from "node:events"; + +export type QueueMessage = { + readonly jobId: string; + readonly type: string; + readonly payload: unknown; +}; + +export type QueueHandler = (message: QueueMessage) => Promise | void; + +export interface QueueAdapter { + enqueue(message: QueueMessage): Promise; + process(handler: QueueHandler): Promise; + close(): Promise; +} + +export class QueueUnavailableError extends Error { + readonly code = "QUEUE_UNAVAILABLE"; + + constructor(message = "Queue is unavailable") { + super(message); + this.name = "QueueUnavailableError"; + } +} + +export class InMemoryQueueAdapter implements QueueAdapter { + private readonly messages: QueueMessage[] = []; + private closed = false; + + async enqueue(message: QueueMessage): Promise { + if (this.closed) throw new QueueUnavailableError("In-memory queue is closed"); + this.messages.push(message); + } + + async process(handler: QueueHandler): Promise { + if (this.closed) throw new QueueUnavailableError("In-memory queue is closed"); + + while (this.messages.length > 0) { + const message = this.messages.shift(); + if (message) await handler(message); + } + } + + async close(): Promise { + this.closed = true; + this.messages.length = 0; + } +} + +export type BullMqQueueAdapterOptions = { + readonly queueName: string; + readonly redisUrl: string; + readonly connectionTimeoutMs?: number; +}; + +type BullMqQueueInstance = { + add(name: string, data: QueueMessage): Promise; + close(): Promise; +}; + +type BullMqWorkerInstance = { + close(): Promise; + on(event: string, listener: (error: Error) => void): unknown; +}; + +type BullMqModule = { + readonly Queue: new (name: string, options: { connection: unknown }) => BullMqQueueInstance; + readonly Worker: new ( + name: string, + handler: (job: { data: QueueMessage }) => Promise, + options: { connection: unknown } + ) => BullMqWorkerInstance; +}; + +type IoredisModule = { + readonly default: new ( + url: string, + options: { maxRetriesPerRequest: null; enableReadyCheck: boolean; lazyConnect: boolean; connectTimeout: number } + ) => { + connect(): Promise; + disconnect(): void; + }; +}; + +function timeout(promise: Promise, timeoutMs: number): Promise { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => reject(new QueueUnavailableError()), timeoutMs); + promise.then( + (value) => { + clearTimeout(timer); + resolve(value); + }, + (error: unknown) => { + clearTimeout(timer); + reject(error); + } + ); + }); +} + +async function importBullMq(): Promise { + return (await import("bullmq")) as BullMqModule; +} + +async function importIoredis(): Promise { + return (await import("ioredis")) as unknown as IoredisModule; +} + +export class BullMqQueueAdapter implements QueueAdapter { + private readonly queueName: string; + private readonly redisUrl: string; + private readonly connectionTimeoutMs: number; + private queue: BullMqQueueInstance | undefined; + private worker: BullMqWorkerInstance | undefined; + private connection: + | { + connect(): Promise; + disconnect(): void; + } + | undefined; + + constructor(options: BullMqQueueAdapterOptions) { + this.queueName = options.queueName; + this.redisUrl = options.redisUrl; + this.connectionTimeoutMs = options.connectionTimeoutMs ?? 1000; + } + + async enqueue(message: QueueMessage): Promise { + const queue = await this.getQueue(); + try { + await timeout(queue.add(message.type, message), this.connectionTimeoutMs); + } catch (error) { + throw this.toUnavailable(error); + } + } + + async process(handler: QueueHandler): Promise { + try { + const [{ Worker }, connection] = await Promise.all([importBullMq(), this.getConnection()]); + this.worker = new Worker( + this.queueName, + async (job) => { + await handler(job.data); + }, + { connection } + ); + this.worker.on("error", () => undefined); + } catch (error) { + throw this.toUnavailable(error); + } + } + + async close(): Promise { + await this.worker?.close().catch(() => undefined); + await this.queue?.close().catch(() => undefined); + this.connection?.disconnect(); + } + + private async getQueue(): Promise { + if (this.queue) return this.queue; + + try { + const [{ Queue }, connection] = await Promise.all([importBullMq(), this.getConnection()]); + this.queue = new Queue(this.queueName, { connection }); + return this.queue; + } catch (error) { + throw this.toUnavailable(error); + } + } + + private async getConnection(): Promise> { + if (this.connection) return this.connection; + + try { + const { default: Redis } = await importIoredis(); + const connection = new Redis(this.redisUrl, { + maxRetriesPerRequest: null, + enableReadyCheck: false, + lazyConnect: true, + connectTimeout: this.connectionTimeoutMs + }); + await timeout(connection.connect(), this.connectionTimeoutMs); + this.connection = connection; + return connection; + } catch (error) { + throw this.toUnavailable(error); + } + } + + private toUnavailable(error: unknown): QueueUnavailableError { + if (error instanceof QueueUnavailableError) return error; + const message = error instanceof Error ? error.message : "Queue is unavailable"; + return new QueueUnavailableError(message); + } +} + +export class NoopQueueProcessor extends EventEmitter { + private processed = 0; + + async handle(message: QueueMessage): Promise { + // S1 worker 只消费 no-op 消息,不在 worker 内 claim/complete DB row,避免越过 API-owned JobExecutionStore。 + if (message.type !== "noop") throw new QueueUnavailableError(`Unsupported S1 job type: ${message.type}`); + this.processed += 1; + this.emit("processed", message); + } + + getProcessedCount(): number { + return this.processed; + } +} diff --git a/apps/api/src/modules/queue/queue.spec.ts b/apps/api/src/modules/queue/queue.spec.ts new file mode 100644 index 00000000..f18e089c --- /dev/null +++ b/apps/api/src/modules/queue/queue.spec.ts @@ -0,0 +1,32 @@ +import { BullMqQueueAdapter, InMemoryQueueAdapter, QueueUnavailableError } from "./index.js"; +import { describe, expect, it } from "vitest"; + +describe("QueueAdapter", () => { + it("memory adapter processes a no-op job in tests", async () => { + const adapter = new InMemoryQueueAdapter(); + const processed: string[] = []; + + await adapter.enqueue({ jobId: "job-memory-1", type: "noop", payload: { ok: true } }); + await adapter.process(async (message) => { + processed.push(message.jobId); + }); + + expect(processed).toEqual(["job-memory-1"]); + await adapter.close(); + }); + + it("BullMQ adapter reports QUEUE_UNAVAILABLE when Redis is unavailable", async () => { + const adapter = new BullMqQueueAdapter({ + queueName: "task7-unavailable", + redisUrl: "redis://127.0.0.1:1", + connectionTimeoutMs: 50 + }); + + await expect(adapter.enqueue({ jobId: "job-bullmq-1", type: "noop", payload: {} })).rejects.toMatchObject< + QueueUnavailableError + >({ + code: "QUEUE_UNAVAILABLE" + }); + await adapter.close(); + }); +}); diff --git a/apps/api/src/modules/rbac/index.ts b/apps/api/src/modules/rbac/index.ts new file mode 100644 index 00000000..e299e6d4 --- /dev/null +++ b/apps/api/src/modules/rbac/index.ts @@ -0,0 +1,95 @@ +export type UserRoleName = "admin" | "operator" | "creator" | "player"; +export type ActorRoleName = UserRoleName | "anonymous"; + +export type AuthenticatedActor = { + readonly id: string; + readonly roles: readonly UserRoleName[]; +}; + +export type AnonymousActor = { + readonly id: null; + readonly roles: readonly ["anonymous"]; +}; + +export type RbacActor = AuthenticatedActor | AnonymousActor; + +export type ReviewFoundationDataCategory = + | "project" + | "version" + | "audit-log" + | "review-record" + | "lifecycle-event" + | "management-crud"; + +const knownRoles = new Set(["admin", "operator", "creator", "player", "anonymous"]); +const reviewFoundationReadCategories = new Set([ + "project", + "version", + "audit-log", + "review-record", + "lifecycle-event" +]); + +export class RbacForbiddenError extends Error { + readonly statusCode = 403; + readonly code = "FORBIDDEN"; + + constructor(message: string) { + super(message); + this.name = "RbacForbiddenError"; + } +} + +export function makeAnonymousActor(): AnonymousActor { + return { id: null, roles: ["anonymous"] }; +} + +export function isKnownRole(role: unknown): role is ActorRoleName { + return typeof role === "string" && knownRoles.has(role as ActorRoleName); +} + +export function hasRole(actor: RbacActor, role: UserRoleName): boolean { + return actor.roles.some((actorRole) => actorRole === role); +} + +export function isAuthenticated(actor: RbacActor): actor is AuthenticatedActor { + return actor.id !== null; +} + +export function requireAuthenticated(actor: RbacActor): AuthenticatedActor { + if (!isAuthenticated(actor)) { + throw new Error("FORBIDDEN: anonymous actor is outside the S1 protected-route boundary"); + } + + return actor; +} + +export function creatorOwnsResource( + actor: RbacActor, + resource: { readonly ownerId?: string; readonly creatorId?: string; readonly actorId?: string } +): boolean { + if (!isAuthenticated(actor) || !hasRole(actor, "creator")) return false; + + // direct-object 授权必须 fail closed:资源对象没有明确归属字段时,不推断项目/版本关系。 + return resource.ownerId === actor.id || resource.creatorId === actor.id || resource.actorId === actor.id; +} + +export function requireCreatorResourceOwnership( + actor: RbacActor, + resource: { readonly ownerId?: string; readonly creatorId?: string; readonly actorId?: string } +): AuthenticatedActor { + if (!creatorOwnsResource(actor, resource)) { + // 直接对象访问必须先授权再执行写入;缺归属、跨 owner、匿名访问都统一 403,不做补偿式推断。 + throw new RbacForbiddenError("Creator cannot access this resource"); + } + + return requireAuthenticated(actor); +} + +export function canReadReviewFoundationData(actor: RbacActor, category: ReviewFoundationDataCategory): boolean { + if (!isAuthenticated(actor)) return false; + if (!reviewFoundationReadCategories.has(category)) return false; + + // S1 只开放审核所需基础读权限;后台管理 CRUD 留给后续明确端点单独授权。 + return hasRole(actor, "admin") || hasRole(actor, "operator"); +} diff --git a/apps/api/src/modules/rbac/rbac.spec.ts b/apps/api/src/modules/rbac/rbac.spec.ts new file mode 100644 index 00000000..6626125b --- /dev/null +++ b/apps/api/src/modules/rbac/rbac.spec.ts @@ -0,0 +1,66 @@ +import { describe, expect, it } from "vitest"; +import { + canReadReviewFoundationData, + creatorOwnsResource, + isAuthenticated, + isKnownRole, + makeAnonymousActor, + requireAuthenticated, + requireCreatorResourceOwnership +} from "./index.js"; + +describe("RBAC policy boundary", () => { + it("recognizes admin/operator/creator/player/anonymous roles", () => { + expect(isKnownRole("admin")).toBe(true); + expect(isKnownRole("operator")).toBe(true); + expect(isKnownRole("creator")).toBe(true); + expect(isKnownRole("player")).toBe(true); + expect(isKnownRole("anonymous")).toBe(true); + expect(isKnownRole("owner")).toBe(false); + }); + + it("treats anonymous as unauthenticated until the S6 public feed behavior exists", () => { + const anonymous = makeAnonymousActor(); + + expect(isAuthenticated(anonymous)).toBe(false); + expect(() => requireAuthenticated(anonymous)).toThrow(/FORBIDDEN/); + }); + + it("allows creator ownership on own resource-like objects and rejects foreign objects fail-closed", () => { + const creator = { id: "creator-1", roles: ["creator"] as const }; + + expect(creatorOwnsResource(creator, { ownerId: "creator-1" })).toBe(true); + expect(creatorOwnsResource(creator, { creatorId: "creator-1" })).toBe(true); + expect(creatorOwnsResource(creator, { actorId: "creator-1" })).toBe(true); + expect(creatorOwnsResource(creator, { ownerId: "creator-2" })).toBe(false); + expect(creatorOwnsResource(creator, { projectId: "project-without-owner" })).toBe(false); + expect(creatorOwnsResource(makeAnonymousActor(), { ownerId: "creator-1" })).toBe(false); + }); + + it("fails direct-object access closed with 403 before mutation", () => { + const creator = { id: "creator-1", roles: ["creator"] as const }; + const mutation = { applied: false }; + let caught: unknown; + + try { + requireCreatorResourceOwnership(creator, { ownerId: "creator-2" }); + mutation.applied = true; + } catch (error) { + caught = error; + } + + expect(caught).toMatchObject({ code: "FORBIDDEN", statusCode: 403 }); + expect(mutation.applied).toBe(false); + }); + + it("allows only operator/admin to read review-oriented foundation data categories", () => { + expect(canReadReviewFoundationData({ id: "admin-1", roles: ["admin"] }, "project")).toBe(true); + expect(canReadReviewFoundationData({ id: "operator-1", roles: ["operator"] }, "version")).toBe(true); + expect(canReadReviewFoundationData({ id: "operator-1", roles: ["operator"] }, "audit-log")).toBe(true); + + expect(canReadReviewFoundationData({ id: "creator-1", roles: ["creator"] }, "project")).toBe(false); + expect(canReadReviewFoundationData({ id: "player-1", roles: ["player"] }, "version")).toBe(false); + expect(canReadReviewFoundationData(makeAnonymousActor(), "audit-log")).toBe(false); + expect(canReadReviewFoundationData({ id: "operator-1", roles: ["operator"] }, "management-crud")).toBe(false); + }); +}); diff --git a/apps/api/src/modules/state-transition/index.ts b/apps/api/src/modules/state-transition/index.ts new file mode 100644 index 00000000..216d95ba --- /dev/null +++ b/apps/api/src/modules/state-transition/index.ts @@ -0,0 +1,396 @@ +import { readdir, readFile } from "node:fs/promises"; +import path from "node:path"; +import { Prisma, type GameVersion, type LifecycleEvent } from "../../generated/prisma/client.js"; +import type { HarnessClient, HarnessGateResult } from "../harness-gate/index.js"; + +export type ReviewDecisionEvent = "review_approved" | "review_rejected"; + +export type LifecycleEventDto = { + readonly eventId: string; + readonly event: ReviewDecisionEvent; + readonly from: "pending_review"; + readonly to: "publish_ready" | "rejected"; + readonly actor: Prisma.InputJsonValue; + readonly requiredRole: "operator"; + readonly requiredRecordRefs: Prisma.InputJsonValue; + readonly auditEvent: "lifecycle.review_approved" | "lifecycle.review_rejected"; + readonly reasonCode: string; + readonly occurredAt: string; + readonly approval: "operator"; + readonly requiredRecords: Prisma.InputJsonValue; +}; + +export type StateTransitionServiceOptions = { + readonly db: Prisma.TransactionClient; + // 失败审计必须能跨调用方事务回滚持久化,因此由 API composition root 注入非事务客户端。 + readonly blockedAuditDb: Pick; + readonly harnessGate: HarnessClient; + readonly now?: () => Date; +}; + +export type CreateDraftVersionInput = { + readonly id: string; + readonly projectId: string; + readonly versionNumber: number; + readonly configJson: Prisma.InputJsonValue; +}; + +export type ApplyReviewDecisionInput = { + readonly event: ReviewDecisionEvent; + readonly gameVersionId: string; + readonly reviewRecordId: string; + readonly lifecycleEventId: string; + readonly actorId: string; + readonly actor: Prisma.InputJsonValue; + readonly reasonCode: string; +}; + +export type ApplyReviewDecisionResult = { + readonly lifecycleEvent: LifecycleEventDto; +}; + +export type StateBoundaryViolationReason = + | "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION" + | "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION" + | "WORKER_DB_IMPORT_FORBIDDEN" + | "WORKER_STATE_TRANSITION_IMPORT_FORBIDDEN"; + +export type StateBoundaryViolation = { + readonly path: string; + readonly reason: StateBoundaryViolationReason; +}; + +type ScanFile = { + readonly path: string; + readonly content: string; +}; + +const stateTransitionGuardSql = "SELECT set_config('app.state_transition_guard', 'on', true)"; +const stateTransitionModulePrefix = "apps/api/src/modules/state-transition/"; +const generatedPrismaPrefix = "apps/api/src/generated/prisma/"; +const prismaMigrationPrefix = "apps/api/prisma/migrations/"; +const historicalTestFiles = new Set(["apps/api/src/prisma.schema.spec.ts"]); +const ignoredScanSegments = new Set(["node_modules", "dist", ".vite", "coverage", ".next"]); + +export class StateTransitionDomainError extends Error { + readonly statusCode = 422; + readonly reasonCode: string; + + constructor(reasonCode: string) { + super(`State transition rejected by harness: ${reasonCode}`); + this.name = "StateTransitionDomainError"; + this.reasonCode = reasonCode; + } +} + +function eventSpec(event: ReviewDecisionEvent) { + if (event === "review_approved") { + return { + auditEvent: "lifecycle.review_approved" as const, + decision: "approved" as const, + status: "approved" as const, + to: "publish_ready" as const, + requiredRecords: ["ReviewRecord.decision=approved", "ReviewRecord.reasonCode"] + }; + } + + return { + auditEvent: "lifecycle.review_rejected" as const, + decision: "rejected" as const, + status: "rejected" as const, + to: "rejected" as const, + requiredRecords: ["ReviewRecord.decision=rejected", "ReviewRecord.reasonCode"] + }; +} + +export function projectLifecycleEvent(row: Pick< + LifecycleEvent, + | "eventId" + | "event" + | "from" + | "to" + | "actorJson" + | "requiredRole" + | "requiredRecordRefsJson" + | "auditEvent" + | "reasonCode" + | "occurredAt" + | "approval" + | "requiredRecordsJson" +>): LifecycleEventDto { + return { + eventId: row.eventId, + event: row.event as ReviewDecisionEvent, + from: row.from as "pending_review", + to: row.to as "publish_ready" | "rejected", + actor: row.actorJson as Prisma.InputJsonValue, + requiredRole: row.requiredRole as "operator", + requiredRecordRefs: row.requiredRecordRefsJson as Prisma.InputJsonValue, + auditEvent: row.auditEvent as "lifecycle.review_approved" | "lifecycle.review_rejected", + reasonCode: row.reasonCode, + occurredAt: row.occurredAt.toISOString(), + approval: row.approval as "operator", + requiredRecords: row.requiredRecordsJson as Prisma.InputJsonValue + }; +} + +export class StateTransitionService { + private readonly db: Prisma.TransactionClient; + private readonly blockedAuditDb: Pick; + private readonly harnessGate: HarnessClient; + private readonly now: () => Date; + + constructor(options: StateTransitionServiceOptions) { + this.db = options.db; + this.blockedAuditDb = options.blockedAuditDb; + this.harnessGate = options.harnessGate; + this.now = options.now ?? (() => new Date()); + } + + async createDraftVersion(input: CreateDraftVersionInput): Promise { + return this.withStateTransitionGuard(() => + this.db.gameVersion.create({ + data: { + id: input.id, + projectId: input.projectId, + versionNumber: input.versionNumber, + status: "draft", + configJson: input.configJson + } + }) + ); + } + + async applyReviewDecision(input: ApplyReviewDecisionInput): Promise { + const spec = eventSpec(input.event); + const occurredAt = this.now(); + const lifecycleEvent: LifecycleEventDto = { + eventId: input.lifecycleEventId, + event: input.event, + from: "pending_review", + to: spec.to, + actor: input.actor, + requiredRole: "operator", + requiredRecordRefs: [input.reviewRecordId], + auditEvent: spec.auditEvent, + reasonCode: input.reasonCode, + occurredAt: occurredAt.toISOString(), + approval: "operator", + requiredRecords: spec.requiredRecords + }; + + const gate = await this.harnessGate.validateTransition(input.event, lifecycleEvent); + if (!gate.ok) { + await this.writeBlockedAudit(input, spec.auditEvent, gate); + throw new StateTransitionDomainError(gate.reasonCode ?? "HARNESS_INVALID_OUTPUT"); + } + + const contractGate = await this.harnessGate.validateContract("LifecycleEvent", lifecycleEvent); + if (!contractGate.ok) { + await this.writeBlockedAudit(input, spec.auditEvent, contractGate); + throw new StateTransitionDomainError(contractGate.reasonCode ?? "HARNESS_INVALID_OUTPUT"); + } + + await this.withStateTransitionGuard(async () => { + await this.db.reviewRecord.create({ + data: { + id: input.reviewRecordId, + gameVersionId: input.gameVersionId, + status: spec.status, + decision: spec.decision, + reasonCode: input.reasonCode, + decidedById: input.actorId, + decidedAt: occurredAt + } + }); + + await this.db.lifecycleEvent.create({ + data: { + eventId: input.lifecycleEventId, + gameVersionId: input.gameVersionId, + event: input.event, + from: lifecycleEvent.from, + to: lifecycleEvent.to, + actorJson: lifecycleEvent.actor, + requiredRole: lifecycleEvent.requiredRole, + requiredRecordRefsJson: lifecycleEvent.requiredRecordRefs, + auditEvent: lifecycleEvent.auditEvent, + reasonCode: lifecycleEvent.reasonCode, + occurredAt, + approval: lifecycleEvent.approval, + requiredRecordsJson: lifecycleEvent.requiredRecords + } + }); + }); + + await this.db.auditLog.create({ + data: { + id: `${input.lifecycleEventId}-audit`, + actorId: input.actorId, + action: spec.auditEvent, + targetType: "GameVersion", + targetId: input.gameVersionId, + eventJson: { + lifecycleEventId: input.lifecycleEventId, + reviewRecordId: input.reviewRecordId, + harness: gate + } + } + }); + + return { lifecycleEvent }; + } + + private async withStateTransitionGuard(callback: () => Promise): Promise { + await this.db.$executeRawUnsafe(stateTransitionGuardSql); + try { + const result = await callback(); + await this.db.$executeRawUnsafe("SELECT set_config('app.state_transition_guard', '', true)"); + return result; + } catch (error) { + try { + await this.db.$executeRawUnsafe("SELECT set_config('app.state_transition_guard', '', true)"); + } catch { + // 保留原始 DB/业务错误优先级;事务结束时 transaction-local guard 会释放。 + } + throw error; + } + } + + private async writeBlockedAudit( + input: ApplyReviewDecisionInput, + action: string, + gate: HarnessGateResult + ): Promise { + await this.blockedAuditDb.auditLog.create({ + data: { + id: `${input.lifecycleEventId}-blocked-audit`, + actorId: input.actorId, + action: `${action}.blocked`, + targetType: "GameVersion", + targetId: input.gameVersionId, + eventJson: { + lifecycleEventId: input.lifecycleEventId, + reviewRecordId: input.reviewRecordId, + reasonCode: gate.reasonCode + } + } + }); + } +} + +async function collectFiles(root: string, relativeDir: string): Promise { + const absoluteDir = path.join(root, relativeDir); + const entries = await readdir(absoluteDir, { withFileTypes: true }).catch(() => []); + const files: ScanFile[] = []; + + for (const entry of entries) { + if (entry.isDirectory() && ignoredScanSegments.has(entry.name)) continue; + const relativePath = path.join(relativeDir, entry.name); + const absolutePath = path.join(root, relativePath); + if (entry.isDirectory()) files.push(...(await collectFiles(root, relativePath))); + if (entry.isFile() && /\.(?:ts|tsx|js|mjs|cjs|json|sql)$/.test(entry.name)) { + files.push({ + path: relativePath, + content: await readFile(absolutePath, "utf8") + }); + } + } + + return files; +} + +function isAllowedStateTransitionFile(filePath: string): boolean { + return filePath.startsWith(stateTransitionModulePrefix); +} + +function isHistoricalTestFile(filePath: string): boolean { + return historicalTestFiles.has(filePath); +} + +function isGeneratedPrismaFile(filePath: string): boolean { + return filePath.startsWith(generatedPrismaPrefix); +} + +function isIgnoredScanPath(filePath: string): boolean { + return filePath.split("/").some((segment) => ignoredScanSegments.has(segment)); +} + +function hasGuardedPrismaWrite(content: string): boolean { + const guardedModels = ["gameVersion", "reviewRecord", "lifecycleEvent"]; + const hasPrismaWrite = guardedModels.some((model) => { + const createOrUpdate = new RegExp(`\\.${model}\\.(?:create|update|upsert|createMany|updateMany|delete|deleteMany)\\s*\\(`); + return createOrUpdate.test(content); + }); + const hasSqlWrite = /\b(?:INSERT\s+INTO|UPDATE|DELETE\s+FROM)\s+"?(?:GameVersion|ReviewRecord|LifecycleEvent)"?/i.test(content); + return hasPrismaWrite || hasSqlWrite; +} + +function hasRuntimeGuardSetter(content: string): boolean { + return /app\.state_transition_guard|set_config\s*\(|SET\s+LOCAL/i.test(content); +} + +function stripSqlComments(content: string): string { + return content + .replace(/\/\*[\s\S]*?\*\//g, "") + .split("\n") + .map((line) => line.replace(/--.*$/, "")) + .join("\n"); +} + +function hasForbiddenMigrationGuardSetter(content: string): boolean { + const sql = stripSqlComments(content); + return /set_config\s*\(|SET\s+LOCAL/i.test(sql); +} + +export function findStateBoundaryViolations(files: readonly ScanFile[]): StateBoundaryViolation[] { + const violations: StateBoundaryViolation[] = []; + + for (const file of files) { + const normalizedPath = file.path.split(path.sep).join("/"); + if (isIgnoredScanPath(normalizedPath)) continue; + if (isHistoricalTestFile(normalizedPath)) continue; + if (isGeneratedPrismaFile(normalizedPath)) continue; + + if (normalizedPath.startsWith("apps/worker/")) { + if (/@prisma\/client|generated\/prisma|PrismaClient/.test(file.content)) { + violations.push({ path: normalizedPath, reason: "WORKER_DB_IMPORT_FORBIDDEN" }); + } + if (/state-transition|StateTransitionService|app\.state_transition_guard|set_config\s*\(|SET\s+LOCAL/i.test(file.content)) { + violations.push({ path: normalizedPath, reason: "WORKER_STATE_TRANSITION_IMPORT_FORBIDDEN" }); + } + continue; + } + + if (isAllowedStateTransitionFile(normalizedPath)) continue; + + if (normalizedPath.startsWith(prismaMigrationPrefix)) { + if (hasForbiddenMigrationGuardSetter(file.content)) { + violations.push({ path: normalizedPath, reason: "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION" }); + } + if (hasGuardedPrismaWrite(file.content)) { + violations.push({ path: normalizedPath, reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION" }); + } + continue; + } + + if (hasGuardedPrismaWrite(file.content)) { + violations.push({ path: normalizedPath, reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION" }); + } + if (hasRuntimeGuardSetter(file.content)) { + violations.push({ path: normalizedPath, reason: "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION" }); + } + } + + return violations; +} + +export async function scanStateTransitionBoundary(repoRoot: string): Promise { + const files = [ + ...(await collectFiles(repoRoot, "apps/api/src")), + ...(await collectFiles(repoRoot, "apps/api/prisma/migrations")), + ...(await collectFiles(repoRoot, "apps/worker")) + ]; + + return findStateBoundaryViolations(files); +} diff --git a/apps/api/src/modules/state-transition/state-transition.spec.ts b/apps/api/src/modules/state-transition/state-transition.spec.ts new file mode 100644 index 00000000..a27b42c5 --- /dev/null +++ b/apps/api/src/modules/state-transition/state-transition.spec.ts @@ -0,0 +1,456 @@ +import { execFile } from "node:child_process"; +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { promisify } from "node:util"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { Prisma, PrismaClient } from "../../generated/prisma/client.js"; +import { HarnessGateService } from "../harness-gate/index.js"; +import { + StateTransitionDomainError, + StateTransitionService, + findStateBoundaryViolations, + projectLifecycleEvent, + scanStateTransitionBoundary +} from "./index.js"; +import { afterAll, describe, expect, it } from "vitest"; + +const execFileAsync = promisify(execFile); +const databaseUrl = process.env.DATABASE_URL ?? "postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public"; +const adapter = new PrismaPg({ connectionString: databaseUrl }); +const prisma = new PrismaClient({ adapter }); +const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../../.."); +const harnessCli = path.join(repoRoot, "harness", "scripts", "validate-harness.mjs"); +const rollbackToken = Symbol("state transition rollback"); +const runId = `task5-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; +const occurredAt = new Date("2026-06-01T06:00:00.000Z"); + +type DbClient = Prisma.TransactionClient; +let savepointSequence = 0; + +class OrdinaryVersionService { + constructor(private readonly db: DbClient) {} + + async forceStatus(versionId: string) { + return this.db.gameVersion.update({ + where: { id: versionId }, + data: { status: "active" } + }); + } +} + +async function withRollback(callback: (tx: DbClient) => Promise): Promise { + try { + await prisma.$transaction(async (tx) => { + await callback(tx); + throw rollbackToken; + }); + } catch (error) { + if (error !== rollbackToken) throw error; + } +} + +async function expectPrismaRejectedInSavepoint( + db: DbClient, + action: () => Promise, + pattern: RegExp +): Promise { + const savepointName = `task5_sp_${++savepointSequence}`; + await db.$executeRawUnsafe(`SAVEPOINT ${savepointName}`); + + let caught: unknown; + try { + await action(); + } catch (error) { + caught = error; + } + + await db.$executeRawUnsafe(`ROLLBACK TO SAVEPOINT ${savepointName}`); + await db.$executeRawUnsafe(`RELEASE SAVEPOINT ${savepointName}`); + + if (caught === undefined) throw new Error(`Expected Prisma action to reject with ${pattern}`); + expect(() => { + throw caught; + }).toThrow(pattern); +} + +async function withTempJson(value: unknown, callback: (payloadPath: string) => Promise): Promise { + const dir = await mkdtemp(path.join(os.tmpdir(), "huijing-state-transition-")); + const payloadPath = path.join(dir, "payload.json"); + + try { + await writeFile(payloadPath, JSON.stringify(value), "utf8"); + return await callback(payloadPath); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +async function expectHarnessContract(contract: string, value: unknown): Promise { + await withTempJson(value, async (payloadPath) => { + const result = await execFileAsync("node", [harnessCli, "--contract", contract, "--input", payloadPath], { + cwd: repoRoot + }); + expect(JSON.parse(result.stdout)).toEqual({ ok: true, reasonCode: null }); + }); +} + +async function expectHarnessTransition(transition: string, value: unknown): Promise { + await withTempJson(value, async (payloadPath) => { + const result = await execFileAsync("node", [harnessCli, "--transition", transition, "--input", payloadPath], { + cwd: repoRoot + }); + expect(JSON.parse(result.stdout)).toEqual({ ok: true, reasonCode: null }); + }); +} + +async function seedProjectSet(db: DbClient, suffix: string) { + const creator = await db.user.create({ + data: { + id: `${runId}-${suffix}-creator`, + email: `${runId}-${suffix}-creator@example.test`, + displayName: `${suffix} creator` + } + }); + + const operator = await db.user.create({ + data: { + id: `${runId}-${suffix}-operator`, + email: `${runId}-${suffix}-operator@example.test`, + displayName: `${suffix} operator` + } + }); + + const project = await db.gameProject.create({ + data: { + id: `${runId}-${suffix}-project`, + ownerId: creator.id, + slug: `${runId}-${suffix}-project`, + title: `${suffix} project` + } + }); + + const service = new StateTransitionService({ db, blockedAuditDb: db, harnessGate: new HarnessGateService() }); + const version = await service.createDraftVersion({ + id: `${runId}-${suffix}-version`, + projectId: project.id, + versionNumber: 1, + configJson: { seed: suffix } + }); + + return { creator, operator, project, version }; +} + +describe("StateTransitionService", () => { + afterAll(async () => { + await prisma.$disconnect(); + }); + + it("harness PASS allows review_approved and writes review, lifecycle, and audit facts", async () => { + await withRollback(async (tx) => { + const seeded = await seedProjectSet(tx, "approve-pass"); + const service = new StateTransitionService({ + db: tx, + blockedAuditDb: prisma, + harnessGate: new HarnessGateService(), + now: () => occurredAt + }); + + const result = await service.applyReviewDecision({ + event: "review_approved", + gameVersionId: seeded.version.id, + reviewRecordId: `${runId}-approve-pass-review`, + lifecycleEventId: `${runId}-approve-pass-lifecycle`, + actorId: seeded.operator.id, + actor: { role: "operator", operatorId: seeded.operator.id }, + reasonCode: "approved_for_publish" + }); + + expect(result.lifecycleEvent).toEqual({ + eventId: `${runId}-approve-pass-lifecycle`, + event: "review_approved", + from: "pending_review", + to: "publish_ready", + actor: { role: "operator", operatorId: seeded.operator.id }, + requiredRole: "operator", + requiredRecordRefs: [`${runId}-approve-pass-review`], + auditEvent: "lifecycle.review_approved", + reasonCode: "approved_for_publish", + occurredAt: occurredAt.toISOString(), + approval: "operator", + requiredRecords: ["ReviewRecord.decision=approved", "ReviewRecord.reasonCode"] + }); + + const review = await tx.reviewRecord.findUniqueOrThrow({ where: { id: `${runId}-approve-pass-review` } }); + expect(review.status).toBe("approved"); + expect(review.decision).toBe("approved"); + expect(review.reasonCode).toBe("approved_for_publish"); + + const lifecycle = await tx.lifecycleEvent.findUniqueOrThrow({ + where: { eventId: `${runId}-approve-pass-lifecycle` } + }); + const projected = projectLifecycleEvent(lifecycle); + await expectHarnessContract("LifecycleEvent", projected); + await expectHarnessTransition("review_approved", projected); + + const audit = await tx.auditLog.findFirstOrThrow({ + where: { action: "lifecycle.review_approved", targetId: seeded.version.id } + }); + expect(audit.eventJson).toMatchObject({ + lifecycleEventId: `${runId}-approve-pass-lifecycle`, + reviewRecordId: `${runId}-approve-pass-review`, + harness: { ok: true, reasonCode: null } + }); + }); + }); + + it("harness FAIL bubbles across the transaction boundary and persists the blocked audit fact", async () => { + const seeded = await prisma.$transaction((tx) => seedProjectSet(tx, "approve-fail")); + + await expect( + prisma.$transaction(async (tx) => { + const service = new StateTransitionService({ + db: tx, + blockedAuditDb: prisma, + harnessGate: { + validateContract: async () => ({ ok: true, reasonCode: null }), + validateTransition: async () => ({ ok: false, reasonCode: "TRANSITION_REQUIRED_RECORD_MISMATCH" }) + }, + now: () => occurredAt + }); + + await service.applyReviewDecision({ + event: "review_approved", + gameVersionId: seeded.version.id, + reviewRecordId: `${runId}-approve-fail-review`, + lifecycleEventId: `${runId}-approve-fail-lifecycle`, + actorId: seeded.operator.id, + actor: { role: "operator", operatorId: seeded.operator.id }, + reasonCode: "approved_for_publish" + }); + }) + ).rejects.toMatchObject({ + statusCode: 422, + reasonCode: "TRANSITION_REQUIRED_RECORD_MISMATCH" + }); + + await expect(prisma.reviewRecord.findUnique({ where: { id: `${runId}-approve-fail-review` } })).resolves.toBeNull(); + await expect( + prisma.lifecycleEvent.findUnique({ where: { eventId: `${runId}-approve-fail-lifecycle` } }) + ).resolves.toBeNull(); + + const audit = await prisma.auditLog.findUniqueOrThrow({ + where: { id: `${runId}-approve-fail-lifecycle-blocked-audit` } + }); + expect(audit).toMatchObject({ + action: "lifecycle.review_approved.blocked", + targetId: seeded.version.id + }); + expect(audit.eventJson).toMatchObject({ + reasonCode: "TRANSITION_REQUIRED_RECORD_MISMATCH", + lifecycleEventId: `${runId}-approve-fail-lifecycle`, + reviewRecordId: `${runId}-approve-fail-review` + }); + }); + + it("ordinary services and direct Prisma cannot bypass guarded status or lifecycle writes", async () => { + await withRollback(async (tx) => { + const seeded = await seedProjectSet(tx, "bypass"); + const ordinary = new OrdinaryVersionService(tx); + + await expectPrismaRejectedInSavepoint(tx, () => ordinary.forceStatus(seeded.version.id), /state transition guard is required/); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.gameVersion.create({ + data: { + id: `${runId}-bypass-direct-version`, + projectId: seeded.project.id, + versionNumber: 2, + status: "draft", + configJson: {} + } + }), + /state transition guard is required/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.reviewRecord.create({ + data: { + id: `${runId}-bypass-direct-review`, + gameVersionId: seeded.version.id, + status: "pending_review" + } + }), + /state transition guard is required/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.lifecycleEvent.create({ + data: { + eventId: `${runId}-bypass-direct-lifecycle`, + gameVersionId: seeded.version.id, + event: "review_rejected", + from: "pending_review", + to: "rejected", + actorJson: { role: "operator", operatorId: seeded.operator.id }, + requiredRole: "operator", + requiredRecordRefsJson: [`${runId}-bypass-direct-review`], + auditEvent: "lifecycle.review_rejected", + reasonCode: "needs_design_changes", + occurredAt, + approval: "operator", + requiredRecordsJson: ["ReviewRecord.decision=rejected", "ReviewRecord.reasonCode"] + } + }), + /state transition guard is required/ + ); + }); + }); + + it("DB review/lifecycle facts project to S0 review_rejected transition input and LifecycleEvent contract", async () => { + await withRollback(async (tx) => { + const seeded = await seedProjectSet(tx, "reject-pass"); + const service = new StateTransitionService({ + db: tx, + blockedAuditDb: prisma, + harnessGate: new HarnessGateService(), + now: () => occurredAt + }); + + await service.applyReviewDecision({ + event: "review_rejected", + gameVersionId: seeded.version.id, + reviewRecordId: `${runId}-reject-pass-review`, + lifecycleEventId: `${runId}-reject-pass-lifecycle`, + actorId: seeded.operator.id, + actor: { role: "operator", operatorId: seeded.operator.id }, + reasonCode: "needs_design_changes" + }); + + const review = await tx.reviewRecord.findUniqueOrThrow({ where: { id: `${runId}-reject-pass-review` } }); + expect(review.status).toBe("rejected"); + expect(review.decision).toBe("rejected"); + + const lifecycle = await tx.lifecycleEvent.findUniqueOrThrow({ + where: { eventId: `${runId}-reject-pass-lifecycle` } + }); + const projected = projectLifecycleEvent(lifecycle); + await expectHarnessContract("LifecycleEvent", projected); + await expectHarnessTransition("review_rejected", projected); + }); + }); + + it("static scan enforces runtime state-transition and worker DB boundaries without scanning historical Task 4 tests", async () => { + await expect(scanStateTransitionBoundary(repoRoot)).resolves.toEqual([]); + + expect( + findStateBoundaryViolations([ + { + path: "apps/api/src/modules/projects/project.service.ts", + content: "await prisma.gameVersion.update({ where: { id }, data: { status: 'active' } });" + }, + { + path: "apps/api/src/modules/reviews/review.service.ts", + content: "await db.$executeRawUnsafe(\"SELECT set_config('app.state_transition_guard', 'on', true)\");" + }, + { + path: "apps/worker/src/index.ts", + content: "import { PrismaClient } from '@prisma/client';" + }, + { + path: "apps/worker/src/review-worker.ts", + content: "import { StateTransitionService } from '../../api/src/modules/state-transition/index.js';" + }, + { + path: "apps/worker/package.json", + content: "{\"dependencies\":{\"@prisma/client\":\"7.8.0\"}}" + } + ]) + ).toEqual([ + { + path: "apps/api/src/modules/projects/project.service.ts", + reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION" + }, + { + path: "apps/api/src/modules/reviews/review.service.ts", + reason: "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION" + }, + { + path: "apps/worker/src/index.ts", + reason: "WORKER_DB_IMPORT_FORBIDDEN" + }, + { + path: "apps/worker/src/review-worker.ts", + reason: "WORKER_STATE_TRANSITION_IMPORT_FORBIDDEN" + }, + { + path: "apps/worker/package.json", + reason: "WORKER_DB_IMPORT_FORBIDDEN" + } + ]); + + expect( + findStateBoundaryViolations([ + { + path: "apps/api/src/modules/state-transition/index.ts", + content: + "await tx.$executeRawUnsafe(\"SELECT set_config('app.state_transition_guard', 'on', true)\"); await tx.lifecycleEvent.create({ data });" + }, + { + path: "apps/api/prisma/migrations/20260601040253_s1_app_foundation/migration.sql", + content: await readFile(path.join(repoRoot, "apps/api/prisma/migrations/20260601040253_s1_app_foundation/migration.sql"), "utf8") + } + ]) + ).toEqual([]); + + expect( + findStateBoundaryViolations([ + { + path: "apps/api/prisma/migrations/20260601999999_bad/migration.sql", + content: "SELECT set_config('app.state_transition_guard', 'on', true);" + }, + { + path: "apps/api/prisma/migrations/20260601999999_bad/migration.sql", + content: "UPDATE \"GameVersion\" SET \"status\" = 'active';" + }, + { + path: "apps/api/prisma/migrations/20260601999999_bad/migration.sql", + content: "INSERT INTO \"LifecycleEvent\" (\"eventId\") VALUES ('x');" + } + ]) + ).toEqual([ + { + path: "apps/api/prisma/migrations/20260601999999_bad/migration.sql", + reason: "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION" + }, + { + path: "apps/api/prisma/migrations/20260601999999_bad/migration.sql", + reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION" + }, + { + path: "apps/api/prisma/migrations/20260601999999_bad/migration.sql", + reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION" + } + ]); + + expect( + findStateBoundaryViolations([ + { + path: "apps/api/src/prisma.schema.spec.ts", + content: "await db.$executeRawUnsafe(\"SELECT set_config('app.state_transition_guard', 'on', true)\");" + }, + { + path: "apps/worker/dist/index.js", + content: "const { PrismaClient } = require('@prisma/client');" + } + ]) + ).toEqual([]); + }); +}); diff --git a/apps/api/src/modules/storage/index.ts b/apps/api/src/modules/storage/index.ts new file mode 100644 index 00000000..6bb17c1b --- /dev/null +++ b/apps/api/src/modules/storage/index.ts @@ -0,0 +1,190 @@ +import { createHash, randomUUID } from "node:crypto"; +import { lstat, mkdir, realpath, rename, rm, writeFile } from "node:fs/promises"; +import path from "node:path"; + +export type PutObjectInput = { + readonly ownerId: string; + readonly projectId: string; + readonly objectName: string; + readonly mimeType: string; + readonly bytes: Buffer | Uint8Array; + readonly expectedSha256: string; +}; + +export type PutObjectResult = { + readonly storageKey: string; + readonly absolutePath: string; + readonly byteSize: number; + readonly sha256: string; + readonly mimeType: string; +}; + +export type PlanObjectInput = Omit & { + readonly byteSize: number; +}; + +export type PlanObjectResult = Omit; + +export type LocalStorageAdapterOptions = { + readonly root: string; + readonly allowedMimeTypes: readonly string[]; + readonly maxBytes: number; +}; + +export type StorageBoundaryErrorCode = + | "INVALID_STORAGE_KEY" + | "STORAGE_ROOT_ESCAPE" + | "MIME_NOT_ALLOWED" + | "FILE_TOO_LARGE" + | "CHECKSUM_MISMATCH"; + +export class StorageBoundaryError extends Error { + readonly code: StorageBoundaryErrorCode; + + constructor(code: StorageBoundaryErrorCode, message = code) { + super(message); + this.name = "StorageBoundaryError"; + this.code = code; + } +} + +function sha256(bytes: Buffer | Uint8Array): string { + return createHash("sha256").update(bytes).digest("hex"); +} + +function isSafeSegment(segment: string): boolean { + return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(segment) && segment !== "." && segment !== ".."; +} + +function rejectUnsafeValue(value: string): void { + if (value.includes("\u0000")) throw new StorageBoundaryError("INVALID_STORAGE_KEY"); + if (/%(?:2f|5c|00|2e)/i.test(value)) throw new StorageBoundaryError("INVALID_STORAGE_KEY"); +} + +function normalizeObjectName(objectName: string): string { + rejectUnsafeValue(objectName); + if (path.isAbsolute(objectName)) throw new StorageBoundaryError("INVALID_STORAGE_KEY"); + + const normalized = path.posix.normalize(objectName); + if (normalized.startsWith("../") || normalized === ".." || normalized.includes("/../")) { + throw new StorageBoundaryError("INVALID_STORAGE_KEY"); + } + + const segments = normalized.split("/"); + if (segments.some((segment) => !isSafeSegment(segment))) throw new StorageBoundaryError("INVALID_STORAGE_KEY"); + return segments.join("/"); +} + +async function assertInsideRoot(rootReal: string, candidate: string): Promise { + const parentReal = await realpath(path.dirname(candidate)); + const relative = path.relative(rootReal, parentReal); + if (relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative))) return; + throw new StorageBoundaryError("STORAGE_ROOT_ESCAPE"); +} + +function isNotFound(error: unknown): boolean { + return error instanceof Error && "code" in error && error.code === "ENOENT"; +} + +function assertRealPathInsideRoot(rootReal: string, candidateReal: string): void { + const relative = path.relative(rootReal, candidateReal); + if (relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative))) return; + throw new StorageBoundaryError("STORAGE_ROOT_ESCAPE"); +} + +async function assertSafeExistingDirectory(rootReal: string, candidate: string): Promise { + const stat = await lstat(candidate); + if (stat.isSymbolicLink()) throw new StorageBoundaryError("STORAGE_ROOT_ESCAPE"); + if (!stat.isDirectory()) throw new StorageBoundaryError("INVALID_STORAGE_KEY"); + assertRealPathInsideRoot(rootReal, await realpath(candidate)); +} + +async function ensureSafeDirectory(root: string, rootReal: string, relativeSegments: readonly string[]): Promise { + let current = root; + for (const segment of relativeSegments) { + current = path.join(current, segment); + try { + await assertSafeExistingDirectory(rootReal, current); + } catch (error) { + if (!isNotFound(error)) throw error; + + // 逐级创建目录前已确认父级不是 symlink 且 realpath 仍在 root 内,避免 recursive mkdir 穿过 root 内 symlink 污染外部目录。 + await mkdir(current); + await assertSafeExistingDirectory(rootReal, current); + } + } +} + +export class LocalStorageAdapter { + private readonly root: string; + private readonly allowedMimeTypes: Set; + private readonly maxBytes: number; + + constructor(options: LocalStorageAdapterOptions) { + this.root = path.resolve(options.root); + this.allowedMimeTypes = new Set(options.allowedMimeTypes); + this.maxBytes = options.maxBytes; + } + + planObject(input: PlanObjectInput): PlanObjectResult { + if (!this.allowedMimeTypes.has(input.mimeType)) throw new StorageBoundaryError("MIME_NOT_ALLOWED"); + if (input.byteSize > this.maxBytes) throw new StorageBoundaryError("FILE_TOO_LARGE"); + if (!Number.isInteger(input.byteSize) || input.byteSize <= 0) throw new StorageBoundaryError("FILE_TOO_LARGE"); + + rejectUnsafeValue(input.ownerId); + rejectUnsafeValue(input.projectId); + if (!isSafeSegment(input.ownerId) || !isSafeSegment(input.projectId)) throw new StorageBoundaryError("INVALID_STORAGE_KEY"); + + const expected = input.expectedSha256.toLowerCase(); + if (!/^[a-f0-9]{64}$/.test(expected)) throw new StorageBoundaryError("CHECKSUM_MISMATCH"); + + return { + // presign 和实际 putObject 共用 adapter-owned key 构造,避免 API 层复制 path/MIME/size 规则后漂移。 + storageKey: `owners/${input.ownerId}/projects/${input.projectId}/${normalizeObjectName(input.objectName)}`, + byteSize: input.byteSize, + sha256: expected, + mimeType: input.mimeType + }; + } + + async putObject(input: PutObjectInput): Promise { + const planned = this.planObject({ + ownerId: input.ownerId, + projectId: input.projectId, + objectName: input.objectName, + mimeType: input.mimeType, + byteSize: input.bytes.byteLength, + expectedSha256: input.expectedSha256 + }); + const expected = input.expectedSha256.toLowerCase(); + const actual = sha256(input.bytes); + if (actual !== expected) throw new StorageBoundaryError("CHECKSUM_MISMATCH"); + + await mkdir(this.root, { recursive: true }); + const rootReal = await realpath(this.root); + const finalPath = path.join(this.root, planned.storageKey); + const finalDirSegments = planned.storageKey.split("/").slice(0, -1); + const tempPath = path.join(this.root, `.upload-${randomUUID()}.tmp`); + + try { + await assertSafeExistingDirectory(rootReal, this.root); + await ensureSafeDirectory(this.root, rootReal, finalDirSegments); + await assertInsideRoot(rootReal, finalPath); + await writeFile(tempPath, input.bytes); + await assertInsideRoot(rootReal, tempPath); + await rename(tempPath, finalPath); + await assertInsideRoot(rootReal, finalPath); + return { + storageKey: planned.storageKey, + absolutePath: finalPath, + byteSize: input.bytes.byteLength, + sha256: actual, + mimeType: input.mimeType + }; + } catch (error) { + await rm(tempPath, { force: true }).catch(() => undefined); + if (error instanceof StorageBoundaryError) throw error; + throw error; + } + } +} diff --git a/apps/api/src/modules/storage/storage.spec.ts b/apps/api/src/modules/storage/storage.spec.ts new file mode 100644 index 00000000..cbb241e7 --- /dev/null +++ b/apps/api/src/modules/storage/storage.spec.ts @@ -0,0 +1,132 @@ +import { mkdir, readdir, readFile, rm, symlink, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { createHash } from "node:crypto"; +import { LocalStorageAdapter, StorageBoundaryError } from "./index.js"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; + +let root: string; +let outside: string; + +function sha256(buffer: Buffer): string { + return createHash("sha256").update(buffer).digest("hex"); +} + +function adapter(options: { maxBytes?: number; mimeTypes?: string[] } = {}) { + return new LocalStorageAdapter({ + root, + allowedMimeTypes: options.mimeTypes ?? ["text/plain", "image/png"], + maxBytes: options.maxBytes ?? 1024 + }); +} + +beforeEach(async () => { + root = path.join(os.tmpdir(), `huijing-storage-${Date.now()}-${Math.random().toString(36).slice(2)}`); + await mkdir(root, { recursive: true }); + outside = path.join(os.tmpdir(), `huijing-storage-outside-${Date.now()}-${Math.random().toString(36).slice(2)}`); + await mkdir(outside, { recursive: true }); +}); + +afterEach(async () => { + await rm(root, { recursive: true, force: true }); + await rm(outside, { recursive: true, force: true }); +}); + +describe("LocalStorageAdapter", () => { + it("builds owner/project scoped object keys and stores uploads under S1_STORAGE_ROOT", async () => { + const data = Buffer.from("hello", "utf8"); + const stored = await adapter().putObject({ + ownerId: "creator-1", + projectId: "project-1", + objectName: "cover.txt", + mimeType: "text/plain", + bytes: data, + expectedSha256: sha256(data) + }); + + expect(stored.storageKey).toBe("owners/creator-1/projects/project-1/cover.txt"); + expect(stored.absolutePath.startsWith(root)).toBe(true); + await expect(readFile(stored.absolutePath, "utf8")).resolves.toBe("hello"); + }); + + it.each([ + ["path traversal", "../escape.txt"], + ["absolute paths", "/tmp/escape.txt"], + ["encoded separators", "folder%2Fescape.txt"], + ["encoded traversal", "%2e%2e/escape.txt"], + ["NUL bytes", "evil\u0000name.txt"] + ])("rejects %s", async (_label, objectName) => { + const data = Buffer.from("blocked", "utf8"); + + await expect( + adapter().putObject({ + ownerId: "creator-1", + projectId: "project-1", + objectName, + mimeType: "text/plain", + bytes: data, + expectedSha256: sha256(data) + }) + ).rejects.toMatchObject({ code: "INVALID_STORAGE_KEY" }); + }); + + it("rejects symlink and realpath escapes outside S1_STORAGE_ROOT", async () => { + await mkdir(path.join(outside, "target"), { recursive: true }); + await symlink(path.join(outside, "target"), path.join(root, "owners")); + const data = Buffer.from("escape", "utf8"); + + await expect( + adapter().putObject({ + ownerId: "creator-1", + projectId: "project-1", + objectName: "escape.txt", + mimeType: "text/plain", + bytes: data, + expectedSha256: sha256(data) + }) + ).rejects.toMatchObject({ code: "STORAGE_ROOT_ESCAPE" }); + + await expect(readdir(path.join(outside, "target"))).resolves.toEqual([]); + }); + + it("enforces MIME allowlist, max size, checksum validation, and temporary cleanup", async () => { + const data = Buffer.from("hello", "utf8"); + + await expect( + adapter({ mimeTypes: ["image/png"] }).putObject({ + ownerId: "creator-1", + projectId: "project-1", + objectName: "file.txt", + mimeType: "text/plain", + bytes: data, + expectedSha256: sha256(data) + }) + ).rejects.toMatchObject({ code: "MIME_NOT_ALLOWED" }); + + await expect( + adapter({ maxBytes: 2 }).putObject({ + ownerId: "creator-1", + projectId: "project-1", + objectName: "large.txt", + mimeType: "text/plain", + bytes: data, + expectedSha256: sha256(data) + }) + ).rejects.toMatchObject({ code: "FILE_TOO_LARGE" }); + + await expect( + adapter().putObject({ + ownerId: "creator-1", + projectId: "project-1", + objectName: "bad-checksum.txt", + mimeType: "text/plain", + bytes: data, + expectedSha256: "0".repeat(64) + }) + ).rejects.toMatchObject({ code: "CHECKSUM_MISMATCH" }); + + await expect(readFile(path.join(root, "owners/creator-1/projects/project-1/bad-checksum.txt"))).rejects.toThrow(); + await writeFile(path.join(root, "leftover.tmp"), "manual"); + await expect(readFile(path.join(root, "leftover.tmp"), "utf8")).resolves.toBe("manual"); + }); +}); diff --git a/apps/api/src/prisma.schema.spec.ts b/apps/api/src/prisma.schema.spec.ts new file mode 100644 index 00000000..46856919 --- /dev/null +++ b/apps/api/src/prisma.schema.spec.ts @@ -0,0 +1,800 @@ +import { execFile } from "node:child_process"; +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { promisify } from "node:util"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { Prisma, PrismaClient } from "./generated/prisma/client.js"; +import { afterAll, describe, expect, it } from "vitest"; + +const execFileAsync = promisify(execFile); +const databaseUrl = process.env.DATABASE_URL ?? "postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public"; +const adapter = new PrismaPg({ connectionString: databaseUrl }); +const prisma = new PrismaClient({ adapter }); +const runId = `task4-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`; +const rollbackToken = Symbol("rollback test transaction"); +type DbClient = Prisma.TransactionClient; +let savepointSequence = 0; + +const workspaceRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../.."); +const harnessCli = path.join(workspaceRoot, "harness/scripts/validate-harness.mjs"); + +// S0 harness 的 AgentTask 校验依赖 fixture context,这里使用 fixture 兼容 ID 单独验证投影。 +const s0SessionSeed = { + id: "session-main-creation-001", + creatorId: "creator-demo-001", + projectId: "project-s0-simulation-001", + versionId: "version-s0-simulation-001", + status: "routing_internal_tasks", + contextSummary: "Creator asked for a lightweight simulation game with short sessions and mobile-first controls.", + createdAt: new Date("2026-06-01T01:55:00.000Z"), + updatedAt: new Date("2026-06-01T02:00:00.000Z") +}; + +const s0TaskSeed = { + id: "agent-task-requirement-clarifier-001", + sessionId: "session-main-creation-001", + taskType: "requirement_clarifier", + subagentId: "subagent-requirement-clarifier-001", + inputRef: "prompt-record-s0-001", + outputRef: "requirement-brief-simulation-001", + status: "succeeded", + timeoutAt: new Date("2026-06-01T02:10:00.000Z"), + errorCode: null, + auditLogId: "audit-agent-task-requirement-clarifier-001", + createdAt: new Date("2026-06-01T01:56:00.000Z"), + updatedAt: new Date("2026-06-01T01:58:00.000Z") +}; + +function iso(value: Date): string { + return value.toISOString(); +} + +// Prisma row 不能直接作为 S0 DTO 暴露;投影函数只输出 S0 schema 允许字段。 +function projectSession(row: { + id: string; + creatorId: string; + projectId: string; + versionId: string; + status: string; + contextSummary: string; + createdAt: Date; + updatedAt: Date; +}) { + return { + id: row.id, + creatorId: row.creatorId, + projectId: row.projectId, + versionId: row.versionId, + status: row.status, + contextSummary: row.contextSummary, + createdAt: iso(row.createdAt), + updatedAt: iso(row.updatedAt) + }; +} + +function projectTask(row: { + id: string; + sessionId: string; + taskType: string; + subagentId: string; + inputRef: string; + outputRef: string | null; + status: string; + timeoutAt: Date; + errorCode: string | null; + auditLogId: string; + createdAt: Date; + updatedAt: Date; +}) { + return { + id: row.id, + sessionId: row.sessionId, + taskType: row.taskType, + subagentId: row.subagentId, + inputRef: row.inputRef, + outputRef: row.outputRef, + status: row.status, + timeoutAt: iso(row.timeoutAt), + errorCode: row.errorCode, + auditLogId: row.auditLogId, + createdAt: iso(row.createdAt), + updatedAt: iso(row.updatedAt) + }; +} + +function projectLifecycle(row: { + eventId: string; + event: string; + from: string; + to: string; + actorJson: Prisma.JsonValue; + requiredRole: string; + requiredRecordRefsJson: Prisma.JsonValue; + auditEvent: string; + reasonCode: string; + occurredAt: Date; + approval: string; + requiredRecordsJson: Prisma.JsonValue; +}) { + return { + eventId: row.eventId, + event: row.event, + from: row.from, + to: row.to, + actor: row.actorJson, + requiredRole: row.requiredRole, + requiredRecordRefs: row.requiredRecordRefsJson, + auditEvent: row.auditEvent, + reasonCode: row.reasonCode, + occurredAt: iso(row.occurredAt), + approval: row.approval, + requiredRecords: row.requiredRecordsJson + }; +} + +async function withTempJson(value: unknown, run: (file: string) => Promise): Promise { + const dir = await mkdtemp(path.join(os.tmpdir(), "huijing-prisma-")); + const file = path.join(dir, "payload.json"); + await writeFile(file, JSON.stringify(value, null, 2), "utf8"); + try { + return await run(file); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +async function expectHarnessContract(contract: string, value: unknown): Promise { + await withTempJson(value, async (file) => { + const result = await execFileAsync("node", [harnessCli, "--contract", contract, "--input", file], { + cwd: workspaceRoot + }); + expect(JSON.parse(result.stdout)).toEqual({ ok: true, reasonCode: null }); + }); +} + +async function expectHarnessTransition(transition: string, value: unknown): Promise { + await withTempJson(value, async (file) => { + const result = await execFileAsync("node", [harnessCli, "--transition", transition, "--input", file], { + cwd: workspaceRoot + }); + expect(JSON.parse(result.stdout)).toEqual({ ok: true, reasonCode: null }); + }); +} + +async function expectPrismaRejectedInSavepoint( + db: DbClient, + action: () => Promise, + pattern: RegExp +): Promise { + const savepointName = `task4_sp_${++savepointSequence}`; + await db.$executeRawUnsafe(`SAVEPOINT ${savepointName}`); + + let caught: unknown; + try { + await action(); + } catch (error) { + caught = error; + } + + await db.$executeRawUnsafe(`ROLLBACK TO SAVEPOINT ${savepointName}`); + await db.$executeRawUnsafe(`RELEASE SAVEPOINT ${savepointName}`); + + if (caught === undefined) { + throw new Error(`Expected Prisma action to reject with ${pattern}`); + } + expect(() => { + throw caught; + }).toThrow(pattern); +} + +// Task 4 只允许测试 setup 使用事务本地 guard,不提供生产 state-transition helper。 +async function withStateGuard(db: DbClient, callback: () => Promise): Promise { + await db.$executeRawUnsafe("SELECT set_config('app.state_transition_guard', 'on', true)"); + const result = await callback(); + await db.$executeRawUnsafe("SELECT set_config('app.state_transition_guard', '', true)"); + return result; +} + +async function withRollback(callback: (tx: DbClient) => Promise): Promise { + try { + await prisma.$transaction(async (tx) => { + await callback(tx); + throw rollbackToken; + }); + } catch (error) { + if (error !== rollbackToken) throw error; + } +} + +async function seedProjectSet(db: DbClient, prefix: string) { + const scopedPrefix = `${runId}-${prefix}`; + const creator = await db.user.create({ + data: { + id: `${scopedPrefix}-creator`, + email: `${scopedPrefix}@example.test`, + displayName: `${prefix} creator` + } + }); + + const operator = await db.user.create({ + data: { + id: `${scopedPrefix}-operator`, + email: `${scopedPrefix}-operator@example.test`, + displayName: `${prefix} operator` + } + }); + + const project = await db.gameProject.create({ + data: { + id: `${scopedPrefix}-project`, + ownerId: creator.id, + slug: `${scopedPrefix}-project`, + title: `${prefix} project` + } + }); + + const version = await insertGameVersion(db, project.id, `${scopedPrefix}-version`, 1); + + return { creator, operator, project, version }; +} + +async function seedS0FixtureProjectSet(db: DbClient) { + const creator = await db.user.create({ + data: { + id: s0SessionSeed.creatorId, + email: `${runId}-creator-demo-001@example.test`, + displayName: "S0 fixture creator" + } + }); + + const project = await db.gameProject.create({ + data: { + id: s0SessionSeed.projectId, + ownerId: creator.id, + slug: `${runId}-${s0SessionSeed.projectId}`, + title: "S0 simulation project" + } + }); + + const version = await insertGameVersion(db, project.id, s0SessionSeed.versionId, 1); + + return { creator, project, version }; +} + +async function insertGameVersion(db: DbClient, projectId: string, id: string, versionNumber: number) { + return withStateGuard(db, () => + db.gameVersion.create({ + data: { + id, + projectId, + versionNumber, + status: "draft", + configJson: { seed: id } + } + }) + ); +} + +describe("Prisma core database model", () => { + afterAll(async () => { + await prisma.$disconnect(); + }); + + it("stores S0-compatible session and task anchors and passes the S0 CLI projection checks", async () => { + await withRollback(async (tx) => { + await seedS0FixtureProjectSet(tx); + const session = await tx.mainCreationAgentSession.create({ + data: { + ...s0SessionSeed + } + }); + + const task = await tx.agentTask.create({ + data: { + ...s0TaskSeed, + sessionId: session.id + } + }); + + await expectHarnessContract("MainCreationAgentSession", projectSession(session)); + await expectHarnessContract("AgentTask", projectTask(task)); + }); + }); + + it("anchors arbitrary DB session and task rows to their actual owner, project, version, and parent session", async () => { + await withRollback(async (tx) => { + const seeded = await seedProjectSet(tx, "relationship-integrity"); + const session = await tx.mainCreationAgentSession.create({ + data: { + id: `${runId}-relationship-integrity-session`, + creatorId: seeded.creator.id, + projectId: seeded.project.id, + versionId: seeded.version.id, + status: "routing_internal_tasks", + contextSummary: "Arbitrary relationship integrity anchor" + } + }); + + const task = await tx.agentTask.create({ + data: { + id: `${runId}-relationship-integrity-task`, + sessionId: session.id, + taskType: "requirement_clarifier", + subagentId: "subagent-requirement-clarifier-001", + inputRef: "relationship-integrity-input", + outputRef: null, + status: "queued", + timeoutAt: new Date("2026-06-01T04:00:00.000Z"), + auditLogId: `${runId}-audit-relationship-integrity-task` + } + }); + + const anchoredSession = await tx.mainCreationAgentSession.findUniqueOrThrow({ + where: { id: session.id }, + include: { + creator: true, + project: true, + version: true, + tasks: true + } + }); + + expect(anchoredSession.creator.id).toBe(seeded.creator.id); + expect(anchoredSession.project.id).toBe(seeded.project.id); + expect(anchoredSession.version.id).toBe(seeded.version.id); + expect(anchoredSession.tasks.map((item) => item.id)).toEqual([task.id]); + }); + }); + + it("rejects session anchors when projectId and versionId point at different projects", async () => { + await withRollback(async (tx) => { + const first = await seedProjectSet(tx, "session-first"); + const second = await seedProjectSet(tx, "session-second"); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.mainCreationAgentSession.create({ + data: { + id: `${runId}-session-project-mismatch`, + creatorId: first.creator.id, + projectId: first.project.id, + versionId: second.version.id, + status: "routing_internal_tasks", + contextSummary: "Mismatched session anchor" + } + }), + /Foreign key constraint violated/ + ); + }); + }); + + it("enforces enums, task allowlist, timeout, failure, and audit anchor fields at the DB boundary", async () => { + await withRollback(async (tx) => { + const seeded = await seedProjectSet(tx, "task-policy"); + const session = await tx.mainCreationAgentSession.create({ + data: { + id: `${runId}-task-policy-session`, + creatorId: seeded.creator.id, + projectId: seeded.project.id, + versionId: seeded.version.id, + status: "routing_internal_tasks", + contextSummary: "Task policy anchor" + } + }); + + const failedTask = await tx.agentTask.create({ + data: { + id: `${runId}-task-policy-failed-task`, + sessionId: session.id, + taskType: "game_design_draft_generator", + subagentId: "subagent-game-draft-001", + inputRef: "requirement-brief-simulation-001", + outputRef: null, + status: "failed", + timeoutAt: new Date("2026-06-01T04:30:00.000Z"), + errorCode: "SUBAGENT_TIMEOUT", + auditLogId: `${runId}-audit-task-policy-failed` + } + }); + + expect(failedTask.errorCode).toBe("SUBAGENT_TIMEOUT"); + expect(failedTask.auditLogId).toBe(`${runId}-audit-task-policy-failed`); + expect(failedTask.timeoutAt.toISOString()).toBe("2026-06-01T04:30:00.000Z"); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.agentTask.create({ + data: { + id: `${runId}-task-policy-invalid-pair`, + sessionId: session.id, + taskType: "requirement_clarifier", + subagentId: "subagent-game-draft-001", + inputRef: "prompt-record-s0-001", + outputRef: null, + status: "queued", + timeoutAt: new Date("2026-06-01T04:40:00.000Z"), + auditLogId: `${runId}-audit-task-policy-invalid` + } + }), + /AgentTask_task_subagent_allowlist_check/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.$executeRawUnsafe( + `INSERT INTO "GameVersion" ("id", "projectId", "versionNumber", "status", "configJson") + VALUES ('${runId}-task-policy-bad-status', '${seeded.project.id}', 99, 'pending_review', '{}'::jsonb)` + ), + /invalid input value for enum/ + ); + }); + }); + + it("rejects invalid Job target shapes and enforces scoped idempotency", async () => { + await withRollback(async (tx) => { + const first = await seedProjectSet(tx, "job-first"); + const second = await seedProjectSet(tx, "job-second"); + + await tx.job.create({ + data: { + id: `${runId}-job-project-valid`, + actorId: first.creator.id, + projectId: first.project.id, + type: "build_project", + idempotencyKey: "idem-1", + targetType: "project", + targetId: first.project.id, + targetScopeKey: `project:${first.project.id}`, + gameProjectId: first.project.id, + payloadJson: { ok: true } + } + }); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.job.create({ + data: { + id: `${runId}-job-project-duplicate`, + actorId: first.creator.id, + projectId: first.project.id, + type: "build_project", + idempotencyKey: "idem-1", + targetType: "project", + targetId: first.project.id, + targetScopeKey: `project:${first.project.id}`, + gameProjectId: first.project.id, + payloadJson: { ok: true } + } + }), + /Unique constraint failed/ + ); + + await tx.job.create({ + data: { + id: `${runId}-job-project-same-key-other-actor`, + actorId: second.creator.id, + projectId: first.project.id, + type: "build_project", + idempotencyKey: "idem-1", + targetType: "project", + targetId: first.project.id, + targetScopeKey: `project:${first.project.id}`, + gameProjectId: first.project.id, + payloadJson: { ok: true } + } + }); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.job.create({ + data: { + id: `${runId}-job-project-xor-invalid`, + actorId: first.creator.id, + projectId: first.project.id, + type: "build_project", + idempotencyKey: "idem-xor", + targetType: "project", + targetId: first.project.id, + targetScopeKey: `project:${first.project.id}`, + gameProjectId: first.project.id, + gameVersionId: first.version.id, + payloadJson: { invalid: true } + } + }), + /Job_target_xor_check/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.job.create({ + data: { + id: `${runId}-job-project-targetid-invalid`, + actorId: first.creator.id, + projectId: first.project.id, + type: "build_project", + idempotencyKey: "idem-targetid", + targetType: "project", + targetId: second.project.id, + targetScopeKey: `project:${first.project.id}`, + gameProjectId: first.project.id, + payloadJson: { invalid: true } + } + }), + /Job_target_id_matches_check/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.job.create({ + data: { + id: `${runId}-job-project-scope-invalid`, + actorId: first.creator.id, + projectId: second.project.id, + type: "build_project", + idempotencyKey: "idem-scope", + targetType: "project", + targetId: first.project.id, + targetScopeKey: `project:${first.project.id}`, + gameProjectId: first.project.id, + payloadJson: { invalid: true } + } + }), + /Job_project_scope_matches_check/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.job.create({ + data: { + id: `${runId}-job-version-scope-invalid`, + actorId: first.creator.id, + projectId: second.project.id, + type: "build_version", + idempotencyKey: "idem-version-scope", + targetType: "version", + targetId: first.version.id, + targetScopeKey: `version:${first.version.id}`, + gameVersionId: first.version.id, + payloadJson: { invalid: true } + } + }), + /Foreign key constraint violated/ + ); + }); + }); + + it("enforces ReviewRecord decision evidence for approved, rejected, pending, and canceled states", async () => { + await withRollback(async (tx) => { + const seeded = await seedProjectSet(tx, "review-evidence"); + + await expectPrismaRejectedInSavepoint( + tx, + () => + withStateGuard(tx, () => + tx.reviewRecord.create({ + data: { + id: `${runId}-review-approved-missing-decision`, + gameVersionId: seeded.version.id, + status: "approved", + reasonCode: "approved_for_publish", + decidedById: seeded.operator.id, + decidedAt: new Date("2026-06-01T05:01:00.000Z") + } + }) + ), + /ReviewRecord_decision_reason_check/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + withStateGuard(tx, () => + tx.reviewRecord.create({ + data: { + id: `${runId}-review-rejected-missing-evidence`, + gameVersionId: seeded.version.id, + status: "rejected", + decision: "rejected", + reasonCode: " ", + decidedById: seeded.operator.id, + decidedAt: new Date("2026-06-01T05:02:00.000Z") + } + }) + ), + /ReviewRecord_decision_reason_check/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + withStateGuard(tx, () => + tx.reviewRecord.create({ + data: { + id: `${runId}-review-pending-with-decision`, + gameVersionId: seeded.version.id, + status: "pending_review", + decision: "approved", + reasonCode: "approved_for_publish", + decidedById: seeded.operator.id, + decidedAt: new Date("2026-06-01T05:03:00.000Z") + } + }) + ), + /ReviewRecord_decision_reason_check/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + withStateGuard(tx, () => + tx.reviewRecord.create({ + data: { + id: `${runId}-review-canceled-with-decision`, + gameVersionId: seeded.version.id, + status: "canceled", + decision: "rejected", + reasonCode: "needs_design_changes", + decidedById: seeded.operator.id, + decidedAt: new Date("2026-06-01T05:04:00.000Z") + } + }) + ), + /ReviewRecord_decision_reason_check/ + ); + }); + }); + + it("blocks direct guarded state writes, lifecycle deletes, and audit mutations without the transaction guard", async () => { + await withRollback(async (tx) => { + const seeded = await seedProjectSet(tx, "guard-policy"); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.gameVersion.create({ + data: { + id: `${runId}-guard-policy-direct-version`, + projectId: seeded.project.id, + versionNumber: 2, + status: "draft", + configJson: {} + } + }), + /state transition guard is required/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.gameVersion.update({ + where: { id: seeded.version.id }, + data: { status: "candidate" } + }), + /state transition guard is required/ + ); + + const review = await withStateGuard(tx, () => + tx.reviewRecord.create({ + data: { + id: `${runId}-guard-policy-review-approved`, + gameVersionId: seeded.version.id, + status: "approved", + decision: "approved", + reasonCode: "approved_for_publish", + decidedById: seeded.operator.id, + decidedAt: new Date("2026-06-01T05:00:00.000Z") + } + }) + ); + expect(review.reasonCode).toBe("approved_for_publish"); + + await expectPrismaRejectedInSavepoint( + tx, + () => + tx.reviewRecord.update({ + where: { id: review.id }, + data: { status: "rejected", decision: "rejected", reasonCode: "needs_fix" } + }), + /state transition guard is required/ + ); + + await expectPrismaRejectedInSavepoint( + tx, + () => + withStateGuard(tx, () => + tx.reviewRecord.create({ + data: { + id: `${runId}-guard-policy-review-missing-reason`, + gameVersionId: seeded.version.id, + status: "approved", + decision: "approved", + reasonCode: null, + decidedById: seeded.operator.id, + decidedAt: new Date("2026-06-01T05:01:00.000Z") + } + }) + ), + /ReviewRecord_decision_reason_check/ + ); + + const lifecycle = await withStateGuard(tx, () => + tx.lifecycleEvent.create({ + data: { + eventId: `${runId}-guard-policy-review-approved-event`, + gameVersionId: seeded.version.id, + event: "review_approved", + from: "pending_review", + to: "publish_ready", + actorJson: { role: "operator", operatorId: seeded.operator.id }, + requiredRole: "operator", + requiredRecordRefsJson: [review.id], + auditEvent: "lifecycle.review_approved", + reasonCode: "approved_for_publish", + approval: "operator", + requiredRecordsJson: ["ReviewRecord.decision=approved", "ReviewRecord.reasonCode"], + occurredAt: new Date("2026-06-01T05:02:00.000Z") + } + }) + ); + + await expectHarnessContract("LifecycleEvent", projectLifecycle(lifecycle)); + await expectHarnessTransition("review_approved", projectLifecycle(lifecycle)); + + const rejectedLifecycle = await withStateGuard(tx, () => + tx.lifecycleEvent.create({ + data: { + eventId: `${runId}-guard-policy-review-rejected-event`, + gameVersionId: seeded.version.id, + event: "review_rejected", + from: "pending_review", + to: "rejected", + actorJson: { role: "operator", operatorId: seeded.operator.id }, + requiredRole: "operator", + requiredRecordRefsJson: [`${runId}-review-rejected-001`], + auditEvent: "lifecycle.review_rejected", + reasonCode: "needs_design_changes", + approval: "operator", + requiredRecordsJson: ["ReviewRecord.decision=rejected", "ReviewRecord.reasonCode"], + occurredAt: new Date("2026-06-01T05:03:00.000Z") + } + }) + ); + + await expectHarnessTransition("review_rejected", projectLifecycle(rejectedLifecycle)); + + await expectPrismaRejectedInSavepoint( + tx, + () => tx.lifecycleEvent.delete({ where: { eventId: lifecycle.eventId } }), + /state transition guard is required/ + ); + + const audit = await tx.auditLog.create({ + data: { + id: `${runId}-guard-policy-audit`, + actorId: seeded.operator.id, + action: "lifecycle.review_approved", + targetType: "GameVersion", + targetId: seeded.version.id, + eventJson: { reviewRecordId: review.id } + } + }); + + await expectPrismaRejectedInSavepoint( + tx, + () => tx.auditLog.update({ where: { id: audit.id }, data: { action: "changed" } }), + /AuditLog is append-only/ + ); + await expectPrismaRejectedInSavepoint(tx, () => tx.auditLog.delete({ where: { id: audit.id } }), /AuditLog is append-only/); + }); + }); +}); diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json new file mode 100644 index 00000000..54e02583 --- /dev/null +++ b/apps/api/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "rootDir": "src", + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist", "src/**/*.spec.ts"] +} diff --git a/apps/web/next-env.d.ts b/apps/web/next-env.d.ts new file mode 100644 index 00000000..9edff1c7 --- /dev/null +++ b/apps/web/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +import "./.next/types/routes.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs new file mode 100644 index 00000000..9e31d41c --- /dev/null +++ b/apps/web/next.config.mjs @@ -0,0 +1,5 @@ +const nextConfig = { + transpilePackages: ["@huijing/shared-contracts"] +}; + +export default nextConfig; diff --git a/apps/web/package.json b/apps/web/package.json new file mode 100644 index 00000000..e0118f92 --- /dev/null +++ b/apps/web/package.json @@ -0,0 +1,25 @@ +{ + "name": "@huijing/web", + "private": true, + "type": "module", + "scripts": { + "dev": "next dev", + "lint": "eslint .", + "typecheck": "tsc --noEmit", + "test": "vitest run", + "build": "next build", + "dev:smoke": "next build" + }, + "dependencies": { + "@huijing/shared-contracts": "workspace:*", + "next": "^16.2.6", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "@types/react": "^19.2.15", + "@types/react-dom": "^19.2.3", + "vitest": "^4.1.7" + } +} diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx new file mode 100644 index 00000000..54424335 --- /dev/null +++ b/apps/web/src/app/layout.tsx @@ -0,0 +1,11 @@ +import type { ReactNode } from "react"; +import { createElement } from "react"; + +export const metadata = { + description: "Huijing AI app foundation", + title: "Huijing AI" +}; + +export default function RootLayout({ children }: { readonly children: ReactNode }) { + return createElement("html", { lang: "en" }, createElement("body", null, children)); +} diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx new file mode 100644 index 00000000..8a46cf15 --- /dev/null +++ b/apps/web/src/app/page.tsx @@ -0,0 +1,11 @@ +import { createElement } from "react"; +import { S1_PACKAGE_NAMES } from "@huijing/shared-contracts"; + +export default function HomePage() { + return createElement( + "main", + { "data-package": S1_PACKAGE_NAMES.web }, + createElement("h1", null, "Huijing AI App Foundation"), + createElement("p", null, `${S1_PACKAGE_NAMES.web} is ready.`) + ); +} diff --git a/apps/web/src/smoke.test.ts b/apps/web/src/smoke.test.ts new file mode 100644 index 00000000..41dafee2 --- /dev/null +++ b/apps/web/src/smoke.test.ts @@ -0,0 +1,25 @@ +import type { ReactElement, ReactNode } from "react"; +import { describe, expect, it } from "vitest"; +import RootLayout from "./app/layout"; +import HomePage from "./app/page"; + +describe("@huijing/web smoke", () => { + it("returns an App Router root layout with html and body elements", () => { + const layout = RootLayout({ children: "content" }) as unknown as ReactElement<{ + children: ReactElement<{ children: ReactNode }>; + lang: string; + }>; + + expect(layout.type).toBe("html"); + expect(layout.props.lang).toBe("en"); + expect(layout.props.children.type).toBe("body"); + expect(layout.props.children.props.children).toBe("content"); + }); + + it("renders the web package identity on the home page", () => { + const page = HomePage() as ReactElement<{ "data-package": string }>; + + expect(page.type).toBe("main"); + expect(page.props["data-package"]).toBe("@huijing/web"); + }); +}); diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json new file mode 100644 index 00000000..7ac02416 --- /dev/null +++ b/apps/web/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "allowJs": false, + "jsx": "preserve", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "noEmit": true, + "plugins": [{ "name": "next" }], + "types": ["node", "react", "react-dom"] + }, + "include": ["next-env.d.ts", ".next/types/**/*.ts", "src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/apps/worker/.env.example b/apps/worker/.env.example new file mode 100644 index 00000000..2f7a5567 --- /dev/null +++ b/apps/worker/.env.example @@ -0,0 +1,5 @@ +DATABASE_URL=postgresql://huijing:huijing@localhost:5432/huijing_dev?schema=public +REDIS_URL=redis://localhost:6379 +QUEUE_ADAPTER=bullmq +S1_STORAGE_ROOT=.local/storage +HARNESS_CLI_TIMEOUT_MS=5000 diff --git a/apps/worker/package.json b/apps/worker/package.json new file mode 100644 index 00000000..c7c05ec2 --- /dev/null +++ b/apps/worker/package.json @@ -0,0 +1,16 @@ +{ + "name": "@huijing/worker", + "private": true, + "type": "module", + "scripts": { + "lint": "eslint .", + "typecheck": "tsc --noEmit", + "test": "vitest run", + "build": "tsc -p tsconfig.json", + "dev:smoke": "vitest run" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "vitest": "^4.1.7" + } +} diff --git a/apps/worker/src/index.ts b/apps/worker/src/index.ts new file mode 100644 index 00000000..a7536250 --- /dev/null +++ b/apps/worker/src/index.ts @@ -0,0 +1,40 @@ +export interface WorkerSmokeStatus { + readonly packageName: "@huijing/worker"; + readonly queue: "none" | "memory"; + readonly status: "idle"; +} + +export interface WorkerQueueMessage { + readonly jobId: string; + readonly type: "noop"; + readonly payload: unknown; +} + +export interface WorkerNoopSmokeResult { + readonly processed: number; + readonly jobTypes: readonly string[]; +} + +export function getWorkerSmokeStatus(): WorkerSmokeStatus { + return { + packageName: "@huijing/worker", + queue: "none", + status: "idle" + }; +} + +export async function runNoopWorkerSmoke(): Promise { + const messages: WorkerQueueMessage[] = [{ jobId: "worker-smoke-noop", type: "noop", payload: {} }]; + const processed: string[] = []; + + for (const message of messages) { + // S1 worker smoke 只证明 no-op queue handler 可运行;DB claim/complete 由 API JobExecutionStore 统一拥有。 + if (message.type !== "noop") continue; + processed.push(message.type); + } + + return { + processed: processed.length, + jobTypes: processed + }; +} diff --git a/apps/worker/src/worker.smoke.spec.ts b/apps/worker/src/worker.smoke.spec.ts new file mode 100644 index 00000000..7e706d02 --- /dev/null +++ b/apps/worker/src/worker.smoke.spec.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from "vitest"; +import { getWorkerSmokeStatus, runNoopWorkerSmoke } from "./index"; + +describe("@huijing/worker smoke", () => { + it("reports an idle no-op worker status", () => { + expect(getWorkerSmokeStatus()).toEqual({ + packageName: "@huijing/worker", + queue: "none", + status: "idle" + }); + }); + + it("processes one no-op queue message without importing Prisma or mutating guarded state", async () => { + await expect(runNoopWorkerSmoke()).resolves.toEqual({ + processed: 1, + jobTypes: ["noop"] + }); + }); +}); diff --git a/apps/worker/tsconfig.json b/apps/worker/tsconfig.json new file mode 100644 index 00000000..43f2363b --- /dev/null +++ b/apps/worker/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist", "src/**/*.spec.ts"] +} diff --git a/docs/memorys/2026-06-01-S1Task1工作区初始化门禁.md b/docs/memorys/2026-06-01-S1Task1工作区初始化门禁.md new file mode 100644 index 00000000..76672afd --- /dev/null +++ b/docs/memorys/2026-06-01-S1Task1工作区初始化门禁.md @@ -0,0 +1,81 @@ +# 2026-06-01 S1 Task 1 工作区初始化门禁 + +## 结论 + +S1 Task 1 `Initialize Workspace` 已完成实现,并通过两轮 fresh review gate: + +- spec compliance review:PASS,无 blocking finding。 +- quality / feasibility review:PASS,无 blocking finding。 + +可以进入 S1 Task 2。 + +## 前置基线 + +Task 1 开始前,工作树已有 `.idea/`、`docs-design/`、`docs/`、`harness/` 变更或未跟踪内容。它们是前置 dirty baseline,不属于 Task 1 delta;Task 1 未回退、清理或重写这些内容。 + +## 实现范围 + +Task 1 delta 仅包含: + +- `.gitignore` +- `package.json` +- `pnpm-workspace.yaml` +- `tsconfig.base.json` +- `eslint.config.mjs` +- `scripts/check-workspace-scripts.mjs` +- `pnpm-lock.yaml` + +未创建: + +- `apps/**` +- `packages/**` +- `scripts/check-s1-scope.mjs` + +## Review Gate + +| Gate | Reviewer ID | Result | Blocking findings | +| --- | --- | --- | --- | +| implementation | `019e80cd-cec9-7631-b131-7f93954b2808` | DONE | 无 | +| spec compliance initial | `019e80d3-9538-7a32-9ec9-c231ed27e478` | FAIL | 误把前置 dirty baseline 计入 Task 1 scope | +| spec compliance re-review | `019e80d9-075d-70e3-bd45-dad329715740` | PASS | 无 | +| quality / feasibility | `019e80de-5705-74f0-a04d-e29d0de4e659` | PASS | 无 | + +初次 spec review 的 Critical 是证据上下文问题,不是实现缺陷;补充 Task 1 前置 `git status --short` baseline 后,fresh re-review 判定 Task 1 delta 合规。 + +## Controller Verification + +已运行: + +```bash +node --check scripts/check-workspace-scripts.mjs +pnpm check:workspace-scripts +pnpm install --frozen-lockfile +pnpm exec eslint --print-config apps/example.ts >/dev/null +test ! -e scripts/check-s1-scope.mjs && test ! -d apps && test ! -d packages +``` + +结果: + +- `node --check scripts/check-workspace-scripts.mjs`:PASS。 +- `pnpm check:workspace-scripts`:PASS;当前没有 workspace packages。 +- `pnpm install --frozen-lockfile`:PASS;lockfile up to date。 +- `pnpm exec eslint --print-config apps/example.ts >/dev/null`:PASS;flat config 可解析。 +- forbidden path check:PASS;`apps/`、`packages/`、`scripts/check-s1-scope.mjs` 不存在。 + +未运行完整 `pnpm lint`、`pnpm typecheck`、`pnpm test`、`pnpm build`,因为 Task 2 才创建 workspace packages 和占位测试。 + +## SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `.gitignore` | `6dcd1666bf43e6f3abb664ad4aa511502a89f3500904fd059912dec73e516ae6` | +| `package.json` | `0e3d6edb70fe2317497ce883710d961eaa3df9b5b37cd0e2b53873633dabe92b` | +| `pnpm-workspace.yaml` | `08d75840c97ab0e72d1d9b5b84a17e47a2e06cb159a5fbec5ee0a6a56682dad7` | +| `tsconfig.base.json` | `0080d9633209d16b5328cfad0c9a4d4b63de70ffd65115bf5ef89a3c185f34c8` | +| `eslint.config.mjs` | `d055a4c012addf1b74db19811630b5a51d453dcf10d5366faf4d4aa0499c7a11` | +| `scripts/check-workspace-scripts.mjs` | `c46c16a1c07d8afbce8c4afd6bcee9804413298651729966f46f9f5109742eb7` | +| `pnpm-lock.yaml` | `3410b404ec3eab910cf0c7fb6aa74b6b63296f634fce2762e0ec3ce908b38eb9` | + +## 当前限制 + +`check:s1-scope` 仍指向未来的 `scripts/check-s1-scope.mjs`;这是 S1 plan 的预期安排,Task 9 才创建并验证该脚本。 diff --git a/docs/memorys/2026-06-01-S1Task2应用骨架门禁.md b/docs/memorys/2026-06-01-S1Task2应用骨架门禁.md new file mode 100644 index 00000000..a7693451 --- /dev/null +++ b/docs/memorys/2026-06-01-S1Task2应用骨架门禁.md @@ -0,0 +1,135 @@ +# 2026-06-01 S1 Task 2 应用骨架门禁 + +## 结论 + +S1 Task 2 `Scaffold Web, API, Worker, Shared Packages` 已完成实现,并通过两轮 fresh review gate: + +- spec compliance review:PASS,无 blocking finding。 +- quality / feasibility review:首次 FAIL,修复后 PASS,无 blocking finding。 + +可以进入 S1 Task 3。 + +## 前置基线 + +Task 2 开始前,工作树已有: + +- `.idea/`、`docs-design/`、`docs/`、`harness/` 前置 dirty baseline。 +- S1 Task 1 根 workspace 文件。 +- `docs/memorys/2026-06-01-S1Task1工作区初始化门禁.md`。 + +这些不属于 Task 2 delta;Task 2 未回退、清理或重写这些内容。 + +## 实现范围 + +Task 2 delta 包含: + +- `apps/web/**` +- `apps/api/**` +- `apps/worker/**` +- `packages/shared-contracts/**` +- `packages/harness-client/**` +- `pnpm-lock.yaml` + +保留的生成文件: + +- `apps/web/next-env.d.ts`:Next TypeScript build 支持文件。 + +未创建: + +- DB / Prisma schema。 +- Docker / dev infra。 +- auth / project modules。 +- worker queue implementation。 +- harness CLI integration。 +- `scripts/check-s1-scope.mjs`。 +- game generation / runtime / WebPlatformAdapter / storage / RBAC 实现。 + +## Review Gate + +| Gate | Reviewer ID | Result | Blocking findings | +| --- | --- | --- | --- | +| implementation | `019e80e5-9503-7d31-aecc-f9cb4232db24` | DONE_WITH_CONCERNS -> DONE | pnpm ignored build scripts 作为后续 Prisma 风险记录 | +| spec compliance initial | `019e80fb-c82b-7a21-98c0-9a557bae20c0` | PASS | 无 | +| quality / feasibility initial | `019e8102-eadf-7673-ba2f-c47372a13216` | FAIL | API ESM build artifact 不能被 Node load | +| spec compliance re-review | `019e8112-3f05-7de3-95ed-96ce7e8ec144` | PASS | 无 | +| quality / feasibility re-review | `019e8118-6796-74d0-ae4e-f24b4083b6d6` | PASS | 无 | + +## 关键修复 + +初次 quality review 发现 `@huijing/api` 在 ESM + extensionless import 下,`pnpm build` 能成功但 `node apps/api/dist/main.js` 失败,报 `ERR_MODULE_NOT_FOUND`。 + +已修复: + +- `apps/api/tsconfig.json` 使用 `module: "NodeNext"` 和 `moduleResolution: "NodeNext"`。 +- API 相对 import 改为 `.js` specifier。 +- `apps/api/src/main.ts` 只在直接执行时启动 Nest server;被 import 时不会启动长运行进程。 +- `apps/api/package.json` 的 `build` 加入 `node -e "await import('./dist/main.js')"`,确保 API 编译产物可被 Node bounded load。 + +## Controller Verification + +控制器在临时镜像 `/tmp/games-s1-task2-controller.*` 中运行完整验证,避免在原工作区留下 build artifacts: + +```bash +pnpm install --frozen-lockfile +pnpm check:workspace-scripts +pnpm lint +pnpm typecheck +pnpm test +pnpm build +pnpm dev:smoke +cd apps/api && node -e "await import('./dist/main.js')" +``` + +结果: + +- `pnpm install --frozen-lockfile`:PASS。 +- `pnpm check:workspace-scripts`:PASS。 +- `pnpm lint`:PASS。 +- `pnpm typecheck`:PASS。 +- `pnpm test`:PASS,5 个 test files / 7 个 tests。 +- `pnpm build`:PASS,包含 API dist import-load check 和 Next build。 +- `pnpm dev:smoke`:PASS,bounded Vitest / Next build smoke。 +- `node -e "await import('./dist/main.js')"`:PASS。 + +安装时 pnpm 仍提示 ignored build scripts:`@nestjs/core`、`@prisma/engines`、`prisma`、`sharp`。Task 2 review 判定这不是当前阻塞;Task 4/Prisma 接入前必须显式验证 Prisma CLI/engine 行为。 + +原工作区 build hygiene: + +- `apps/**` / `packages/**` 下无 `dist`、`.next`、`coverage`、`.turbo`、`tsconfig.tsbuildinfo` 残留。 +- `node_modules` 存在于 pnpm 安装面,但已被 `.gitignore` 忽略。 + +## SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `apps/api/package.json` | `c196bf57ce0620678bba85bb120560ac57c328ce939feab81b2c20fe2236cece` | +| `apps/api/tsconfig.json` | `3bd816db2ad470383908e05caeaa6d09f70a442faa048f5fa37a048a3f833dba` | +| `apps/api/src/main.ts` | `fcefc7c057d211b11f890477a9a0017ea4a3d4ed41c34e93dc1be271f8212d58` | +| `apps/api/src/app.module.ts` | `801f76ed55d6a68c16b602ab1de2383102d3360ebc0a6d4187381e7972475056` | +| `apps/api/src/health.controller.ts` | `148a766072bdc8fd82196d0e12a570d819ef73e3790e486b8382423820f12640` | +| `apps/api/src/health.controller.spec.ts` | `55951223829eee0337b7f2cdbcdbc59e91dc3d16e7f5c8b2cb23bff5d6a31818` | +| `apps/web/package.json` | `8f98a78d0ae0568784eb5d2030d969245e5557726716ff4b754bf475a6548e28` | +| `apps/web/tsconfig.json` | `aea53dc64ec13851d4ae402eecdc72877e1dbe49683b0f766eb6b22418b0725f` | +| `apps/web/next.config.mjs` | `bbd5d4d14444fa08710ea17b600f194281abc880700bfd66cf088477a7f54c16` | +| `apps/web/next-env.d.ts` | `7b550dda9686c16f36a17bf9051d5dbf31e98555b30d114ac49fc49a1e712651` | +| `apps/web/src/app/layout.tsx` | `d895c441c61e964e0c59d68cfb6f6d596bd80b0430676496b2c4dfd1d77e97ba` | +| `apps/web/src/app/page.tsx` | `476da146bb7fa7164404af6bf24d6b4b65bdcd1a8c92a7b9a9488a6a59fdfb61` | +| `apps/web/src/smoke.test.ts` | `0c26e88a463147d8542f2ab59485907a8b396ea53a9c7349b99ed22a7c17fd87` | +| `apps/worker/package.json` | `5094f400f8a169a4375c392802402454fcc333576a026d491d58b5f79a8c1cf2` | +| `apps/worker/tsconfig.json` | `2f4be30e3b5a16e3912d3da11f257c8cce21c77af144655ce8cc20e17400cd25` | +| `apps/worker/src/index.ts` | `66e0389a61773e34d6b33b75dc24646785a5da16e73b30b49f065cd09cf24360` | +| `apps/worker/src/worker.smoke.spec.ts` | `081a4ad6d4a4ca2941faa895c0c4afd4a5cff5a2e66ba9656dd9c41824c3b91a` | +| `packages/shared-contracts/package.json` | `3f4b7503422a02075111877f69a62d5683c3c051acba744bc724a0600c6987bf` | +| `packages/shared-contracts/tsconfig.json` | `2f4be30e3b5a16e3912d3da11f257c8cce21c77af144655ce8cc20e17400cd25` | +| `packages/shared-contracts/src/index.ts` | `bacedef4146ed83fb306d52184d1a6373b121fc9aa1bb5a20ed1fbc398b23758` | +| `packages/shared-contracts/src/index.spec.ts` | `05fdb16cb210d7c5a03f8af530b902bf9522ffcccc4cc7892bbdd1a2407cb6a2` | +| `packages/harness-client/package.json` | `dae5f12bde880da0400c9023a6aa44519b96a33c2c011a6c38ed6e01d251e8bb` | +| `packages/harness-client/tsconfig.json` | `2f4be30e3b5a16e3912d3da11f257c8cce21c77af144655ce8cc20e17400cd25` | +| `packages/harness-client/src/index.ts` | `aa435bdb7f9027241968e6e04fc095cb73c32ee78ddd527f88193895eb5654f8` | +| `packages/harness-client/src/index.spec.ts` | `13c651235c0fe2571d6ed9209fcb15c55a37d98c94817652b5994f509364994a` | +| `pnpm-lock.yaml` | `9182ae05154e589711137d21b1a58afa54a28ecde5e0e7cb6d23cac3db69a4ab` | + +## 后续注意 + +- Task 4/Prisma 前必须处理或验证 pnpm ignored build scripts 对 Prisma engine 的影响。 +- `@huijing/harness-client` 当前是 fail-closed placeholder;Task 5 才接入 S0 CLI,不得提前把 placeholder 当作真实 validator。 diff --git a/docs/memorys/2026-06-01-S1Task3开发基础设施门禁.md b/docs/memorys/2026-06-01-S1Task3开发基础设施门禁.md new file mode 100644 index 00000000..46cd8c8f --- /dev/null +++ b/docs/memorys/2026-06-01-S1Task3开发基础设施门禁.md @@ -0,0 +1,78 @@ +# 2026-06-01 S1 Task 3 开发基础设施门禁 + +## 结论 + +S1 Task 3 `Add Development Infrastructure` 已完成实现,并通过两轮 fresh review gate: + +- spec compliance review:PASS,无 blocking finding。 +- quality / feasibility review:PASS,无 blocking finding。 + +可以进入 S1 Task 4。 + +## 前置基线 + +Task 3 开始前,工作树已有: + +- `.idea/`、`docs-design/`、`docs/`、`harness/` 前置 dirty baseline。 +- S1 Task 1 / Task 2 workspace 与 app skeleton 文件。 +- S1 Task 1 / Task 2 memory 留痕。 + +这些不属于 Task 3 delta;Task 3 未回退、清理或重写这些内容。 + +## 实现范围 + +Task 3 delta 仅包含: + +- `infra/docker-compose.dev.yml` +- `apps/api/.env.example` +- `apps/worker/.env.example` + +未创建: + +- DB schema / Prisma migration。 +- dev scripts / README / docs。 +- app code / queue / storage implementation。 +- 业务模块。 + +## Review Gate + +| Gate | Reviewer ID | Result | Blocking findings | +| --- | --- | --- | --- | +| implementation | `019e812c-3746-7e42-ad95-5be412def299` | DONE | 无 | +| spec compliance | `019e8132-4244-7f43-a275-63ab2e84b113` | PASS | 无 | +| quality / feasibility | `019e8134-d6d2-7d90-ae33-f27a642a0e1e` | PASS | 无 | + +## Controller Verification + +已运行: + +```bash +docker compose -f infra/docker-compose.dev.yml ps +docker compose -f infra/docker-compose.dev.yml exec -T postgres pg_isready -U huijing -d huijing_dev +docker compose -f infra/docker-compose.dev.yml exec -T postgres psql -U huijing -d huijing_dev -tAc 'select 1' +docker compose -f infra/docker-compose.dev.yml exec -T redis redis-cli ping +POSTGRES_PORT=15432 REDIS_PORT=16379 docker compose -f infra/docker-compose.dev.yml config +``` + +结果: + +- `infra-postgres-1`:`Up ... (healthy)`,端口 `0.0.0.0:5432->5432/tcp`。 +- `infra-redis-1`:`Up ... (healthy)`,端口 `0.0.0.0:6379->6379/tcp`。 +- `pg_isready`:`/var/run/postgresql:5432 - accepting connections`。 +- `psql select 1`:返回 `1`。 +- `redis-cli ping`:返回 `PONG`。 +- 端口覆盖配置可解析:`POSTGRES_PORT=15432` 映射到 target `5432`,`REDIS_PORT=16379` 映射到 target `6379`。 + +容器保持运行,供 Task 4 Prisma migration 使用。 + +## SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `infra/docker-compose.dev.yml` | `0bd44a47ed724c2a80ed0fc6e6923e2ed9d8800461027ee1261e6df0d5ebc67f` | +| `apps/api/.env.example` | `7a3101a09f29d3be684bdc2f7990c98b4d7e737af6055993d9a536bd028344ef` | +| `apps/worker/.env.example` | `7a3101a09f29d3be684bdc2f7990c98b4d7e737af6055993d9a536bd028344ef` | + +## 后续注意 + +Task 4 可直接复用当前运行中的 Postgres / Redis。若本机端口后续冲突,按 plan 使用 `POSTGRES_PORT` / `REDIS_PORT` 覆盖并记录验证证据。 diff --git a/docs/memorys/2026-06-01-S1Task4数据库模型门禁.md b/docs/memorys/2026-06-01-S1Task4数据库模型门禁.md new file mode 100644 index 00000000..f712a103 --- /dev/null +++ b/docs/memorys/2026-06-01-S1Task4数据库模型门禁.md @@ -0,0 +1,131 @@ +# 2026-06-01 S1 Task 4 数据库模型门禁 + +## 结论 + +S1 Task 4 `Implement Core Database Model` 已完成实现,并通过两轮 fresh review gate: + +- spec compliance review:最终 PASS,无 blocking finding。 +- quality / feasibility review:最终 PASS,无 blocking finding。 + +可以进入 S1 Task 5。 + +## 前置基线 + +Task 4 开始前,工作树已有: + +- `.idea/`、`docs-design/`、`docs/`、`harness/` 前置 dirty baseline。 +- S1 Task 1-3 workspace / app / infra 文件。 +- S1 Task 4 plan amendment:`docs/superpowers/plans/2026-05-31-mvp-S1-app-foundation.md`。 +- S1 Task 4 plan amendment memory:`docs/memorys/2026-06-01-S1Task4计划修正门禁.md`。 + +这些不属于 Task 4 implementation delta;Task 4 未回退、清理或重写这些内容。 + +## 实现范围 + +Task 4 delta 包含: + +- `apps/api/prisma/schema.prisma` +- `apps/api/prisma.config.ts` +- `apps/api/prisma/migrations/20260601040253_s1_app_foundation/migration.sql` +- `apps/api/prisma/migrations/20260601050132_s1_task4_quality_fixes/migration.sql` +- `apps/api/prisma/migrations/migration_lock.toml` +- `apps/api/src/generated/prisma/**` +- `apps/api/src/prisma.schema.spec.ts` +- `apps/api/package.json` +- `pnpm-lock.yaml` + +未创建: + +- service / API endpoint。 +- JobExecutionStore。 +- state-transition service / helper module。 +- worker Prisma import / DB writer。 +- auth / project / storage / queue business module。 +- game generation / prompt routing / subagent execution / GameIR compilation。 + +## Review Gate + +| Gate | Reviewer ID | Result | Blocking findings | +| --- | --- | --- | --- | +| implementation attempt | `019e813b-ad1b-7003-8899-80d6508f18a5` | NEEDS_CONTEXT | Prisma 7 plan 缺口 | +| plan amendment re-review coherence | `019e814b-1fbf-7263-a5ee-764e8efd6ee0` | PASS | 无 | +| plan amendment re-review feasibility | `019e814b-2053-70f3-bceb-ab84ecf4bd3f` | PASS | 无 | +| implementation | `019e8151-c119-7812-a7fd-848549897826` | DONE_WITH_CONCERNS -> DONE | pg warning 非阻塞 | +| spec compliance initial | `019e8166-b443-7270-83b4-52287f806636` | FAIL | Session S0 投影测试覆盖了 DB row 字段 | +| spec compliance re-review | `019e817b-0403-7013-a3d7-57ef40549ef6` | PASS | 无 | +| quality initial | `019e8180-6923-7912-8e36-1d6a700150bd` | FAIL | 普通测试 destructive;ReviewRecord CHECK 不完整 | +| spec compliance after quality fixes | `019e8192-7d94-7791-ba83-816a5f6e91f1` | PASS | 无 | +| quality re-review | `019e8196-d916-7591-a6ff-e0d535ce9836` | FAIL | unused helper 导致 lint 失败 | +| final spec compliance | `019e81a2-2ce0-7db1-bbcb-561839c2d4a7` | PASS | 无 | +| final quality / feasibility | `019e81a6-01a7-7ce3-8f40-c2592d194343` | PASS | 无 | + +## 关键修复 + +- Prisma 7 plan 修正: + - 新增 `apps/api/prisma.config.ts`。 + - 使用 `prisma-client` generator,output 为 `apps/api/src/generated/prisma`。 + - direct tests 通过 `@prisma/adapter-pg` / `pg` 连接 Postgres。 +- Session S0 projection: + - S0 fixture ID 真实写入 DB 关系。 + - `MainCreationAgentSession` CLI 校验直接使用 `projectSession(session)`,不再覆盖 `creatorId/projectId/versionId`。 + - 另有 arbitrary relationship integrity 测试。 +- Test safety: + - 移除 `TRUNCATE` / `RESTART IDENTITY` / broad reset。 + - 普通 Prisma tests 使用 transaction rollback + savepoint。 +- ReviewRecord invariant: + - `pending_review` / `canceled` 必须没有 decision evidence。 + - `approved` / `rejected` 必须有 matching `decision`、非空 `reasonCode`、`decidedById`、`decidedAt`。 +- Session/version same-project: + - `MainCreationAgentSession(versionId, projectId)` 复合 FK 指向 `GameVersion(id, projectId)`。 + +## Controller Verification + +已运行: + +```bash +pnpm --filter @huijing/api exec prisma validate --schema prisma/schema.prisma +pnpm --filter @huijing/api exec prisma migrate status --schema prisma/schema.prisma +pnpm --filter @huijing/api lint +pnpm --filter @huijing/api test -- prisma +pnpm --filter @huijing/api build +docker compose -f infra/docker-compose.dev.yml ps +``` + +结果: + +- Prisma schema:valid。 +- Prisma migrate status:2 migrations found,database schema up to date。 +- API lint:PASS。 +- API Prisma tests:PASS,2 files / 8 tests。 +- API build:PASS。 +- Docker: + - `infra-postgres-1` healthy on `5432`。 + - `infra-redis-1` healthy on `6379`。 +- Build outputs 已清理,`apps/**` / `packages/**` 下无 `dist`、`.next`、`coverage`、`tsconfig.tsbuildinfo` 残留。 +- destructive scan:普通 app/package/script surface 中未发现 `TRUNCATE`、`RESTART IDENTITY`、`migrate reset`、`DROP DATABASE`、`DROP TABLE`、`DELETE FROM`。 + +## Residual Non-blocking Notes + +- `pnpm test` 已在 quality review 中通过;`check:s1-scope` 仍指向未来的 `scripts/check-s1-scope.mjs`,这是 Task 9 预期交付,不是 Task 4 blocker。 +- Prisma test 当前会输出 `pg` deprecation warning;现有 `pg` range 仍在 v8,命令 exit 0。升级 Prisma adapter / `pg` 时需复查 savepoint 测试方式。 +- pnpm ignored build scripts 仍可能列出 `@prisma/engines` / `prisma`,但本轮 validate / migrate / generate / tests / build 均通过。 + +## SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `apps/api/package.json` | `678617fe3796b710a24f72230df9805f47879df2ca0f3f2b907bd68b1941bc17` | +| `apps/api/prisma.config.ts` | `eb72dc13ebfd7bf6e74036ac3c2ecc7add69be52e374b2c47411307b0c9381be` | +| `apps/api/prisma/schema.prisma` | `c418f59a6bcd10a87e7f68af336bffdedace5ba506a793ac7f2fb82f220996d9` | +| `apps/api/prisma/migrations/20260601040253_s1_app_foundation/migration.sql` | `00ce17a7f11a9c041679977a3c81cc5d8f4d0aece6681d793cb9acae4bad500a` | +| `apps/api/prisma/migrations/20260601050132_s1_task4_quality_fixes/migration.sql` | `666807cdfe9f549a34638f60c07cf1631f8ccd1ca43b796f346db2122e965e3b` | +| `apps/api/prisma/migrations/migration_lock.toml` | `99836963713b4f5b269ad49af0ed3d7b0b2e336115c2f92dc9ac683d139d0900` | +| `apps/api/src/prisma.schema.spec.ts` | `b98d3f82d0c500930c1a95f6648ce0c3c2894c3414da8c3067a612754b67a9a2` | +| `pnpm-lock.yaml` | `c85b03575467a508b0e85dbe81a7ab51c0ea6f754e122567b0671c2f3b12b576` | +| `docs/superpowers/plans/2026-05-31-mvp-S1-app-foundation.md` | `868dc63fee64e254cf267d63db472aa46abf15977f1999785cfaea6fa1956a0a` | + +Generated Prisma client output under `apps/api/src/generated/prisma/**` is part of Task 4 output; individual file hashes were computed during controller verification and can be regenerated with: + +```bash +find apps/api/src/generated/prisma -type f | sort | xargs shasum -a 256 +``` diff --git a/docs/memorys/2026-06-01-S1Task4计划修正门禁.md b/docs/memorys/2026-06-01-S1Task4计划修正门禁.md new file mode 100644 index 00000000..b7c6cd31 --- /dev/null +++ b/docs/memorys/2026-06-01-S1Task4计划修正门禁.md @@ -0,0 +1,63 @@ +# 2026-06-01 S1 Task 4 计划修正门禁 + +## 结论 + +S1 Task 4 在实现前发现 Prisma 7 工具链与原计划 allowed files 不匹配。已修正 Task 4 plan,并通过 fresh amendment review gate。 + +可以重新派 fresh implementation subagent 执行 S1 Task 4。 + +## 阻塞事实 + +原 Task 4 plan 只允许创建 `apps/api/prisma/schema.prisma`、`apps/api/prisma/migrations/**` 和测试相关 `apps/api/src/**` 文件。实现子代理在进入实现前验证到: + +- `pnpm --filter @huijing/api exec prisma --version`:Prisma CLI 为 `7.8.0`,`@prisma/client: Not found`。 +- Prisma 7 不允许 `schema.prisma` 使用 `datasource.url = env("DATABASE_URL")`。 +- `migrate dev --schema prisma/schema.prisma` 需要 `prisma.config.ts` 提供 datasource URL。 +- 直接 Prisma tests / `prisma generate` 需要允许安装 Prisma 7 client/runtime 依赖并更新 lockfile。 + +因此,原计划在不越权的情况下不可实现。 + +## Plan Amendment + +已修改 `docs/superpowers/plans/2026-05-31-mvp-S1-app-foundation.md`: + +- Task 4 allowed files 增加: + - `apps/api/prisma.config.ts` + - `apps/api/package.json` + - `pnpm-lock.yaml` +- Dependency Matrix 中 `@huijing/api` 增加: + - runtime:`@prisma/client`、`@prisma/adapter-pg`、`pg` + - dev:`@types/pg` +- Task 4 Step 2 明确: + - Prisma 7 datasource URL 放在 `apps/api/prisma.config.ts`。 + - `schema.prisma` 不写 `url = env("DATABASE_URL")`。 + - 使用 Prisma 7 `prisma-client` generator。 + - generated client explicit output 为 `apps/api/src/generated/prisma`。 + - direct Prisma tests 从该 output path import generated client,并使用 PostgreSQL driver adapter。 + - 不依赖 install-time postinstall;仍以显式 `prisma generate` 作为验收证据。 + +未修改 S1 DB 合同、guarded-state/audit/job target 约束,也未把 Task 4 范围扩大到 service/API/Task 5+。 + +## Review Gate + +| Gate | Reviewer ID | Result | Blocking findings | +| --- | --- | --- | --- | +| implementation attempt | `019e813b-ad1b-7003-8899-80d6508f18a5` | NEEDS_CONTEXT | Prisma 7 config/client scope 缺口 | +| amendment review 1 | `019e8143-d916-7351-a413-c59a2e1c05eb` | FAIL | package/lockfile scope 与 client strategy 不足 | +| amendment review 2 | `019e8143-d992-71b3-ad37-caab35c72e0d` | FAIL | `@prisma/client` / generator strategy / lockfile scope 缺口 | +| amendment re-review coherence/scope | `019e814b-1fbf-7263-a5ee-764e8efd6ee0` | PASS | 无 | +| amendment re-review feasibility | `019e814b-2053-70f3-bceb-ab84ecf4bd3f` | PASS | 无 | + +## SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `docs/superpowers/plans/2026-05-31-mvp-S1-app-foundation.md` | `868dc63fee64e254cf267d63db472aa46abf15977f1999785cfaea6fa1956a0a` | +| `docs/superpowers/specs/2026-05-31-mvp-S1-app-foundation-design.md` | `f514de72c36c5fd1ee6f3e87999b911f33d392549dbb76c6ee5d538dac774cdb` | +| `docs/superpowers/plans/2026-06-01-implementation-review-gate-protocol.md` | `c8726acc5457ab87fb8f26c2e439e1d1b98df0255af78e4d6e8d9636dc518478` | + +## 后续执行要求 + +- S1 Task 4 必须使用新的 fresh implementation subagent,不复用已返回 `NEEDS_CONTEXT` 的子代理。 +- Task 4 review 必须检查 `prisma.config.ts`、generated client output、PostgreSQL adapter、`@prisma/client` 依赖、`pnpm-lock.yaml`、迁移 SQL 约束和 direct Prisma tests。 +- pnpm ignored build scripts 仍存在;只有在 migrate/generate 实际失败时,才引入 `pnpm.onlyBuiltDependencies` / rebuild 作为 scoped fix。 diff --git a/docs/memorys/2026-06-01-S1Task5状态边界门禁.md b/docs/memorys/2026-06-01-S1Task5状态边界门禁.md new file mode 100644 index 00000000..256c9a6f --- /dev/null +++ b/docs/memorys/2026-06-01-S1Task5状态边界门禁.md @@ -0,0 +1,143 @@ +# 2026-06-01 S1 Task 5 状态边界门禁 + +## 结论 + +S1 Task 5 `Implement Harness Client And State Transition Boundary` 已完成实现,并通过 mandatory fresh review gate: + +- spec compliance review:最终 PASS,无 Critical / Important / Minor finding。 +- quality / feasibility review:最终 PASS,无 Critical / Important;剩余 1 个 Minor 风险,不阻塞进入 Task 6。 + +可以进入 S1 Task 6。 + +## 实现范围 + +Task 5 delta 包含: + +- `packages/harness-client/package.json` +- `packages/harness-client/src/index.ts` +- `packages/harness-client/src/internal.ts` +- `packages/harness-client/src/index.spec.ts` +- `apps/api/src/modules/harness-gate/index.ts` +- `apps/api/src/modules/harness-gate/harness-gate.spec.ts` +- `apps/api/src/modules/state-transition/index.ts` +- `apps/api/src/modules/state-transition/state-transition.spec.ts` +- `apps/api/package.json` +- `pnpm-lock.yaml` + +未实现: + +- Task 6 auth / RBAC。 +- Task 7 queue / worker / storage / audit service。 +- Task 8 project / version / review endpoint。 +- Task 9 `scripts/check-s1-scope.mjs`。 +- game generation / prompt routing / asset pipeline / publish pipeline。 + +## 关键实现事实 + +- `@huijing/harness-client` package root 只导出 Task 5 指定的两个 type: + - `HarnessGateResult` + - `HarnessClient` +- `@huijing/harness-client/runtime` 是受控 runtime subpath,供 API 复用同一套 S0 CLI shell-out 实现,避免 API 复制子进程、临时文件、JSON parse 和 timeout 逻辑。 +- Harness client runtime: + - shell out 到 `node harness/scripts/validate-harness.mjs`。 + - 从 repo root resolve S0 CLI path,不依赖当前 cwd。 + - payload 写入临时 JSON,成功、失败、timeout 后清理。 + - 默认 timeout 为 `5000ms`,API 侧通过 `HARNESS_CLI_TIMEOUT_MS` 解析注入。 + - stdout / stderr 有捕获上限。 + - strict JSON-only parse,不使用 substring 判断。 + - timeout 返回 `HARNESS_TIMEOUT`。 + - invalid output / spawn ambiguity 返回 `HARNESS_INVALID_OUTPUT`。 + - S0 CLI 返回 `{ ok:false, reasonCode }` 时保留 S0 reasonCode。 +- `HarnessGateService`: + - 通过 `@huijing/harness-client/runtime` 创建 runtime client。 + - 只作为 API 内部 S0 gate facade,不复制 harness runtime 核心逻辑。 +- `StateTransitionService`: + - 是 S1 当前唯一 API-owned guarded state transition boundary。 + - 允许 S1 draft version creation,但不把 draft creation 标记为 S0 high-risk transition。 + - `review_approved` / `review_rejected` 会先过 S0 transition 和 `LifecycleEvent` contract gate。 + - PASS 路径设置事务本地 guard,写入 `ReviewRecord`、`LifecycleEvent`、`AuditLog`。 + - FAIL 路径返回 422-style `StateTransitionDomainError(reasonCode)`,不写 guarded state。 + - FAIL blocked audit 使用独立 `blockedAuditDb` 写入通道;测试已覆盖外层 transaction rollback 后 blocked audit 仍持久化。 + - guard cleanup 保留原始错误优先级,不让 cleanup failure 覆盖业务 / DB 原错。 +- 静态边界扫描: + - 拦截 state-transition module 外的 guarded Prisma writes。 + - 拦截 state-transition module 外的 runtime guard setter。 + - migration 不再整体 allowlist;只允许 trigger / current_setting 定义,不允许 guard setter 或 protected table DML。 + - 扫描 `apps/worker/**`,忽略 `node_modules`、`dist`、`.vite`、`coverage`、`.next` 等生成目录。 + - 明确不误伤 Task 4 `apps/api/src/prisma.schema.spec.ts` 的 test-only guard helper。 + +## Review Gate + +| Gate | Agent ID | Result | Blocking findings | +| --- | --- | --- | --- | +| implementation | `019e81b2-b8fd-7c00-983b-04ff43dcaabe` | DONE | 初版完成 | +| spec compliance initial | `019e81cc-2106-7541-a604-c4e8b413f2c3` | FAIL | public contract 外泄;API timeout 未接 env config;scanner allowlist 过宽 | +| implementation fix 1 | `019e81b2-b8fd-7c00-983b-04ff43dcaabe` | DONE | 修复 spec findings | +| spec compliance re-review | `019e81f0-52e0-76d2-8ca9-5f4b4db015f1` | PASS | 无 | +| quality / feasibility initial | `019e81fb-497e-7230-9ede-5aa017d3757a` | FAIL | blocked audit 可随 transaction rollback 丢失;API 复制 harness runtime | +| implementation fix 2 | `019e81b2-b8fd-7c00-983b-04ff43dcaabe` | DONE | 修复 quality findings | +| spec compliance safety recheck | `019e8215-c68e-7361-97ca-f8a2ca107c07` | PASS | 无 | +| quality / feasibility re-review | `019e821b-2026-77f3-8563-97515277b471` | PASS | 无 Critical / Important;1 个 Minor | + +## Controller Verification + +已运行: + +```bash +pnpm --filter @huijing/harness-client test +pnpm --filter @huijing/api test -- harness-gate state-transition +pnpm --filter @huijing/harness-client lint +pnpm --filter @huijing/harness-client typecheck +pnpm --filter @huijing/api lint +pnpm --filter @huijing/api typecheck +pnpm --filter @huijing/harness-client build +pnpm --filter @huijing/api build +pnpm --filter @huijing/api exec prisma validate --schema prisma/schema.prisma +pnpm --filter @huijing/api exec prisma migrate status --schema prisma/schema.prisma +node harness/scripts/validate-harness.mjs +pnpm check:workspace-scripts +pnpm --filter @huijing/api test -- prisma +docker compose -f infra/docker-compose.dev.yml ps +``` + +结果: + +- Harness client tests:PASS,1 file / 10 tests。 +- API harness-gate / state-transition tests:PASS,4 files / 19 tests。 +- Harness client lint / typecheck / build:PASS。 +- API lint / typecheck / build:PASS。 +- Prisma validate:PASS。 +- Prisma migrate status:2 migrations found,database schema up to date。 +- S0 full harness validation:PASS,checks=1259,validFixtures=45,invalidFixtures=51,invalidCoverage=51/51。 +- Workspace script check:PASS。 +- API Prisma tests:PASS,4 files / 19 tests。 +- Docker: + - `infra-postgres-1` healthy on `5432`。 + - `infra-redis-1` healthy on `6379`。 +- Build outputs 已清理;`apps/**` / `packages/**` 下无 `dist`、`.next`、`coverage`、`tsconfig.tsbuildinfo` 残留。 + +## Residual Non-blocking Notes + +- Quality reviewer 记录 1 个 Minor:同一 `lifecycleEventId` 的 blocked transition 如果重试,固定 `blocked-audit` id 可能撞主键,原始 harness reasonCode 可能被 Prisma unique error 覆盖。后续 API composition root 接入时建议用 `createMany skipDuplicates`、`upsert`,或显式复用已有 blocked audit 后继续返回 `StateTransitionDomainError`。 +- `StateTransitionServiceOptions.blockedAuditDb` 依赖调用方注入非事务客户端;当前注释和测试表达了边界,后续 composition root 应用工厂封装,避免业务方直接 `new StateTransitionService` 时误传 transaction client。 +- API / Prisma tests 仍输出既有 `pg` deprecation warning;命令 exit 0。升级 `pg@9` 前需要复查 Prisma adapter / 并发测试方式。 +- `check:s1-scope` 仍指向未来的 `scripts/check-s1-scope.mjs`,这是 Task 9 交付项,不是 Task 5 blocker。 +- 当前 git status 仍包含 `.idea/`、`docs-design/` 和大量 untracked workspace surface,这是前置工作面;Task 5 未回退或清理这些内容。 + +## SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `packages/harness-client/package.json` | `94bb54022628ded5c934816f2a0f5c9b47129e6090d5770718821ba5b3c6a733` | +| `packages/harness-client/src/index.ts` | `9936030f93e145baab3b701609442834be871b7f6177117ff2de3bf20464fa80` | +| `packages/harness-client/src/internal.ts` | `54deaba53a418a1a3b8d76366cf3f9c1f071c808489e1481c26525dc63cd8d59` | +| `packages/harness-client/src/index.spec.ts` | `d6b150b00098e4efceaf9ac9a8ab6d29887e6a50a169ac0ef53fc3f8f5da8ef1` | +| `apps/api/src/modules/harness-gate/index.ts` | `dfb683ce8b5e500aae271a8daa8e97592fdc2e2e39e50544d86c2fecc72de673` | +| `apps/api/src/modules/harness-gate/harness-gate.spec.ts` | `7f936d954add5a40c755abae987fdfd845c120b1ba281362afe174781aada3ac` | +| `apps/api/src/modules/state-transition/index.ts` | `c3c08bf59728f6e07160d821772a3a37201005ab38710583b6cab45e0938c065` | +| `apps/api/src/modules/state-transition/state-transition.spec.ts` | `cf8ae70448541185980ac716cc8118c3f6b84a1c0b1109e1fb4f36898b327dd2` | +| `apps/api/package.json` | `6697372caa5a2ae69c45995ca1ad66b92c656b548d581c1d4276f7e0fcd5902a` | +| `pnpm-lock.yaml` | `d1e6463b4b56b7f63ed35b4df7bf5ab43fd28a1df31adb21beb608c2f834ed26` | +| `docs/superpowers/plans/2026-05-31-mvp-S1-app-foundation.md` | `868dc63fee64e254cf267d63db472aa46abf15977f1999785cfaea6fa1956a0a` | +| `docs/superpowers/specs/2026-05-31-mvp-S1-app-foundation-design.md` | `f514de72c36c5fd1ee6f3e87999b911f33d392549dbb76c6ee5d538dac774cdb` | +| `docs/superpowers/plans/2026-06-01-implementation-review-gate-protocol.md` | `c8726acc5457ab87fb8f26c2e439e1d1b98df0255af78e4d6e8d9636dc518478` | diff --git a/docs/memorys/2026-06-01-S1Task6权限边界门禁.md b/docs/memorys/2026-06-01-S1Task6权限边界门禁.md new file mode 100644 index 00000000..9e8520fe --- /dev/null +++ b/docs/memorys/2026-06-01-S1Task6权限边界门禁.md @@ -0,0 +1,99 @@ +# 2026-06-01 S1 Task 6 权限边界门禁 + +## 结论 + +S1 Task 6 `Implement Auth And RBAC Boundary` 已完成实现,并通过 mandatory fresh review gate: + +- spec compliance review:PASS,无 Critical / Important / Minor finding。 +- quality / feasibility review:PASS,无 Critical / Important;剩余 3 个 Minor 风险,不阻塞进入 Task 7。 + +可以进入 S1 Task 7。 + +## 实现范围 + +Task 6 delta 包含: + +- `apps/api/src/app.module.ts` +- `apps/api/src/modules/auth/index.ts` +- `apps/api/src/modules/auth/auth.spec.ts` +- `apps/api/src/modules/rbac/index.ts` +- `apps/api/src/modules/rbac/rbac.spec.ts` + +未实现: + +- project / version / asset / job / audit endpoints。 +- queue / worker / storage / audit service。 +- Prisma schema / migration 变更。 +- 外部 auth provider、OAuth、复杂 JWT。 +- `scripts/check-s1-scope.mjs`。 + +## 关键实现事实 + +- `AuthModule` 已注册到 `AppModule`。 +- `AuthController` 暴露: + - `POST /auth/login` + - `POST /auth/logout` + - `GET /me` +- S1 auth 使用本地内存 session store 和 deterministic seed users,满足 local MVP / test boundary;不作为生产多实例认证方案。 +- token 使用 Node `crypto.randomBytes` 生成,不是固定 token。 +- `AuthGuard` 在服务端解析 Bearer token,并对缺失 / 未知 token fail closed。 +- logout 会删除当前 token;同 token 后续 `GET /me` 失败。 +- RBAC policy 覆盖: + - `admin` + - `operator` + - `creator` + - `player` + - `anonymous` +- `creatorOwnsResource` 作为 resource-like ownership predicate,不调用 project/version API。 +- `canReadReviewFoundationData` 允许 operator/admin 读审核基础数据类别,不创建管理 CRUD。 +- `assertDirectObjectAccess` 对 anonymous / 非 owner fail closed,返回 403-style error。 +- Task 6 没有提前创建 project/version/asset/job/audit HTTP endpoint;endpoint-level RBAC 留给 Task 8。 + +## Review Gate + +| Gate | Agent ID | Result | Blocking findings | +| --- | --- | --- | --- | +| implementation | `019e8234-9c8d-7280-85d3-f817b9796ebe` | DONE | 无 | +| spec compliance review | `019e823f-89e9-7380-b2fb-ce259be9e8e7` | PASS | 无 | +| quality / feasibility review | `019e8245-5205-7ec3-b37b-4b1e686c17f8` | PASS | 无 Critical / Important;3 个 Minor | + +## Controller Verification + +已运行: + +```bash +pnpm --filter @huijing/api test -- auth rbac +pnpm --filter @huijing/api lint +pnpm --filter @huijing/api typecheck +pnpm --filter @huijing/api build +find apps packages -maxdepth 4 \( -name dist -o -name .next -o -name tsconfig.tsbuildinfo -o -name coverage \) -print +``` + +结果: + +- API auth/RBAC tests:PASS,6 files / 27 tests。 +- API lint:PASS。 +- API typecheck:PASS。 +- API build:PASS。 +- Build outputs 已清理;`apps/**` / `packages/**` 下无 `dist`、`.next`、`coverage`、`tsconfig.tsbuildinfo` 残留。 + +## Residual Non-blocking Notes + +- Quality reviewer 记录 Minor:AuthGuard protected-route test 只覆盖 anonymous rejection,尚未覆盖 authenticated token success path 和 `request.actor` 注入。Task 8 接真实 endpoint 前建议补一条 Bearer token 成功访问用例。 +- Quality reviewer 记录 Minor:seed users 位于 runtime code;符合 local MVP,但后续真实认证前应加 local-only / env-gated provider,避免演示环境误认为生产认证。 +- Quality reviewer 记录 Minor:`creatorOwnsResource` 接受 `ownerId` / `creatorId` / `actorId`,后续 Task 8 endpoint 接入时应优先使用明确 owner field;只有 job 这类 `actorId` 语义等于请求方资源时才使用 `actorId`。 +- API tests 仍输出既有 `pg` deprecation warning;命令 exit 0。升级 `pg@9` 前需要复查 Prisma adapter / 并发测试方式。 +- 当前 git status 仍包含 `.idea/`、`docs-design/` 和大量 untracked workspace surface,这是前置工作面;Task 6 未回退或清理这些内容。 + +## SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `apps/api/src/app.module.ts` | `6c4072e3f6e65e6759e9b55ee6ba5acc43e0dc4b3a2351fafdf5fd0fc80fa1b8` | +| `apps/api/src/modules/auth/index.ts` | `63597418c1e2402957f448dfbfaa221ab87a93d550ad8c3361b04ca62420c160` | +| `apps/api/src/modules/auth/auth.spec.ts` | `69a7e7df869116ffb0d6eff51fa8503c791867aea9f6358d6640f1120a522ebc` | +| `apps/api/src/modules/rbac/index.ts` | `cf923d0f787dd5ea73ac3e9408f757e30c80be9fe84ef0f83ccd9972b5c984b1` | +| `apps/api/src/modules/rbac/rbac.spec.ts` | `8f58871b6ce1ed8b12999215953a4129de62edebd1b1342e5c20a128ddc84bac` | +| `docs/superpowers/plans/2026-05-31-mvp-S1-app-foundation.md` | `868dc63fee64e254cf267d63db472aa46abf15977f1999785cfaea6fa1956a0a` | +| `docs/superpowers/specs/2026-05-31-mvp-S1-app-foundation-design.md` | `f514de72c36c5fd1ee6f3e87999b911f33d392549dbb76c6ee5d538dac774cdb` | +| `docs/superpowers/plans/2026-06-01-implementation-review-gate-protocol.md` | `c8726acc5457ab87fb8f26c2e439e1d1b98df0255af78e4d6e8d9636dc518478` | diff --git a/docs/memorys/2026-06-01-S1Task7队列存储审计门禁.md b/docs/memorys/2026-06-01-S1Task7队列存储审计门禁.md new file mode 100644 index 00000000..feaf8bd5 --- /dev/null +++ b/docs/memorys/2026-06-01-S1Task7队列存储审计门禁.md @@ -0,0 +1,168 @@ +# 2026-06-01 S1 Task 7 队列存储审计门禁 + +## 结论 + +S1 Task 7 `Implement Queue, Worker, Storage, And Audit Boundaries` 已完成实现,并通过 mandatory fresh review gate: + +- spec compliance review:最终 PASS,无 Critical / Important。 +- quality / feasibility review:最终 PASS,无 Critical / Important。 + +可以进入 S1 Task 8。 + +## 实现范围 + +Task 7 delta 包含: + +- `apps/api/prisma/schema.prisma` +- `apps/api/prisma/migrations/20260601165239_s1_task7_job_lease_fields/migration.sql` +- `apps/api/src/generated/prisma/**` +- `apps/api/src/modules/jobs/index.ts` +- `apps/api/src/modules/jobs/jobs.spec.ts` +- `apps/api/src/modules/queue/index.ts` +- `apps/api/src/modules/queue/queue.spec.ts` +- `apps/api/src/modules/storage/index.ts` +- `apps/api/src/modules/storage/storage.spec.ts` +- `apps/api/src/modules/audit/index.ts` +- `apps/api/src/modules/audit/audit.spec.ts` +- `apps/api/package.json` +- `apps/worker/package.json` +- `apps/worker/src/index.ts` +- `apps/worker/src/worker.smoke.spec.ts` +- `pnpm-lock.yaml` + +未实现: + +- Project / version / asset / job / audit HTTP endpoints。 +- Audit admin UI。 +- Real build / conversion / generation worker business。 +- Cloud storage SDK。 +- `scripts/check-s1-scope.mjs`。 + +## 关键实现事实 + +- `Job` 新增持久运行态字段: + - `leaseToken` + - `leasedBy` + - `leaseExpiresAt` + - `lockVersion` +- Task 7 migration 增加: + - Job lease fields。 + - `Job_status_nextRetryAt_createdAt_idx`。 + - `Job_leaseToken_idx`。 + - `Job_running_lease_check`。 + - `Job_lock_version_check`。 +- `JobExecutionStore` 是 API-owned Job 状态写入口,覆盖: + - `enqueueScopedJob` + - `claimNext` + - `markSucceeded` + - `markFailedOrRetry` + - `markTimedOut` + - `cancelQueued` +- `enqueueScopedJob` 必须使用 root Prisma client;如果用外层 transaction client 调用,会抛 `JOB_ENQUEUE_REQUIRES_ROOT_CLIENT`,并且不会执行 `mutateTarget`、不会 enqueue、不会持久化 Job。 +- 同 scope/idempotencyKey 并发请求只有 winner 会执行 `mutateTarget`。 +- `queue.enqueue` 已移出 DB transaction,在 Job commit 后执行。 +- `queue.enqueue` 失败后,Job 会进入 `pending_retry`,写入 `QUEUE_ENQUEUE_FAILED` 和 `nextRetryAt`,避免保持普通 `queued`。 +- `markTimedOut` 同时支持 persisted `timeoutAt <= now` 和 `leaseExpiresAt <= now`。 +- `QueueAdapter` 包含 `enqueue(job)`、`process(handler)`、`close()`。 +- `InMemoryQueueAdapter` 用于测试 / explicit local fallback。 +- `BullMqQueueAdapter` 在 Redis 不可用时显式返回 `QUEUE_UNAVAILABLE`,不静默 fallback 到 memory。 +- Worker 仍是 S1 no-op smoke,不 import Prisma,不写 DB,不更新 guarded state。 +- Local storage adapter: + - 使用 `S1_STORAGE_ROOT` root isolation。 + - 生成 owner/project scoped asset keys。 + - 拒绝 path traversal、absolute path、encoded separators、NUL bytes。 + - 逐级 `lstat` / `realpath` 拒绝 symlink escape,拒绝后不会在 root 外创建目录或文件。 + - 校验 MIME、size、sha256 checksum。 + - 失败路径清理临时文件。 +- Audit service: + - 只提供 append create path。 + - service-layer update/delete attempt 被拒绝。 + - direct Prisma auditLog update/delete 仍由 DB trigger 拒绝。 + - static scan 会发现 S1 app code 中的 `auditLog.update/delete`。 + - high-risk blocked facts 可写 audit,不变更 target state。 +- Task 7 没有引入 Task 8 HTTP endpoints;当前生产 controller 仍只有 health 和 auth。 + +## Review Gate + +| Gate | Agent ID | Result | Blocking findings | +| --- | --- | --- | --- | +| implementation | `019e8252-50f2-7311-8ddd-235f17d52a31` | DONE_WITH_CONCERNS | BullMQ happy path 未测;既有 pg warning | +| spec compliance initial | `019e8270-5e5e-72e3-8d5c-ca9745de85bc` | FAIL | storage symlink escape 先污染 root 外目录;Job timeout 未使用 persisted `timeoutAt` | +| implementation fix 1 | `019e8252-50f2-7311-8ddd-235f17d52a31` | DONE | 修复 storage / timeout findings | +| spec compliance re-review | `019e828b-3b2c-78d3-baa1-e5989d5191b1` | PASS | 无 Critical / Important;2 个 Minor | +| quality / feasibility initial | `019e8297-bf65-7302-9321-a7dded6147fd` | FAIL | duplicate idempotency 可重复 `mutateTarget`;`queue.enqueue` 在 DB transaction 内 | +| implementation fix 2 | `019e8252-50f2-7311-8ddd-235f17d52a31` | DONE | 修复 winner-only mutation 和 post-commit enqueue | +| spec compliance safety recheck | `019e82a9-1aeb-74d3-ba0c-919e788dba34` | PASS | 无 | +| quality / feasibility re-review | `019e82b2-e49e-7b60-89b1-db47760b1551` | FAIL | 外层 transaction client 仍可导致 queue before outer commit | +| implementation fix 3 | `019e8252-50f2-7311-8ddd-235f17d52a31` | DONE | `enqueueScopedJob` 要求 root Prisma client | +| spec compliance safety recheck 2 | `019e82cc-459e-7d90-977f-c06894022a28` | PASS | 无 | +| quality / feasibility re-review 2 | `019e82f2-2382-7dc0-9cc3-8912b42c07ef` | PASS | 无 Critical / Important | + +## Controller Verification + +已运行: + +```bash +pnpm --filter @huijing/api test -- jobs queue storage audit +pnpm --filter @huijing/worker test +pnpm --filter @huijing/api lint +pnpm --filter @huijing/api typecheck +pnpm --filter @huijing/worker lint +pnpm --filter @huijing/worker typecheck +pnpm --filter @huijing/api exec prisma validate --schema prisma/schema.prisma +pnpm --filter @huijing/api exec prisma migrate status --schema prisma/schema.prisma +pnpm --filter @huijing/api exec prisma generate --schema prisma/schema.prisma +pnpm --filter @huijing/api build +pnpm --filter @huijing/worker build +docker compose -f infra/docker-compose.dev.yml ps +find apps packages -maxdepth 4 \( -name dist -o -name .next -o -name tsconfig.tsbuildinfo -o -name coverage \) -print +``` + +结果: + +- API jobs / queue / storage / audit tests:PASS,10 files / 53 tests。 +- Worker tests:PASS,1 file / 2 tests。 +- API lint / typecheck / build:PASS。 +- Worker lint / typecheck / build:PASS。 +- Prisma validate:PASS。 +- Prisma migrate status:3 migrations found,database schema up to date。 +- Prisma generate:PASS。 +- Docker: + - `infra-postgres-1` healthy on `5432`。 + - `infra-redis-1` healthy on `6379`。 +- Build outputs 已清理;`apps/**` / `packages/**` 下无 `dist`、`.next`、`coverage`、`tsconfig.tsbuildinfo` 残留。 + +## Residual Non-blocking Notes + +- `pnpm check:s1-scope` 仍失败,因为 `scripts/check-s1-scope.mjs` 不存在;这是 Task 9 交付项,不是 Task 7 blocker。 +- Storage cleanup 测试仍主要覆盖 pre-write failure;spec re-review 记录 Minor:可后续补一个写入 temp 后让 rename 失败的测试,断言 `.upload-*` 不残留。 +- Worker package 未声明 dependency matrix 中的 `bullmq`、`ioredis`、`zod`、`@huijing/shared-contracts`;当前 queue runtime 依赖在 API package,worker 保持 no-op smoke。后续若 worker 真正消费 queue,再补 worker runtime dependencies。 +- BullMQ worker runtime error signal 目前较弱;后续真实 worker 接入时应提供 `onError` / logger / status hook。 +- Storage symlink / realpath 检查不是原子 nofollow 策略;S1 本地单进程 root 下可接受。后续上传 API 接入前可补目录替换并发测试或更强 nofollow/open/rename 校验。 +- `mutateTarget` 当前在 enqueue 成功后执行;S1 worker 仍是 no-op。后续真实 worker 接入时,需要明确 worker 只以 committed job / DB claim 为准,不把 target mutation 当作已完成业务前置条件。 +- `pending_retry` recovery 当前在 `JobExecutionStore.claimNext` 层清晰,但还没有真实 retry scheduler / DB polling worker 端到端链路;符合 S1 no-op worker 范围。 +- API tests 仍输出既有 `pg` deprecation warning;命令 exit 0。升级 `pg@9` 前需要复查 Prisma adapter / 并发测试方式。 +- 当前 git status 仍包含 `.idea/`、`docs-design/` 和大量 untracked workspace surface,这是前置工作面;Task 7 未回退或清理这些内容。 + +## SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `apps/api/prisma/schema.prisma` | `e0a536208fe789d0c83ca89c081381a906d8e8520f63625335816c7df6b82c06` | +| `apps/api/prisma/migrations/20260601165239_s1_task7_job_lease_fields/migration.sql` | `389d32966131c98520493bac8ee6938217275133a6c4e5d5fd4083616936277a` | +| `apps/api/src/modules/jobs/index.ts` | `b2e4dd3709a053537e24884aa40f77d140d446a5df66d8f746339d760a1d3175` | +| `apps/api/src/modules/jobs/jobs.spec.ts` | `c236eb5d78a68d111e68c328af4b26ec8cebae02aa85ddaa063020c02eef2d29` | +| `apps/api/src/modules/queue/index.ts` | `de86c64863bf6d9ffd4c963b70d24f3e8478f80b41440f2cc4fed7c8c4a4c6c4` | +| `apps/api/src/modules/queue/queue.spec.ts` | `9eb1cc2fb1052e19f3f2d38c6a04193bb4da6b043aa015205bc7b16605bb44ce` | +| `apps/api/src/modules/storage/index.ts` | `efba0aa32fae28b0b21de6c842ef8ee19274a6c77f27ffcbcdbb2fbd7aede34b` | +| `apps/api/src/modules/storage/storage.spec.ts` | `117c21d29afbba42213b0bf90b7b781baf5e3e3ae6a4df21d08750233e07241c` | +| `apps/api/src/modules/audit/index.ts` | `42382d6d233d58e54b4535499d43f94f2a2ef561264a5ee3ba7b8da6c96c93bb` | +| `apps/api/src/modules/audit/audit.spec.ts` | `b5f8bf06014c29bff2604369fcc0f9a9ed0c0a896b15c591f8287971b705e458` | +| `apps/api/package.json` | `5ac20498af83cd24527da598bfee8e28dda9e6a2a93012a29759b135c2d98b63` | +| `apps/worker/package.json` | `5094f400f8a169a4375c392802402454fcc333576a026d491d58b5f79a8c1cf2` | +| `apps/worker/src/index.ts` | `23f99cb50abbd66599d10e6851473f9c03ae47fc24f3cd66c05902fcf134e980` | +| `apps/worker/src/worker.smoke.spec.ts` | `510ded34b3204fcb466937a9298e69eba0ce18c644fa50e55b6668b499166510` | +| `pnpm-lock.yaml` | `293cd73e9a8f692e6444152a983664c3520f1f8d1d956151b453a213b79069eb` | +| `docs/superpowers/plans/2026-05-31-mvp-S1-app-foundation.md` | `868dc63fee64e254cf267d63db472aa46abf15977f1999785cfaea6fa1956a0a` | +| `docs/superpowers/specs/2026-05-31-mvp-S1-app-foundation-design.md` | `f514de72c36c5fd1ee6f3e87999b911f33d392549dbb76c6ee5d538dac774cdb` | +| `docs/superpowers/plans/2026-06-01-implementation-review-gate-protocol.md` | `c8726acc5457ab87fb8f26c2e439e1d1b98df0255af78e4d6e8d9636dc518478` | diff --git a/docs/memorys/2026-06-01-S1Task8API门禁.md b/docs/memorys/2026-06-01-S1Task8API门禁.md new file mode 100644 index 00000000..21e7caa1 --- /dev/null +++ b/docs/memorys/2026-06-01-S1Task8API门禁.md @@ -0,0 +1,158 @@ +# 2026-06-01 S1 Task 8 API 门禁 + +## 结论 + +S1 Task 8 `Implement Project, Version, Asset, Job, And Audit APIs` 已完成实现,并通过 mandatory fresh review gate: + +- spec compliance review:最终 PASS,无 Critical / Important。 +- quality / feasibility review:最终 PASS,无 Critical / Important。 + +可以进入 S1 Task 9。Task 9 之前仍不能运行 `pnpm check:s1-scope` 作为通过门禁,因为 `scripts/check-s1-scope.mjs` 是 Task 9 交付项。 + +## 实现范围 + +Task 8 delta 包含: + +- `apps/api/src/app.module.ts` +- `apps/api/src/main.ts` +- `apps/api/src/modules/projects/index.ts` +- `apps/api/src/modules/projects/api-runtime.ts` +- `apps/api/src/modules/projects/projects.api.spec.ts` +- `apps/api/src/modules/projects/api-runtime.spec.ts` +- `apps/api/src/modules/assets/index.ts` +- `apps/api/src/modules/assets/assets.api.spec.ts` +- `apps/api/src/modules/jobs/index.ts` +- `apps/api/src/modules/jobs/jobs.spec.ts` +- `apps/api/src/modules/jobs/jobs.api.spec.ts` +- `apps/api/src/modules/audit/index.ts` +- `apps/api/src/modules/audit/audit.api.spec.ts` + +未实现: + +- Task 9 `scripts/check-s1-scope.mjs`。 +- S2+ creation agent、GameIR editor、runtime、conversion、publish/feed/telemetry API。 +- 新 schema / migration。 +- audit admin UI。 + +## 关键实现事实 + +- S1 HTTP API surface 包含: + - `POST /auth/login` + - `POST /auth/logout` + - `GET /me` + - `POST /projects` + - `GET /projects` + - `GET /projects/:projectId` + - `POST /projects/:projectId/versions` + - `GET /projects/:projectId/versions` + - `POST /assets/presign` + - `GET /jobs/:jobId` + - `GET /audit-logs` +- `POST /projects` 仅 creator 可创建;operator/admin/player/anonymous 会被拒绝且不产生 project/audit mutation。 +- creator 只能读写自有 project/version/asset/job;operator/admin 只在列出的 foundation read endpoints 读取审核基础数据。 +- draft version 创建通过 `StateTransitionService.createDraftVersion` 写入 `draft`,没有调用无关 S0 review transition。 +- asset presign 复用 `LocalStorageAdapter.planObject()`,保持 Task 7 storage boundary。 +- queue provider 由 `createQueueAdapterFromEnv()` 决定: + - `QUEUE_ADAPTER=memory` 才使用 `InMemoryQueueAdapter`。 + - `QUEUE_ADAPTER=bullmq` 且 `REDIS_URL` 存在时使用 `BullMqQueueAdapter`。 + - 缺失 / unsupported `QUEUE_ADAPTER` 或 bullmq 缺 `REDIS_URL` 时 fail closed 为 `QUEUE_UNAVAILABLE`,不静默 fallback memory。 +- `ManagedQueueAdapter` 实现 `onModuleDestroy()`,Nest `app.close()` 会关闭底层 queue adapter。 +- `JobExecutionStore.enqueueScopedJob()` 返回 `{ job, created, enqueued }`,用于区分 create winner、duplicate 和 enqueue success。 +- S1 generic job runtime 不暴露 `mutateTarget` 或 `onJobCreated` pre-enqueue DB hook;避免 queue failure 后留下半成品 target。 +- `queue.enqueue` 仍在 DB commit 后执行。 +- `job.enqueued` 只在 queue side effect 成功后追加。 +- queue failure 后 Job 进入 `pending_retry`,写入 `QUEUE_ENQUEUE_FAILED`,并追加 `job.enqueue_failed`;不会追加 `job.enqueued`,也不会修改 target。 +- 全局异常过滤器稳定映射 Prisma `P2002/P2025`、`JobExecutionError`、`QueueUnavailableError`、`StateTransitionDomainError`,并保持 `{ code, message, requestId, details }` 响应形状。 +- Task8 API specs 按 runId 清理自己的 audit/project/job/asset 测试数据;`task8-*` leftover 已验证为 0。 + +## Review Gate + +| Gate | Agent ID | Result | Blocking findings | +| --- | --- | --- | --- | +| implementation | `019e82fc-f61d-73e0-a9a6-b5895a49db4d` | DONE | 初始实现通过后进入 review | +| spec compliance initial | `019e830f-0800-77b3-8108-942901a4ae7f` | FAIL | `POST /projects` 允许非 creator;asset presign 未复用 storage boundary | +| implementation fix 1 | `019e82fc-f61d-73e0-a9a6-b5895a49db4d` | DONE | 修复 creator-only project creation 与 storage planner delegation | +| spec compliance re-review | `019e8319-5514-7ba3-8e9b-29c9799fa789` | PASS | 无 | +| quality / feasibility initial | `019e831d-c3d9-7253-bb4e-f777ebfd7fb6` | FAIL | queue provider 忽略 env;job audit 幂等 / queue failure 边界;异常映射不足 | +| implementation fix 2 | `019e82fc-f61d-73e0-a9a6-b5895a49db4d` | DONE | 增加 queue env factory、异常映射、job failure audit | +| spec compliance safety recheck | `019e8335-b8c9-7d10-8292-4117256468b2` | PASS | 无 | +| quality / feasibility re-review | `019e833d-5ccf-70c3-aa3c-662f6af21b44` | FAIL | `QUEUE_ADAPTER` 缺省 fallback memory;enqueue 后 target mutation;queue adapter lifecycle | +| implementation fix 3 | `019e82fc-f61d-73e0-a9a6-b5895a49db4d` | DONE | 显式 queue adapter、ManagedQueueAdapter、移动 target mutation | +| spec compliance recheck 2 | `019e834f-befd-7903-83a9-659f348bcf2a` | FAIL | queue failure 后 target mutation 已提交 | +| implementation fix 4 | `019e82fc-f61d-73e0-a9a6-b5895a49db4d` | DONE | 移除 generic `mutateTarget` | +| spec compliance recheck 3 | `019e835b-fbb1-7951-98f3-d691c4806454` | PASS | 无 | +| quality / feasibility re-review 2 | `019e8361-4709-7bc3-b4de-ad504dbf43aa` | FAIL | `job.enqueued` 早于 queue success;`onJobCreated` pre-enqueue DB hook 风险 | +| implementation fix 5 | `019e82fc-f61d-73e0-a9a6-b5895a49db4d` | DONE | 移除 `onJobCreated`;`job.enqueued` 移到 queue success 后 | +| spec compliance recheck 4 | `019e8374-0515-7832-b402-9882aa8076fc` | FAIL | Job tests 并行污染,`claimNext()` 可领取其他 spec fixture | +| implementation fix 6 | `019e82fc-f61d-73e0-a9a6-b5895a49db4d` | DONE | 修复 Job tests 隔离,不改 runtime `claimNext()` 语义 | +| spec compliance recheck 5 | `019e8389-c240-7d41-9416-ab6eeac2ed1b` | PASS | 无 | +| quality / feasibility re-review 3 | `019e839a-aaef-7ca3-a64e-bd8a00461631` | FAIL | 测试隔离会改写非本 runId Job;Task8 audit leftovers | +| implementation fix 7 | `019e82fc-f61d-73e0-a9a6-b5895a49db4d` | DONE | advisory lock 隔离;只清理本 runId / task8 测试数据;leftover 清零 | +| spec compliance final | `019e83cb-4f97-7e93-b583-1d7a8f5afdbf` | PASS | 无 | +| quality / feasibility final attempt | `019e83d2-a012-77c1-87e7-d250193c5405` | TIMEOUT | 超时关闭,无结果 | +| quality / feasibility final | `019e859d-3c8f-7b02-99b2-51c632f41469` | PASS | 无 Critical / Important;2 个 Minor | + +## Controller Verification + +已运行: + +```bash +pnpm --filter @huijing/api test -- projects assets jobs audit +pnpm --filter @huijing/api test -- auth rbac jobs queue storage audit state-transition +pnpm --filter @huijing/api lint +pnpm --filter @huijing/api typecheck +pnpm --filter @huijing/api build +rm -rf apps/api/dist +pnpm --filter @huijing/api exec prisma validate --schema prisma/schema.prisma +pnpm --filter @huijing/api exec prisma migrate status --schema prisma/schema.prisma +pnpm check:workspace-scripts +docker compose -f infra/docker-compose.dev.yml ps +find apps packages -maxdepth 5 \( -name dist -o -name coverage -o -name .next -o -name tsconfig.tsbuildinfo \) -print +``` + +结果: + +- API Task8 tests:PASS,15 files / 82 tests。 +- API auth/rbac/jobs/queue/storage/audit/state-transition tests:PASS,15 files / 82 tests。 +- API lint / typecheck / build:PASS。 +- Prisma validate:PASS。 +- Prisma migrate status:3 migrations found,database schema up to date。 +- `pnpm check:workspace-scripts`:PASS。 +- Docker: + - `infra-postgres-1` healthy on `5432`。 + - `infra-redis-1` healthy on `6379`。 +- Build outputs 已清理;`apps/**` / `packages/**` 下无 `dist`、`.next`、`coverage`、`tsconfig.tsbuildinfo` 残留。 +- Task8 DB leftover 查询: + - `audit_task8_leftovers=0` + - `job_task8_leftovers=0` + - `project_task8_leftovers=0` + +## Residual Non-blocking Notes + +- `pnpm check:s1-scope` 仍失败,因为 `scripts/check-s1-scope.mjs` 不存在;这是 Task 9 交付项,不是 Task 8 blocker。 +- `GET /audit-logs` 当前返回全局 latest 200。官方单进程 / 顺序门禁通过;两个完整 Vitest 进程同时打同一个 dev DB 时,audit API 测试可能被其他进程新 audit 挤出 latest 200。Quality final 评定为 Minor,不阻塞 Task8。后续建议使用 per-process DB/schema,或禁止完整 Vitest 并发共享 dev DB。 +- API tests 仍输出既有 `pg` deprecation warning;命令 exit 0。升级 `pg@9` 前需要复查 Prisma adapter / 并发测试方式。 +- Task7 memory 中关于 `mutateTarget` 的 residual note 已过时;Task8 最新事实是 runtime 不再暴露 `mutateTarget` / `onJobCreated` pre-enqueue hook。 +- 当前 git status 仍包含 `.idea/`、`docs-design/` 和大量 untracked workspace surface,这是前置工作面;Task8 未回退或清理这些内容。 + +## SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `apps/api/src/app.module.ts` | `8d2b322de359888a470ba863f6cee488a72b8cb6261b66fd9bf14d6f17d073fe` | +| `apps/api/src/main.ts` | `fcefc7c057d211b11f890477a9a0017ea4a3d4ed41c34e93dc1be271f8212d58` | +| `apps/api/src/modules/projects/index.ts` | `fb33104864df22c829eb5beeb1015890f0fd71900f6e32230531fc7ea50d2233` | +| `apps/api/src/modules/projects/api-runtime.ts` | `a4ebdcbba9e25f1a49fc4cc0156147daf8836fec3df1a522b89e5c3d3305713b` | +| `apps/api/src/modules/projects/projects.api.spec.ts` | `c941170e73bf293926283147aa5fe384c515c742035ab7b77181742053f87c09` | +| `apps/api/src/modules/projects/api-runtime.spec.ts` | `96e1e1ea4b47363c4af6238a944e10136033b321c1206cc3fe581a76a4709d3b` | +| `apps/api/src/modules/assets/index.ts` | `df8236d27715f98e2cea9a2abbd40677afc2863293e09682b80bc83ec766092c` | +| `apps/api/src/modules/assets/assets.api.spec.ts` | `4b260fe97ce42cf27dca2aba0c8abc0573091d966a7692d5f504e54e28a8b8a3` | +| `apps/api/src/modules/jobs/index.ts` | `300563b079c80edf2ce64c4035f12446b0b7edb73ba56809f1938128a56f391a` | +| `apps/api/src/modules/jobs/jobs.spec.ts` | `8188d8d52fa3da5b354b89f01d723c87758010356ddbe5abc0f5ae644cd63fa9` | +| `apps/api/src/modules/jobs/jobs.api.spec.ts` | `15275a7298eff7092e2888986c782c070edd29afa66f3100c4320f1ef8222331` | +| `apps/api/src/modules/audit/index.ts` | `d815b6e143f39ccf9525b4cd931f13d003299ba36063946861a546eb3ec97c18` | +| `apps/api/src/modules/audit/audit.api.spec.ts` | `262eb16e9423ab82119aaf2a4d2115c06669d2f518205236128ab6fce8a64640` | +| `apps/api/prisma/schema.prisma` | `e0a536208fe789d0c83ca89c081381a906d8e8520f63625335816c7df6b82c06` | +| `docs/superpowers/plans/2026-05-31-mvp-S1-app-foundation.md` | `868dc63fee64e254cf267d63db472aa46abf15977f1999785cfaea6fa1956a0a` | +| `docs/superpowers/specs/2026-05-31-mvp-S1-app-foundation-design.md` | `f514de72c36c5fd1ee6f3e87999b911f33d392549dbb76c6ee5d538dac774cdb` | +| `docs/superpowers/plans/2026-06-01-implementation-review-gate-protocol.md` | `c8726acc5457ab87fb8f26c2e439e1d1b98df0255af78e4d6e8d9636dc518478` | diff --git a/docs/memorys/2026-06-01-S1规格计划门禁.md b/docs/memorys/2026-06-01-S1规格计划门禁.md new file mode 100644 index 00000000..a8f4de30 --- /dev/null +++ b/docs/memorys/2026-06-01-S1规格计划门禁.md @@ -0,0 +1,54 @@ +# 2026-06-01 S1 规格计划门禁 + +## 结论 + +S1 App Foundation spec/plan review gate 已通过。四个 fresh reviewer 均为 `gpt-5.5 + xhigh`,本轮无 Critical / Important finding,可以进入 S1 Task 1 实现。 + +## Reviewers + +| Role | Reviewer ID | Gate | Blocking findings | +| --- | --- | --- | --- | +| coherence/scope | `019e80c3-ff72-7d10-bc0b-58bea7bccf9e` | PASS | 无 | +| feasibility | `019e80c4-0003-7a43-926b-ef25efdd7308` | PASS | 无 | +| security | `019e80c4-023c-7373-8548-adeef0dee226` | PASS | 无 | +| adversarial | `019e80c4-0350-7b72-b115-84e71c0cebe5` | PASS | 无 | + +## Reviewed Files And SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `docs/superpowers/specs/2026-05-31-mvp-S1-app-foundation-design.md` | `f514de72c36c5fd1ee6f3e87999b911f33d392549dbb76c6ee5d538dac774cdb` | +| `docs/superpowers/plans/2026-05-31-mvp-S1-app-foundation.md` | `25591c2ec52cde6651dca8fbadbdb6ad13fad051b0319e366f8393c6d1cef71a` | +| `docs/superpowers/plans/2026-06-01-implementation-review-gate-protocol.md` | `c8726acc5457ab87fb8f26c2e439e1d1b98df0255af78e4d6e8d9636dc518478` | +| `harness/scripts/validate-harness.mjs` | `4e40acad9383548a24389c060c9ed71d134b8b2285147ac2bc2aad14d40808da` | +| `harness/schemas/main-creation-agent-session.schema.json` | `6748fefc0fdc49fa9812f63ef66df5b44b2bb025ef3b2459efdcec2f177b4fa2` | +| `harness/schemas/agent-task.schema.json` | `b26d91750c3651690b9b3f1567255960fc326d23e24cb48386b4fa99b8b46ba2` | +| `harness/schemas/lifecycle-event.schema.json` | `b1a4737a25516a04eb8a2ddc6951766219b420a6eb735c8d6bdfb81fb70b789b` | +| `harness/lifecycle.yaml` | `6e2400aa678ea9feed957ebea56a4f98d50508e03c396dc943e42e4cf802e79e` | +| `docs/memorys/2026-06-01-S0阶段通过门禁.md` | `dce65992dd97fdfd6d2ce1474a180fe95ca0f5635c0b94038a594a1f48b406f5` | + +## Worktree State + +`git status --short` 显示 `docs/` 与 `harness/` 仍为 untracked surface;`git ls-files --stage` 对上述 reviewed docs/harness 文件无输出,因此这些 reviewed files 当前均为 untracked。`.idea/` 与 `docs-design/` 存在既有 staged/modified 内容,S1 gate 未修改或回滚这些文件。 + +## Fixed Blocking Findings + +本轮通过前已修复以下阻塞类问题: + +- S1 spec/plan 起始事实改为已有 S0 `harness/`,S1 固定消费 `harness/scripts/validate-harness.mjs`。 +- `MainCreationAgentSession` / `AgentTask` 对齐 S0 schema,并要求 exact DTO projection 与 S0 CLI 校验。 +- `ReviewRecord` / `LifecycleEvent` 补齐 S0 lifecycle transition 证据字段。 +- Task 4 验收收窄为 DB schema / raw SQL / direct Prisma,不再提前要求 Task 7/8 的 service/API/concurrency。 +- Job target 增加 DB 级 same-project invariant,Job 状态由 API-owned `JobExecutionStore` 单写入口管理。 +- Worker 明确不 import Prisma、不直写 DB、不写 guarded state。 +- Guarded state / audit append-only 通过 DB trigger、static scanner、direct Prisma negative tests 约束。 +- Final verification 纳入 Docker Postgres/Redis、migration deploy/generate、real DB/queue integration。 +- Review gate protocol 要求 evidence note 记录 reviewer ids、roles、SHA-256、`git status --short` 和 tracked/untracked 状态。 + +## Non-blocking Implementation Notes + +- `review_rejected` 可用构造 payload 或新增 S0 fixture 验证;不要误以为当前只存在 `review_approved` fixture 就跳过 rejected path。 +- `LifecycleEvent --contract` 只能证明必填字段存在,审核状态的关键约束仍必须用 `--transition review_approved/review_rejected` 验证。 +- `JobExecutionStore` 实现要使用 `leaseToken`、`leasedBy`、`leaseExpiresAt`、`lockVersion` 或等价持久字段支撑 claim/lease/concurrency。 +- Scope scanner 实现时应固化 denylist、path allowlist、正负 self-test fixture,避免靠自然语言判断。 +- Harness stdout/stderr bound、storage MIME allowlist 和 max size 必须给出具体上限;review 时不接受无界或过宽实现。 diff --git a/docs/memorys/2026-06-02-S1Task9最终验证门禁.md b/docs/memorys/2026-06-02-S1Task9最终验证门禁.md new file mode 100644 index 00000000..868baa81 --- /dev/null +++ b/docs/memorys/2026-06-02-S1Task9最终验证门禁.md @@ -0,0 +1,205 @@ +# 2026-06-02 S1 Task 9 最终验证门禁 + +## 结论 + +S1 Task 9 `Final S1 Verification` 已完成,并通过 mandatory fresh review gate 与 S1 阶段最终 read-only review gate: + +- Task 9 scope scanner spec compliance review:最终 PASS,无 Critical / Important。 +- Task 9 scope scanner quality / feasibility review:最终 PASS,无 Critical / Important。 +- Task 9 full verification:PASS。 +- S1 final read-only review:PASS,无 Critical / Important,可以进入 S2。 + +## 实现范围 + +Task 9 delta 包含: + +- `scripts/check-s1-scope.mjs` +- `apps/api/src/modules/jobs/index.ts` + +Task 9 未实现: + +- S2+ creation agent / 游戏需求确认 / draft 生成 / draft 修改。 +- Web runtime、WebPlatformAdapter、小游戏转换、发布流、feed、analytics。 +- 新业务 API、schema model 或 migration。 + +## 关键实现事实 + +- `scripts/check-s1-scope.mjs` 扫描 `apps/**` 与 `packages/**`,忽略 `node_modules`、`dist`、`.next`、`.vite`、`coverage`、generated Prisma。 +- scanner 会拒绝 S2-S8 路径、路由、模型、符号泄漏,包括: + - `creation-agent/messages` + - `compile-game-ir` + - `web-runtime` + - `mini-game-conversion` + - `AIGameDesignDraft` + - `GameIRArtifact` + - `GameIR` + - `ConversionReport` + - `ValidationReport` + - `MiniGameProject` + - `MiniGameCodeConversion` + - `FeedItem` + - `GameDailyStats` + - `CreatorDailyStats` + - `/events/batch` +- `MainCreationAgentSession`、`AgentTask`、`ReviewRecord`、`LifecycleEvent` 只允许作为 S1 schema/state/audit anchor,不允许作为业务实现泄漏。 +- `packages/harness-client/**` 只在明确 `validateContract(...)` 或 harness CLI `--contract` 参数断言上下文放行 S0 contract 名称。 +- `JobExecutionStore` 是唯一 Job runtime state writer;worker 不 import Prisma/DB。 +- scanner 会拒绝 Job runtime field 的 Prisma direct write、bracket write、optional chaining write、delegate alias write,以及 raw SQL 写。 +- scanner 会拒绝 `AuditLog` update/delete/upsert、raw SQL update/delete/truncate/drop/disable trigger/function tamper。 +- scanner 会拒绝 guarded state `GameVersion` / `ReviewRecord` / `LifecycleEvent` 在 state-transition boundary 外直接写。 +- scanner 会拒绝 runtime guard setter:`set_config`、`SET LOCAL`、`app.state_transition_guard`。 +- raw SQL scanner 覆盖本轮 review 发现的绕过: + - `db.$executeRawUnsafe?.call(...)` + - `db.$executeRawUnsafe?.bind(db)(...)` + - `const execRaw = db.$executeRawUnsafe.bind(db); await execRaw(...)` + - `db. $executeRawUnsafe(...)` + - `db["$executeRawUnsafe"](...)` + - `db?.$executeRawUnsafe(...)` + - `db?.["$executeRawUnsafe"](...)` + - bracket / optional bracket 的 `call`、`bind`、bound alias + - no-semicolon / ASI bound alias +- dynamic raw SQL write identifier fail closed;dynamic read-only `SELECT` 放行。 +- `apps/api/src/modules/jobs/index.ts` 的 Task9 后续 lint 修复只是 `let cursor` -> `const cursor`,未改变 Job runtime 或 scanner 行为。 + +## Review Gate + +| Gate | Agent ID | Result | Blocking findings | +| --- | --- | --- | --- | +| scanner implementation remediation | `019e87ab-d507-7bd0-ae38-5d537bbba64b` | DONE | 修复 Prisma optional chaining、delegate alias、raw optional/call/bind 基础覆盖 | +| scanner spec compliance | `019e87bb-5f8c-79c0-bdee-64bce4584492` | PASS | 无 | +| scanner quality / feasibility | `019e87c0-c594-7c61-8348-30ebe6332a30` | FAIL | raw SQL `?.call` / `?.bind` / bound alias 仍可绕过 | +| scanner implementation fix 1 | `019e87c7-6a70-72c0-add2-e3ae885fe774` | DONE | 修复 optional call/bind/bound alias | +| scanner spec compliance recheck 1 | `019e87d1-1965-74f3-9b22-c976be68d8ac` | PASS | 无 | +| scanner quality / feasibility recheck 1 | `019e87d5-9210-7611-b41d-162d50adb479` | FAIL | raw executor access 漏掉 dot whitespace、static bracket、optional receiver | +| scanner implementation fix 2 | `019e87e0-57e2-70b1-a272-4fa5604c8390` | DONE | 扩展 raw executor access matching | +| scanner spec compliance recheck 2 | `019e87e6-2508-7931-809b-7a5238233ca8` | FAIL | no-semicolon / ASI bound alias 漏报 | +| scanner implementation fix 3 | `019e87ea-a3f0-7273-9a02-877b378b5426` | DONE | 修复 no-semicolon / ASI bound alias | +| scanner spec compliance final | `019e8817-261a-70a3-af70-e358e55156ca` | PASS | 无 | +| scanner quality / feasibility final | `019e881e-d4ea-70b1-aa23-87febde47014` | PASS | 无 | +| lint implementation fix | `019e882a-e2ca-7093-b23e-4c1c603f14aa` | DONE | 修复 `prefer-const` | +| lint fix spec compliance | `019e8835-22cc-7782-82f6-abcc9e4e2699` | PASS | 无 | +| lint fix quality / feasibility | `019e8838-65a7-7d61-8b25-adfa4187208d` | PASS | 无 | +| S1 final read-only review | `019e883c-91a6-7542-84c1-d1c4464e831e` | PASS | 无 Critical / Important,可以进入 S2 | + +## Controller Verification + +已串行运行: + +```bash +pnpm install +pnpm check:workspace-scripts +export POSTGRES_PORT="${POSTGRES_PORT:-5432}" +export REDIS_PORT="${REDIS_PORT:-6379}" +export DATABASE_URL="postgresql://huijing:huijing@localhost:${POSTGRES_PORT}/huijing_dev?schema=public" +export REDIS_URL="redis://localhost:${REDIS_PORT}" +docker compose -f infra/docker-compose.dev.yml up -d --wait +docker compose -f infra/docker-compose.dev.yml exec -T postgres pg_isready -U huijing -d huijing_dev +docker compose -f infra/docker-compose.dev.yml exec -T redis redis-cli ping +pnpm --filter @huijing/api exec prisma migrate deploy --schema prisma/schema.prisma +pnpm --filter @huijing/api exec prisma generate --schema prisma/schema.prisma +pnpm lint +pnpm typecheck +QUEUE_ADAPTER=bullmq pnpm test +pnpm build +pnpm dev:smoke +pnpm check:s1-scope +``` + +结果: + +- `pnpm install`:PASS。 + - 非阻塞提示:pnpm `10.33.0 -> 11.5.0` update notice。 + - 非阻塞 warning:`msgpackr-extract@3.0.4` ignored build scripts。 +- `pnpm check:workspace-scripts`:PASS。 +- Docker dev services: + - `infra-postgres-1` healthy on `5432`。 + - `infra-redis-1` healthy on `6379`。 +- `pg_isready`:PASS。 +- `redis-cli ping`:`PONG`。 +- Prisma migrate deploy:PASS,3 migrations found,No pending migrations。 +- Prisma generate:PASS,Prisma Client 7.8.0 generated。 +- `pnpm lint`:初次失败于 `apps/api/src/modules/jobs/index.ts:703 prefer-const`;fresh implementer 修复并通过两轮 review 后,重跑 PASS。 +- `pnpm typecheck`:PASS。 +- `QUEUE_ADAPTER=bullmq pnpm test`:PASS。 + - worker:1 file / 2 tests。 + - shared-contracts:1 file / 2 tests。 + - harness-client:1 file / 10 tests。 + - web:1 file / 2 tests。 + - api:15 files / 82 tests。 + - 非阻塞 warning:`pg@9` deprecation warning。 +- `pnpm build`:PASS。 +- `pnpm dev:smoke`:PASS。 + - API smoke 中仍出现同一个 `pg@9` deprecation warning。 +- `pnpm check:s1-scope`:PASS,`S1 scope check passed.`。 + +控制器额外探针: + +- optional raw call AuditLog delete:scanner failed as expected。 +- optional raw bind Job status update:scanner failed as expected。 +- bound raw alias AuditLog delete:scanner failed as expected。 +- dot whitespace raw AuditLog delete:scanner failed as expected。 +- bracket raw AuditLog delete:scanner failed as expected。 +- optional receiver / optional bracket raw write:scanner failed as expected。 +- no-semicolon dot / optional dot / bracket / optional bracket bound alias:scanner failed as expected。 +- dynamic read-only `SELECT`:scanner passed as expected。 + +## Cleanup / Runtime State + +- build/dev-smoke 产生的输出已清理: + - `apps/web/.next` + - `apps/api/dist` + - `apps/worker/dist` + - `packages/harness-client/dist` + - `packages/shared-contracts/dist` +- `apps/**` / `packages/**` 下无 `dist`、`.next` 构建输出残留。 +- `/tmp` 下无 `huijing-s1-scope-*`、`huijing-s1-probe-*`、`huijing-audit-scan-*`、`huijing-controller-s1-scope-*` 探针目录残留。 +- Docker dev services 保持运行且 healthy;未在本轮关闭。 + +## Residual Non-blocking Notes + +- 当前仓库大量 S1 workspace surface 仍是 untracked;`git diff` 对这些文件不能代表实际变更范围。 +- `.idea/`、`docs-design/` 和大量 untracked workspace surface 是前置工作面;本轮未回退或清理这些内容。 +- `pg@9` deprecation warning 仍存在,但所有相关测试命令 exit 0;升级 `pg@9` 前需要复查 Prisma adapter / 并发测试方式。 +- `msgpackr-extract@3.0.4` ignored build scripts warning 仍存在;当前验证未受影响。 +- Final reviewer 未重跑完整 `pnpm test/build`,避免重新写构建产物或扰动 dev DB;其基于控制器 full verification 与只读 spot-check 给出 PASS。 + +## SHA-256 + +| Path | SHA-256 | +| --- | --- | +| `scripts/check-s1-scope.mjs` | `e47eee55977f28b1d711f1bc7f4e1a330c1d51291d87f6a1fd2a95d80aa738fc` | +| `apps/api/src/modules/jobs/index.ts` | `dac1176331d0adc6ba7c79f0f7788ef9efd147492d3f36d1155902784820ae32` | +| `apps/api/src/modules/assets/assets.api.spec.ts` | `815109ff2eb27cba10837af862702908c6ea06556b1ae4e75ed51a46fdaed6d0` | +| `apps/api/src/modules/audit/audit.api.spec.ts` | `efa91e6e71851bc5d8ddab0bf6b18e8c1dd4a433712529ef8d39cd877506098d` | +| `apps/api/src/modules/jobs/jobs.api.spec.ts` | `5358ac8a1bd9d66821b7c7cafd2de57a79ceeb4585b90ae9e9d06d366663fe90` | +| `apps/api/src/modules/projects/projects.api.spec.ts` | `1facfbac8e6ddb8d9bb3bed3faf69af050efafb3d7ff48c46d6a58a60d5aab32` | +| `docs/superpowers/plans/2026-05-31-mvp-S1-app-foundation.md` | `868dc63fee64e254cf267d63db472aa46abf15977f1999785cfaea6fa1956a0a` | +| `docs/superpowers/specs/2026-05-31-mvp-S1-app-foundation-design.md` | `f514de72c36c5fd1ee6f3e87999b911f33d392549dbb76c6ee5d538dac774cdb` | +| `docs/superpowers/plans/2026-06-01-implementation-review-gate-protocol.md` | `c8726acc5457ab87fb8f26c2e439e1d1b98df0255af78e4d6e8d9636dc518478` | + +## Git Status Snapshot + +`git status --short` 显示: + +```text +A .idea/.gitignore +A .idea/games-development-ai.iml +A .idea/misc.xml +A .idea/modules.xml +A .idea/vcs.xml +A docs-design/* +AM docs-design/Deployment for AI.md +?? .gitignore +?? apps/ +?? docs/ +?? eslint.config.mjs +?? harness/ +?? infra/ +?? package.json +?? packages/ +?? pnpm-lock.yaml +?? pnpm-workspace.yaml +?? scripts/ +?? tsconfig.base.json +``` + diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..97e1eac0 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,24 @@ +import js from "@eslint/js"; +import tseslint from "typescript-eslint"; + +// 仅覆盖 S1 工作区源码;根脚本和未来特殊目录由各自配置单独处理。 +export default tseslint.config( + { + ignores: [ + "**/node_modules/**", + "**/dist/**", + "**/build/**", + "**/coverage/**", + "**/.next/**", + "**/.turbo/**" + ] + }, + { + files: ["apps/**/*.{ts,tsx}", "packages/**/*.{ts,tsx}"], + extends: [js.configs.recommended, tseslint.configs.recommended], + languageOptions: { + ecmaVersion: "latest", + sourceType: "module" + } + } +); diff --git a/infra/docker-compose.dev.yml b/infra/docker-compose.dev.yml new file mode 100644 index 00000000..a217584b --- /dev/null +++ b/infra/docker-compose.dev.yml @@ -0,0 +1,23 @@ +services: + postgres: + image: postgres:15 + environment: + POSTGRES_USER: huijing + POSTGRES_PASSWORD: huijing + POSTGRES_DB: huijing_dev + ports: + - "${POSTGRES_PORT:-5432}:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U huijing -d huijing_dev"] + interval: 5s + timeout: 3s + retries: 20 + redis: + image: redis:7 + ports: + - "${REDIS_PORT:-6379}:6379" + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 20 diff --git a/package.json b/package.json new file mode 100644 index 00000000..79941756 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "private": true, + "packageManager": "pnpm@10.33.0", + "scripts": { + "lint": "pnpm check:workspace-scripts && pnpm -r lint", + "typecheck": "pnpm check:workspace-scripts && pnpm -r typecheck", + "test": "pnpm check:workspace-scripts && pnpm -r test", + "build": "pnpm check:workspace-scripts && pnpm -r build", + "dev": "pnpm -r --parallel --if-present dev", + "dev:smoke": "pnpm check:workspace-scripts && pnpm -r dev:smoke", + "check:workspace-scripts": "node scripts/check-workspace-scripts.mjs", + "check:s1-scope": "node scripts/check-s1-scope.mjs" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "eslint": "^10.4.1", + "typescript": "^6.0.3", + "typescript-eslint": "^8.60.0" + } +} diff --git a/packages/harness-client/package.json b/packages/harness-client/package.json new file mode 100644 index 00000000..d4cec1ff --- /dev/null +++ b/packages/harness-client/package.json @@ -0,0 +1,26 @@ +{ + "name": "@huijing/harness-client", + "private": true, + "type": "module", + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + }, + "./runtime": { + "types": "./src/internal.ts", + "default": "./src/internal.ts" + } + }, + "scripts": { + "lint": "eslint .", + "typecheck": "tsc --noEmit", + "test": "vitest run", + "build": "tsc -p tsconfig.json", + "dev:smoke": "vitest run" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "vitest": "^4.1.7" + } +} diff --git a/packages/harness-client/src/index.spec.ts b/packages/harness-client/src/index.spec.ts new file mode 100644 index 00000000..91d84532 --- /dev/null +++ b/packages/harness-client/src/index.spec.ts @@ -0,0 +1,201 @@ +import { execFile } from "node:child_process"; +import { mkdtemp, readFile, rm, stat } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { afterEach, describe, expect, it } from "vitest"; +import { + HARNESS_INVALID_OUTPUT, + HARNESS_TIMEOUT, + createHarnessClient, + type ChildProcessRunner +} from "./internal"; + +const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const repoRoot = path.resolve(packageRoot, "../.."); +const fixturePath = (...segments: string[]) => path.join(repoRoot, "harness", "fixtures", ...segments); +const realHarnessCli = path.join(repoRoot, "harness", "scripts", "validate-harness.mjs"); + +async function readFixture(...segments: string[]): Promise { + return JSON.parse(await readFile(fixturePath(...segments), "utf8")); +} + +async function expectMissing(file: string): Promise { + await expect(stat(file)).rejects.toMatchObject({ code: "ENOENT" }); +} + +describe("@huijing/harness-client", () => { + const originalCwd = process.cwd(); + + afterEach(() => { + process.chdir(originalCwd); + }); + + it("通过真实 S0 fixture 调用 contract CLI,并在执行后删除临时 JSON 输入文件", async () => { + let observedInput: string | null = null; + const runner: ChildProcessRunner = async (file, args, options) => { + expect(file).toBe("node"); + expect(args.slice(0, 2)).toEqual([realHarnessCli, "--contract"]); + expect(args[2]).toBe("GameIR"); + expect(args[3]).toBe("--input"); + observedInput = args[4] ?? null; + expect(options.cwd).toBe(repoRoot); + expect(options.timeoutMs).toBe(5_000); + expect(options.maxOutputBytes).toBeGreaterThan(0); + expect(JSON.parse(await readFile(observedInput ?? "", "utf8"))).toEqual( + await readFixture("mvp", "valid", "simulation-game-ir-valid.json") + ); + + return new Promise((resolve) => { + execFile(file, args, { cwd: options.cwd }, (error, stdout, stderr) => { + resolve({ + timedOut: false, + exitCode: typeof error?.code === "number" ? error.code : 0, + stdout, + stderr + }); + }); + }); + }; + + const result = await createHarnessClient({ runner }).validateContract( + "GameIR", + await readFixture("mvp", "valid", "simulation-game-ir-valid.json") + ); + + expect(result).toEqual({ ok: true, reasonCode: null }); + expect(observedInput).toBeTruthy(); + await expectMissing(observedInput ?? ""); + }); + + it("通过真实 S0 failing fixture 解析非零退出 stdout JSON,并返回 fail-closed reasonCode", async () => { + const client = createHarnessClient(); + + await expect( + client.validateContract( + "ValidationReport", + await readFixture("mvp", "invalid", "game-logic-validation-report-web-only-sdk-invalid.json") + ) + ).resolves.toEqual({ ok: false, reasonCode: "WEB_ONLY_SDK_USAGE" }); + }); + + it("调用 transition CLI,使用真实 S0 review_approved fixture", async () => { + const client = createHarnessClient(); + + await expect( + client.validateTransition( + "review_approved", + await readFixture("lifecycle", "publish-approved-valid.json") + ) + ).resolves.toEqual({ ok: true, reasonCode: null }); + }); + + it("repo root 解析独立于当前工作目录", async () => { + const tempDir = await mkdtemp(path.join(os.tmpdir(), "huijing-cwd-")); + try { + process.chdir(tempDir); + const client = createHarnessClient(); + + await expect( + client.validateContract("GameIR", await readFixture("mvp", "valid", "simulation-game-ir-valid.json")) + ).resolves.toEqual({ ok: true, reasonCode: null }); + } finally { + await rm(tempDir, { recursive: true, force: true }); + } + }); + + it("timeout 返回稳定 HARNESS_TIMEOUT 并清理临时文件", async () => { + let observedInput: string | null = null; + const runner: ChildProcessRunner = async (_file, args) => { + observedInput = args[4] ?? null; + return { + timedOut: true, + stdout: "{\"ok\":true,\"reasonCode\":null}", + stderr: "" + }; + }; + + const result = await createHarnessClient({ runner, timeoutMs: 1 }).validateContract("GameIR", { id: "x" }); + + expect(result).toEqual({ ok: false, reasonCode: HARNESS_TIMEOUT }); + await expectMissing(observedInput ?? ""); + }); + + it("invalid JSON 或 invalid result shape 返回稳定 HARNESS_INVALID_OUTPUT", async () => { + const invalidJsonRunner: ChildProcessRunner = async () => ({ + timedOut: false, + stdout: "not json", + stderr: "" + }); + const invalidShapeRunner: ChildProcessRunner = async () => ({ + timedOut: false, + stdout: JSON.stringify({ ok: "yes", reasonCode: null }), + stderr: "" + }); + + await expect(createHarnessClient({ runner: invalidJsonRunner }).validateContract("GameIR", {})).resolves.toEqual({ + ok: false, + reasonCode: HARNESS_INVALID_OUTPUT + }); + await expect(createHarnessClient({ runner: invalidShapeRunner }).validateContract("GameIR", {})).resolves.toEqual({ + ok: false, + reasonCode: HARNESS_INVALID_OUTPUT + }); + }); + + it("stdout/stderr 超过上限时 fail closed,避免无界捕获子进程输出", async () => { + const runner: ChildProcessRunner = async () => ({ + timedOut: false, + stdout: `${JSON.stringify({ ok: true, reasonCode: null })}x`, + stderr: "too much" + }); + + await expect(createHarnessClient({ runner, maxOutputBytes: 16 }).validateContract("GameIR", {})).resolves.toEqual({ + ok: false, + reasonCode: HARNESS_INVALID_OUTPUT + }); + }); + + it("spawn error 不泄露为成功,返回稳定 HARNESS_INVALID_OUTPUT", async () => { + const runner: ChildProcessRunner = async () => { + throw new Error("spawn failed"); + }; + + await expect(createHarnessClient({ runner }).validateContract("GameIR", {})).resolves.toEqual({ + ok: false, + reasonCode: HARNESS_INVALID_OUTPUT + }); + }); + + it("源码不 import 或复制 S0 validator 内部实现", async () => { + const source = await readFile(path.join(packageRoot, "src", "internal.ts"), "utf8"); + + expect(source).not.toMatch(/from\s+["'].*validate-harness\.mjs["']/); + expect(source).not.toMatch(/import\s*\(["'].*validate-harness\.mjs["']\)/); + expect(source).not.toContain("validateAgainstSchema"); + expect(source).not.toContain("customContractRejection"); + expect(source).not.toContain("transitionList"); + }); + + it("包根只暴露 Task 5 指定的两个 public type 合同", async () => { + const source = await readFile(path.join(packageRoot, "src", "index.ts"), "utf8"); + const packageJson = JSON.parse(await readFile(path.join(packageRoot, "package.json"), "utf8")) as { + exports: Record; + }; + + expect(source).toContain("export type HarnessGateResult"); + expect(source).toContain("export type HarnessClient"); + expect(source).not.toMatch(/export\s+(const|function|class|interface)\s+/); + expect(source).not.toContain("createHarnessClient"); + expect(source).not.toContain("HARNESS_TIMEOUT"); + expect(source).not.toContain("ChildProcessRunner"); + expect(packageJson.exports["."]).toEqual({ + types: "./src/index.ts", + default: "./src/index.ts" + }); + expect(packageJson.exports["./runtime"]).toEqual({ + types: "./src/internal.ts", + default: "./src/internal.ts" + }); + }); +}); diff --git a/packages/harness-client/src/index.ts b/packages/harness-client/src/index.ts new file mode 100644 index 00000000..0d338379 --- /dev/null +++ b/packages/harness-client/src/index.ts @@ -0,0 +1,6 @@ +export type HarnessGateResult = { ok: boolean; reasonCode: string | null }; + +export type HarnessClient = { + validateContract(contract: string, payload: unknown): Promise; + validateTransition(event: string, payload: unknown): Promise; +}; diff --git a/packages/harness-client/src/internal.ts b/packages/harness-client/src/internal.ts new file mode 100644 index 00000000..50a621c0 --- /dev/null +++ b/packages/harness-client/src/internal.ts @@ -0,0 +1,181 @@ +import { spawn } from "node:child_process"; +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import type { HarnessClient, HarnessGateResult } from "./index.js"; + +export const HARNESS_TIMEOUT = "HARNESS_TIMEOUT" as const; +export const HARNESS_INVALID_OUTPUT = "HARNESS_INVALID_OUTPUT" as const; + +export type ChildProcessResult = { + readonly timedOut: boolean; + readonly exitCode?: number | null; + readonly stdout: string; + readonly stderr: string; +}; + +export type ChildProcessRunnerOptions = { + readonly cwd: string; + readonly timeoutMs: number; + readonly maxOutputBytes: number; +}; + +export type ChildProcessRunner = ( + file: string, + args: readonly string[], + options: ChildProcessRunnerOptions +) => Promise; + +export type HarnessClientOptions = { + readonly repoRoot?: string; + readonly timeoutMs?: number; + readonly maxOutputBytes?: number; + readonly runner?: ChildProcessRunner; +}; + +const defaultTimeoutMs = 5_000; +const defaultMaxOutputBytes = 64 * 1024; +const currentFile = fileURLToPath(import.meta.url); +const packageRoot = path.resolve(path.dirname(currentFile), ".."); +const defaultRepoRoot = path.resolve(packageRoot, "../.."); + +function byteLength(value: string): number { + return Buffer.byteLength(value, "utf8"); +} + +function appendBounded(current: string, chunk: Buffer, maxOutputBytes: number): string { + const next = current + chunk.toString("utf8"); + if (byteLength(next) <= maxOutputBytes) return next; + return next.slice(0, maxOutputBytes + 1); +} + +async function defaultRunner( + file: string, + args: readonly string[], + options: ChildProcessRunnerOptions +): Promise { + return new Promise((resolve, reject) => { + const child = spawn(file, [...args], { + cwd: options.cwd, + stdio: ["ignore", "pipe", "pipe"] + }); + + let stdout = ""; + let stderr = ""; + let timedOut = false; + + const timeout = setTimeout(() => { + timedOut = true; + child.kill("SIGKILL"); + }, options.timeoutMs); + + child.stdout.on("data", (chunk: Buffer) => { + stdout = appendBounded(stdout, chunk, options.maxOutputBytes); + if (byteLength(stdout) > options.maxOutputBytes) child.kill("SIGKILL"); + }); + + child.stderr.on("data", (chunk: Buffer) => { + stderr = appendBounded(stderr, chunk, options.maxOutputBytes); + if (byteLength(stderr) > options.maxOutputBytes) child.kill("SIGKILL"); + }); + + child.on("error", (error) => { + clearTimeout(timeout); + reject(error); + }); + + child.on("close", (exitCode) => { + clearTimeout(timeout); + resolve({ + timedOut, + exitCode, + stdout, + stderr + }); + }); + }); +} + +function parseHarnessOutput(result: ChildProcessResult, maxOutputBytes: number): HarnessGateResult { + if (result.timedOut) return { ok: false, reasonCode: HARNESS_TIMEOUT }; + if (byteLength(result.stdout) > maxOutputBytes || byteLength(result.stderr) > maxOutputBytes) { + return { ok: false, reasonCode: HARNESS_INVALID_OUTPUT }; + } + + let parsed: unknown; + try { + parsed = JSON.parse(result.stdout); + } catch { + return { ok: false, reasonCode: HARNESS_INVALID_OUTPUT }; + } + + if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) { + return { ok: false, reasonCode: HARNESS_INVALID_OUTPUT }; + } + + const value = parsed as { ok?: unknown; reasonCode?: unknown }; + if (typeof value.ok !== "boolean") return { ok: false, reasonCode: HARNESS_INVALID_OUTPUT }; + if (value.reasonCode !== null && typeof value.reasonCode !== "string") { + return { ok: false, reasonCode: HARNESS_INVALID_OUTPUT }; + } + if (!value.ok && value.reasonCode === null) return { ok: false, reasonCode: HARNESS_INVALID_OUTPUT }; + if (value.ok && result.exitCode !== undefined && result.exitCode !== null && result.exitCode !== 0) { + return { ok: false, reasonCode: HARNESS_INVALID_OUTPUT }; + } + + return { + ok: value.ok, + reasonCode: value.reasonCode + }; +} + +async function withTempJson(payload: unknown, run: (file: string) => Promise): Promise { + const dir = await mkdtemp(path.join(os.tmpdir(), "huijing-harness-")); + const file = path.join(dir, "payload.json"); + + try { + await writeFile(file, JSON.stringify(payload), "utf8"); + return await run(file); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +export function createHarnessClient(options: HarnessClientOptions = {}): HarnessClient { + const repoRoot = options.repoRoot ?? defaultRepoRoot; + const timeoutMs = options.timeoutMs ?? defaultTimeoutMs; + const maxOutputBytes = options.maxOutputBytes ?? defaultMaxOutputBytes; + const runner = options.runner ?? defaultRunner; + const harnessCli = path.join(repoRoot, "harness", "scripts", "validate-harness.mjs"); + + async function validate(kind: "contract" | "transition", name: string, payload: unknown): Promise { + return withTempJson(payload, async (inputFile) => { + const args = + kind === "contract" + ? [harnessCli, "--contract", name, "--input", inputFile] + : [harnessCli, "--transition", name, "--input", inputFile]; + + try { + const result = await runner("node", args, { + cwd: repoRoot, + timeoutMs, + maxOutputBytes + }); + return parseHarnessOutput(result, maxOutputBytes); + } catch { + // 子进程启动失败时无法证明 S0 gate 通过,必须 fail closed。 + return { ok: false, reasonCode: HARNESS_INVALID_OUTPUT }; + } + }); + } + + return { + validateContract(contract: string, payload: unknown) { + return validate("contract", contract, payload); + }, + validateTransition(event: string, payload: unknown) { + return validate("transition", event, payload); + } + }; +} diff --git a/packages/harness-client/tsconfig.json b/packages/harness-client/tsconfig.json new file mode 100644 index 00000000..43f2363b --- /dev/null +++ b/packages/harness-client/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist", "src/**/*.spec.ts"] +} diff --git a/packages/shared-contracts/package.json b/packages/shared-contracts/package.json new file mode 100644 index 00000000..2a6d49bc --- /dev/null +++ b/packages/shared-contracts/package.json @@ -0,0 +1,22 @@ +{ + "name": "@huijing/shared-contracts", + "private": true, + "type": "module", + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "scripts": { + "lint": "eslint .", + "typecheck": "tsc --noEmit", + "test": "vitest run", + "build": "tsc -p tsconfig.json", + "dev:smoke": "vitest run" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "vitest": "^4.1.7" + } +} diff --git a/packages/shared-contracts/src/index.spec.ts b/packages/shared-contracts/src/index.spec.ts new file mode 100644 index 00000000..d4ae76ec --- /dev/null +++ b/packages/shared-contracts/src/index.spec.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from "vitest"; +import { S1_PACKAGE_NAMES, S1_WORKSPACE_KEYS, isS1PackageName } from "./index"; + +describe("@huijing/shared-contracts S1 exports", () => { + it("exports stable S1 package names", () => { + expect(S1_PACKAGE_NAMES).toEqual({ + api: "@huijing/api", + harnessClient: "@huijing/harness-client", + sharedContracts: "@huijing/shared-contracts", + web: "@huijing/web", + worker: "@huijing/worker" + }); + }); + + it("checks whether a value is an S1 package name", () => { + expect(S1_WORKSPACE_KEYS).toEqual(["web", "api", "worker", "sharedContracts", "harnessClient"]); + expect(isS1PackageName("@huijing/api")).toBe(true); + expect(isS1PackageName("@huijing/missing")).toBe(false); + }); +}); diff --git a/packages/shared-contracts/src/index.ts b/packages/shared-contracts/src/index.ts new file mode 100644 index 00000000..e7868ad9 --- /dev/null +++ b/packages/shared-contracts/src/index.ts @@ -0,0 +1,18 @@ +export const S1_PACKAGE_NAMES = { + api: "@huijing/api", + harnessClient: "@huijing/harness-client", + sharedContracts: "@huijing/shared-contracts", + web: "@huijing/web", + worker: "@huijing/worker" +} as const; + +export const S1_WORKSPACE_KEYS = ["web", "api", "worker", "sharedContracts", "harnessClient"] as const; + +export type S1WorkspaceKey = (typeof S1_WORKSPACE_KEYS)[number]; +export type S1PackageName = (typeof S1_PACKAGE_NAMES)[S1WorkspaceKey]; + +const S1_PACKAGE_NAME_SET: ReadonlySet = new Set(Object.values(S1_PACKAGE_NAMES)); + +export function isS1PackageName(value: string): value is S1PackageName { + return S1_PACKAGE_NAME_SET.has(value); +} diff --git a/packages/shared-contracts/tsconfig.json b/packages/shared-contracts/tsconfig.json new file mode 100644 index 00000000..43f2363b --- /dev/null +++ b/packages/shared-contracts/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist", "src/**/*.spec.ts"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..e5a3c4d0 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4053 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@eslint/js': + specifier: ^10.0.1 + version: 10.0.1(eslint@10.4.1(jiti@2.7.0)) + eslint: + specifier: ^10.4.1 + version: 10.4.1(jiti@2.7.0) + typescript: + specifier: ^6.0.3 + version: 6.0.3 + typescript-eslint: + specifier: ^8.60.0 + version: 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + + apps/api: + dependencies: + '@huijing/harness-client': + specifier: workspace:* + version: link:../../packages/harness-client + '@nestjs/common': + specifier: ^11.1.24 + version: 11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^11.1.24 + version: 11.1.24(@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^11.1.24 + version: 11.1.24(@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) + '@prisma/adapter-pg': + specifier: 7.8.0 + version: 7.8.0 + '@prisma/client': + specifier: 7.8.0 + version: 7.8.0(prisma@7.8.0(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@6.0.3))(typescript@6.0.3) + bullmq: + specifier: ^5.77.6 + version: 5.77.6 + ioredis: + specifier: ^5.11.0 + version: 5.11.0 + pg: + specifier: ^8.21.0 + version: 8.21.0 + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.2 + version: 7.8.2 + devDependencies: + '@nestjs/testing': + specifier: ^11.1.24 + version: 11.1.24(@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(@nestjs/platform-express@11.1.24) + '@types/node': + specifier: ^25.9.1 + version: 25.9.1 + '@types/pg': + specifier: ^8.20.0 + version: 8.20.0 + prisma: + specifier: ^7.8.0 + version: 7.8.0(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + vitest: + specifier: ^4.1.7 + version: 4.1.7(@types/node@25.9.1)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)) + + apps/web: + dependencies: + '@huijing/shared-contracts': + specifier: workspace:* + version: link:../../packages/shared-contracts + next: + specifier: ^16.2.6 + version: 16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: + specifier: ^19.2.6 + version: 19.2.6 + react-dom: + specifier: ^19.2.6 + version: 19.2.6(react@19.2.6) + devDependencies: + '@types/node': + specifier: ^25.9.1 + version: 25.9.1 + '@types/react': + specifier: ^19.2.15 + version: 19.2.15 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.15) + vitest: + specifier: ^4.1.7 + version: 4.1.7(@types/node@25.9.1)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)) + + apps/worker: + devDependencies: + '@types/node': + specifier: ^25.9.1 + version: 25.9.1 + vitest: + specifier: ^4.1.7 + version: 4.1.7(@types/node@25.9.1)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)) + + packages/harness-client: + devDependencies: + '@types/node': + specifier: ^25.9.1 + version: 25.9.1 + vitest: + specifier: ^4.1.7 + version: 4.1.7(@types/node@25.9.1)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)) + + packages/shared-contracts: + devDependencies: + '@types/node': + specifier: ^25.9.1 + version: 25.9.1 + vitest: + specifier: ^4.1.7 + version: 4.1.7(@types/node@25.9.1)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)) + +packages: + + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + + '@electric-sql/pglite-socket@0.1.1': + resolution: {integrity: sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw==} + hasBin: true + peerDependencies: + '@electric-sql/pglite': 0.4.1 + + '@electric-sql/pglite-tools@0.3.1': + resolution: {integrity: sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA==} + peerDependencies: + '@electric-sql/pglite': 0.4.1 + + '@electric-sql/pglite@0.4.1': + resolution: {integrity: sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/config-helpers@0.6.0': + resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/plugin-kit@0.7.2': + resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@hono/node-server@1.19.11': + resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@ioredis/commands@1.10.0': + resolution: {integrity: sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==} + + '@ioredis/commands@1.5.1': + resolution: {integrity: sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@kurkle/color@0.3.4': + resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} + + '@lukeed/csprng@1.1.0': + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': + resolution: {integrity: sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==} + cpu: [arm64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4': + resolution: {integrity: sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==} + cpu: [x64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4': + resolution: {integrity: sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==} + cpu: [arm64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4': + resolution: {integrity: sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==} + cpu: [arm] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4': + resolution: {integrity: sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==} + cpu: [x64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': + resolution: {integrity: sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==} + cpu: [x64] + os: [win32] + + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@nestjs/common@11.1.24': + resolution: {integrity: sha512-9zHxaDDM+oXW9As6UsP5yYB+UqczBmpeSCIFWdPEtEukMnZhxODG1BBjaUcdBB8Sc1uzojSJSJlp3yFp853t1g==} + peerDependencies: + class-transformer: '>=0.4.1' + class-validator: '>=0.13.2' + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/core@11.1.24': + resolution: {integrity: sha512-K4bzT+lEdd0Hhcsw3jtk56QAW6s6skK3ViN7hIROSN0kUf4ROwWEAKopJID6yhPQxB45kDtP2wEcjzE8171J3g==} + engines: {node: '>= 20'} + peerDependencies: + '@nestjs/common': ^11.0.0 + '@nestjs/microservices': ^11.0.0 + '@nestjs/platform-express': ^11.0.0 + '@nestjs/websockets': ^11.0.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + '@nestjs/websockets': + optional: true + + '@nestjs/platform-express@11.1.24': + resolution: {integrity: sha512-CeMKbRBm05aOBiWhIHWO2xDeHbxynBF9ySQv3gRjObz2N5+uJnYriAYkHvVqvC4JIydmMPmT5VdICFNlNz3qyA==} + peerDependencies: + '@nestjs/common': ^11.0.0 + '@nestjs/core': ^11.0.0 + + '@nestjs/testing@11.1.24': + resolution: {integrity: sha512-+4M4UAnhtprBQN0J2uI6IP0wDqhy9aH8XCMu5SO8oCi0oB04YXA4a4PAEkxmsPn7gHW4dj1u4GFteNQOWgvTJw==} + peerDependencies: + '@nestjs/common': ^11.0.0 + '@nestjs/core': ^11.0.0 + '@nestjs/microservices': ^11.0.0 + '@nestjs/platform-express': ^11.0.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + + '@next/env@16.2.6': + resolution: {integrity: sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==} + + '@next/swc-darwin-arm64@16.2.6': + resolution: {integrity: sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@16.2.6': + resolution: {integrity: sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@16.2.6': + resolution: {integrity: sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@16.2.6': + resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@16.2.6': + resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@16.2.6': + resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@16.2.6': + resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@16.2.6': + resolution: {integrity: sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nuxt/opencollective@0.4.1': + resolution: {integrity: sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ==} + engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} + hasBin: true + + '@oxc-project/types@0.132.0': + resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} + + '@prisma/adapter-pg@7.8.0': + resolution: {integrity: sha512-ygb3UkerK3v8MDpXVgCISdRNDozpxh6+JVJgiIGbSr5KBgz10LLf5ejUskPGoXlsIjxsOu6nuy1JVQr2EKGSlg==} + + '@prisma/client-runtime-utils@7.8.0': + resolution: {integrity: sha512-5NQZztQ0oY/ADFkmd9gPuweH5A1/CCY8YQPorLLO0Mu6a87mY5gsnDkzmFmIHs9NFaLnZojzgddFVN4RpKYrdw==} + + '@prisma/client@7.8.0': + resolution: {integrity: sha512-HFp3Dawv/3sU3JtlPha90IB+48lS7zHiH4LKZPjmcE8YH5P9DOXGPvo8dqOtO7MqLDd1p2hOWMcFlRT1DMblHw==} + engines: {node: ^20.19 || ^22.12 || >=24.0} + peerDependencies: + prisma: '*' + typescript: '>=5.4.0' + peerDependenciesMeta: + prisma: + optional: true + typescript: + optional: true + + '@prisma/config@7.8.0': + resolution: {integrity: sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw==} + + '@prisma/debug@7.2.0': + resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==} + + '@prisma/debug@7.8.0': + resolution: {integrity: sha512-p+QZReysDUqXC+mk17q9a+Y/qzh4c2KYliDK30buYUyfrGeTGSyfmc0AIrJRhZJrLHhRiJa9Au/J72h3C+szvA==} + + '@prisma/dev@0.24.3': + resolution: {integrity: sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==} + + '@prisma/driver-adapter-utils@7.8.0': + resolution: {integrity: sha512-/Q13o0ZT0rjc1Xk0Q9KhZYwuq2EW/vSbWUBKfgEKkaCuB/Sg6bqnjmTZqC5cD4d6y1vfFAEwBRzfzoSMIVJ55A==} + + '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': + resolution: {integrity: sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA==} + + '@prisma/engines@7.8.0': + resolution: {integrity: sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw==} + + '@prisma/fetch-engine@7.8.0': + resolution: {integrity: sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ==} + + '@prisma/get-platform@7.2.0': + resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} + + '@prisma/get-platform@7.8.0': + resolution: {integrity: sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==} + + '@prisma/query-plan-executor@7.2.0': + resolution: {integrity: sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==} + + '@prisma/streams-local@0.1.2': + resolution: {integrity: sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg==} + engines: {bun: '>=1.3.6', node: '>=22.0.0'} + + '@prisma/studio-core@0.27.3': + resolution: {integrity: sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw==} + engines: {node: ^20.19 || ^22.12 || >=24.0, pnpm: '8'} + peerDependencies: + '@types/react': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-toggle@1.1.10': + resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@rolldown/binding-android-arm64@1.0.2': + resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.2': + resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.2': + resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.2': + resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.2': + resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.2': + resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.2': + resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.2': + resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.2': + resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.2': + resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.2': + resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.2': + resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.2': + resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.2': + resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@25.9.1': + resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==} + + '@types/pg@8.20.0': + resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.15': + resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==} + + '@typescript-eslint/eslint-plugin@8.60.0': + resolution: {integrity: sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.60.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.60.0': + resolution: {integrity: sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.60.0': + resolution: {integrity: sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.60.0': + resolution: {integrity: sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.60.0': + resolution: {integrity: sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.60.0': + resolution: {integrity: sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.60.0': + resolution: {integrity: sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.60.0': + resolution: {integrity: sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.60.0': + resolution: {integrity: sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.60.0': + resolution: {integrity: sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@vitest/expect@4.1.7': + resolution: {integrity: sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==} + + '@vitest/mocker@4.1.7': + resolution: {integrity: sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.7': + resolution: {integrity: sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==} + + '@vitest/runner@4.1.7': + resolution: {integrity: sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==} + + '@vitest/snapshot@4.1.7': + resolution: {integrity: sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==} + + '@vitest/spy@4.1.7': + resolution: {integrity: sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==} + + '@vitest/utils@4.1.7': + resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + append-field@1.0.0: + resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.10.33: + resolution: {integrity: sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==} + engines: {node: '>=6.0.0'} + hasBin: true + + better-result@2.9.2: + resolution: {integrity: sha512-WIFoBPCdnTOdk9inkE1ZRvCZ4P0CpSkAiLlchC65N7n9DcjZ3NhqkBOlafzpOVnO8ixyi37kicmSJ3ENhPZl7Q==} + + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + bullmq@5.77.6: + resolution: {integrity: sha512-WCpSoCD4vWyRD+btOsFrO7iBGInrTgG155gTZCV8qY0Yex2KtsbVtFERx6V1WZ2xWl/5ZxnLar8Z8ufnS4f5jg==} + engines: {node: '>=12.22.0'} + peerDependencies: + redis: '>=5.0.0' + peerDependenciesMeta: + redis: + optional: true + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + c12@3.3.4: + resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} + peerDependencies: + magicast: '*' + peerDependenciesMeta: + magicast: + optional: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + chart.js@4.5.1: + resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==} + engines: {pnpm: '>=8'} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + cluster-key-slot@1.1.1: + resolution: {integrity: sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==} + engines: {node: '>=0.10.0'} + + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + + concat-stream@2.0.0: + resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} + engines: {'0': node >= 6.0} + + 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} + + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + cron-parser@4.9.0: + resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} + engines: {node: '>=12.0.0'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + 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'} + + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + effect@3.20.0: + resolution: {integrity: sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==} + + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.4.1: + resolution: {integrity: sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + file-type@21.3.4: + resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} + engines: {node: '>=20'} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + giget@3.2.0: + resolution: {integrity: sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==} + hasBin: true + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + grammex@3.1.12: + resolution: {integrity: sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==} + + graphmatch@1.1.1: + resolution: {integrity: sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hono@4.12.23: + resolution: {integrity: sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==} + engines: {node: '>=16.9.0'} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + http-status-codes@2.3.0: + resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==} + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ioredis@5.10.1: + resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} + engines: {node: '>=12.22.0'} + + ioredis@5.11.0: + resolution: {integrity: sha512-EZBErytyVovD8f6pDfG3Kb37N6Y3lmDA9NNj+4+IP13CzzHGeX+OyeRM2Um13khRzoBSzzL+5lVnCX8V2RLeMg==} + engines: {node: '>=12.22.0'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + iterare@1.2.1: + resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} + engines: {node: '>=6'} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + load-esm@1.0.3: + resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} + engines: {node: '>=13.2.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + lru.min@1.1.4: + resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + + luxon@3.7.2: + resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} + engines: {node: '>=12'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + msgpackr-extract@3.0.4: + resolution: {integrity: sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==} + hasBin: true + + msgpackr@2.0.1: + resolution: {integrity: sha512-9J+tqTEsbHqY8YohazYgty7LgerFIWxvMLpUjqETSmjHojtJm2WnX2kK/2a1fLI7CO7ERP1YSEUXMucz4j+yBA==} + + multer@2.1.1: + resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==} + engines: {node: '>= 10.16.0'} + + mysql2@3.15.3: + resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} + engines: {node: '>= 8.0'} + + named-placeholders@1.1.6: + resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} + engines: {node: '>=8.0.0'} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + next@16.2.6: + resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==} + engines: {node: '>=20.9.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + + node-gyp-build-optional-packages@5.2.2: + resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} + hasBin: true + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + + pg-cloudflare@1.4.0: + resolution: {integrity: sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==} + + pg-connection-string@2.13.0: + resolution: {integrity: sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.14.0: + resolution: {integrity: sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.14.0: + resolution: {integrity: sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.21.0: + resolution: {integrity: sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA==} + 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==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-array@3.0.4: + resolution: {integrity: sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==} + engines: {node: '>=12'} + + 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'} + + postgres@3.4.7: + resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} + engines: {node: '>=12'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prisma@7.8.0: + resolution: {integrity: sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==} + engines: {node: ^20.19 || ^22.12 || >=24.0} + hasBin: true + peerDependencies: + better-sqlite3: '>=9.0.0' + typescript: '>=5.4.0' + peerDependenciesMeta: + better-sqlite3: + optional: true + typescript: + optional: true + + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + qs@6.15.2: + resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} + engines: {node: '>=0.6'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + rc9@3.0.1: + resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} + + react-dom@19.2.6: + resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} + peerDependencies: + react: ^19.2.6 + + react@19.2.6: + resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} + engines: {node: '>=0.10.0'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + + redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + + remeda@2.33.4: + resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + rolldown@1.0.2: + resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@7.8.0: + resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} + engines: {node: '>=10'} + hasBin: true + + semver@7.8.1: + resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} + engines: {node: '>=18'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + 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'} + + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + + typescript-eslint@8.60.0: + resolution: {integrity: sha512-9f65qWLZdAW9m1JaxBDUHcqRUfL8bkxxXL7XxEfI+F09q56PkBvIfCjLF3yInsDM/BBmwkqmCQdCZe/RYlIWEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + uid@2.0.2: + resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} + engines: {node: '>=8'} + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + valibot@1.2.0: + resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite@8.0.14: + resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.7: + resolution: {integrity: sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.7 + '@vitest/browser-preview': 4.1.7 + '@vitest/browser-webdriverio': 4.1.7 + '@vitest/coverage-istanbul': 4.1.7 + '@vitest/coverage-v8': 4.1.7 + '@vitest/ui': 4.1.7 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zeptomatch@2.1.0: + resolution: {integrity: sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==} + +snapshots: + + '@borewit/text-codec@0.2.2': {} + + '@electric-sql/pglite-socket@0.1.1(@electric-sql/pglite@0.4.1)': + dependencies: + '@electric-sql/pglite': 0.4.1 + + '@electric-sql/pglite-tools@0.3.1(@electric-sql/pglite@0.4.1)': + dependencies: + '@electric-sql/pglite': 0.4.1 + + '@electric-sql/pglite@0.4.1': {} + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@10.4.1(jiti@2.7.0))': + dependencies: + eslint: 10.4.1(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.23.5': + dependencies: + '@eslint/object-schema': 3.0.5 + debug: 4.4.3 + minimatch: 10.2.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.6.0': + dependencies: + '@eslint/core': 1.2.1 + + '@eslint/core@1.2.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/js@10.0.1(eslint@10.4.1(jiti@2.7.0))': + optionalDependencies: + eslint: 10.4.1(jiti@2.7.0) + + '@eslint/object-schema@3.0.5': {} + + '@eslint/plugin-kit@0.7.2': + dependencies: + '@eslint/core': 1.2.1 + levn: 0.4.1 + + '@hono/node-server@1.19.11(hono@4.12.23)': + dependencies: + hono: 4.12.23 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.10.0 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@ioredis/commands@1.10.0': {} + + '@ioredis/commands@1.5.1': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@kurkle/color@0.3.4': {} + + '@lukeed/csprng@1.1.0': {} + + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': + optional: true + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4': + optional: true + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': + optional: true + + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + file-type: 21.3.4 + iterare: 1.2.1 + load-esm: 1.0.3 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + transitivePeerDependencies: + - supports-color + + '@nestjs/core@11.1.24(@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nuxt/opencollective': 0.4.1 + fast-safe-stringify: 2.1.1 + iterare: 1.2.1 + path-to-regexp: 8.4.2 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + '@nestjs/platform-express': 11.1.24(@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) + + '@nestjs/platform-express@11.1.24(@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)': + dependencies: + '@nestjs/common': 11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) + cors: 2.8.6 + express: 5.2.1 + multer: 2.1.1 + path-to-regexp: 8.4.2 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@nestjs/testing@11.1.24(@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24)(@nestjs/platform-express@11.1.24)': + dependencies: + '@nestjs/common': 11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.24(@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.24)(reflect-metadata@0.2.2)(rxjs@7.8.2) + tslib: 2.8.1 + optionalDependencies: + '@nestjs/platform-express': 11.1.24(@nestjs/common@11.1.24(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.24) + + '@next/env@16.2.6': {} + + '@next/swc-darwin-arm64@16.2.6': + optional: true + + '@next/swc-darwin-x64@16.2.6': + optional: true + + '@next/swc-linux-arm64-gnu@16.2.6': + optional: true + + '@next/swc-linux-arm64-musl@16.2.6': + optional: true + + '@next/swc-linux-x64-gnu@16.2.6': + optional: true + + '@next/swc-linux-x64-musl@16.2.6': + optional: true + + '@next/swc-win32-arm64-msvc@16.2.6': + optional: true + + '@next/swc-win32-x64-msvc@16.2.6': + optional: true + + '@nuxt/opencollective@0.4.1': + dependencies: + consola: 3.4.2 + + '@oxc-project/types@0.132.0': {} + + '@prisma/adapter-pg@7.8.0': + dependencies: + '@prisma/driver-adapter-utils': 7.8.0 + '@types/pg': 8.20.0 + pg: 8.21.0 + postgres-array: 3.0.4 + transitivePeerDependencies: + - pg-native + + '@prisma/client-runtime-utils@7.8.0': {} + + '@prisma/client@7.8.0(prisma@7.8.0(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@6.0.3))(typescript@6.0.3)': + dependencies: + '@prisma/client-runtime-utils': 7.8.0 + optionalDependencies: + prisma: 7.8.0(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@6.0.3) + typescript: 6.0.3 + + '@prisma/config@7.8.0': + dependencies: + c12: 3.3.4 + deepmerge-ts: 7.1.5 + effect: 3.20.0 + empathic: 2.0.0 + transitivePeerDependencies: + - magicast + + '@prisma/debug@7.2.0': {} + + '@prisma/debug@7.8.0': {} + + '@prisma/dev@0.24.3(typescript@6.0.3)': + dependencies: + '@electric-sql/pglite': 0.4.1 + '@electric-sql/pglite-socket': 0.1.1(@electric-sql/pglite@0.4.1) + '@electric-sql/pglite-tools': 0.3.1(@electric-sql/pglite@0.4.1) + '@hono/node-server': 1.19.11(hono@4.12.23) + '@prisma/get-platform': 7.2.0 + '@prisma/query-plan-executor': 7.2.0 + '@prisma/streams-local': 0.1.2 + foreground-child: 3.3.1 + get-port-please: 3.2.0 + hono: 4.12.23 + http-status-codes: 2.3.0 + pathe: 2.0.3 + proper-lockfile: 4.1.2 + remeda: 2.33.4 + std-env: 3.10.0 + valibot: 1.2.0(typescript@6.0.3) + zeptomatch: 2.1.0 + transitivePeerDependencies: + - typescript + + '@prisma/driver-adapter-utils@7.8.0': + dependencies: + '@prisma/debug': 7.8.0 + + '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': {} + + '@prisma/engines@7.8.0': + dependencies: + '@prisma/debug': 7.8.0 + '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a + '@prisma/fetch-engine': 7.8.0 + '@prisma/get-platform': 7.8.0 + + '@prisma/fetch-engine@7.8.0': + dependencies: + '@prisma/debug': 7.8.0 + '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a + '@prisma/get-platform': 7.8.0 + + '@prisma/get-platform@7.2.0': + dependencies: + '@prisma/debug': 7.2.0 + + '@prisma/get-platform@7.8.0': + dependencies: + '@prisma/debug': 7.8.0 + + '@prisma/query-plan-executor@7.2.0': {} + + '@prisma/streams-local@0.1.2': + dependencies: + ajv: 8.20.0 + better-result: 2.9.2 + env-paths: 3.0.0 + proper-lockfile: 4.1.2 + + '@prisma/studio-core@0.27.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@types/react': 19.2.15 + chart.js: 4.5.1 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + transitivePeerDependencies: + - '@types/react-dom' + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.15)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.15 + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.15 + '@types/react-dom': 19.2.3(@types/react@19.2.15) + + '@radix-ui/react-slot@1.2.3(@types/react@19.2.15)(react@19.2.6)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.15 + + '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.15 + '@types/react-dom': 19.2.3(@types/react@19.2.15) + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.15)(react@19.2.6)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.15)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.15 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.15)(react@19.2.6)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.15 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.15)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 19.2.15 + + '@rolldown/binding-android-arm64@1.0.2': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.2': + optional: true + + '@rolldown/binding-darwin-x64@1.0.2': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.2': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.2': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.2': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.2': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.2': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.2': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.2': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.2': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.2': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.2': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@standard-schema/spec@1.1.0': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/esrecurse@4.3.1': {} + + '@types/estree@1.0.9': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@25.9.1': + dependencies: + undici-types: 7.24.6 + + '@types/pg@8.20.0': + dependencies: + '@types/node': 25.9.1 + pg-protocol: 1.14.0 + pg-types: 2.2.0 + + '@types/react-dom@19.2.3(@types/react@19.2.15)': + dependencies: + '@types/react': 19.2.15 + + '@types/react@19.2.15': + dependencies: + csstype: 3.2.3 + + '@typescript-eslint/eslint-plugin@8.60.0(@typescript-eslint/parser@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.60.0 + '@typescript-eslint/type-utils': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.60.0 + eslint: 10.4.1(jiti@2.7.0) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.60.0 + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.60.0 + debug: 4.4.3 + eslint: 10.4.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.60.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.60.0(typescript@6.0.3) + '@typescript-eslint/types': 8.60.0 + debug: 4.4.3 + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.60.0': + dependencies: + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/visitor-keys': 8.60.0 + + '@typescript-eslint/tsconfig-utils@8.60.0(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + + '@typescript-eslint/type-utils@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + debug: 4.4.3 + eslint: 10.4.1(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.60.0': {} + + '@typescript-eslint/typescript-estree@8.60.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.60.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.60.0(typescript@6.0.3) + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/visitor-keys': 8.60.0 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.1 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.60.0 + '@typescript-eslint/types': 8.60.0 + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + eslint: 10.4.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.60.0': + dependencies: + '@typescript-eslint/types': 8.60.0 + eslint-visitor-keys: 5.0.1 + + '@vitest/expect@4.1.7': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.7(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0))': + dependencies: + '@vitest/spy': 4.1.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.14(@types/node@25.9.1)(jiti@2.7.0) + + '@vitest/pretty-format@4.1.7': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.7': + dependencies: + '@vitest/utils': 4.1.7 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.7': + dependencies: + '@vitest/pretty-format': 4.1.7 + '@vitest/utils': 4.1.7 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.7': {} + + '@vitest/utils@4.1.7': + dependencies: + '@vitest/pretty-format': 4.1.7 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.2 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + append-field@1.0.0: {} + + assertion-error@2.0.1: {} + + aws-ssl-profiles@1.1.2: {} + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.10.33: {} + + better-result@2.9.2: {} + + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.2 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + + buffer-from@1.1.2: {} + + bullmq@5.77.6: + dependencies: + cron-parser: 4.9.0 + ioredis: 5.10.1 + msgpackr: 2.0.1 + node-abort-controller: 3.1.1 + semver: 7.8.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + bytes@3.1.2: {} + + c12@3.3.4: + dependencies: + chokidar: 5.0.0 + confbox: 0.2.4 + defu: 6.1.7 + dotenv: 17.4.2 + exsolve: 1.0.8 + giget: 3.2.0 + jiti: 2.7.0 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.1 + rc9: 3.0.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + caniuse-lite@1.0.30001793: {} + + chai@6.2.2: {} + + chart.js@4.5.1: + dependencies: + '@kurkle/color': 0.3.4 + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + client-only@0.0.1: {} + + cluster-key-slot@1.1.1: {} + + cluster-key-slot@1.1.2: {} + + concat-stream@2.0.0: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + typedarray: 0.0.6 + + confbox@0.2.4: {} + + consola@3.4.2: {} + + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.0.0: {} + + convert-source-map@2.0.0: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cron-parser@4.9.0: + dependencies: + luxon: 3.7.2 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + deepmerge-ts@7.1.5: {} + + defu@6.1.7: {} + + denque@2.1.0: {} + + depd@2.0.0: {} + + destr@2.0.5: {} + + detect-libc@2.1.2: {} + + dotenv@17.4.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + effect@3.20.0: + dependencies: + '@standard-schema/spec': 1.1.0 + fast-check: 3.23.2 + + empathic@2.0.0: {} + + encodeurl@2.0.0: {} + + env-paths@3.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@2.1.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + eslint-scope@9.1.2: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@10.4.1(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.4.1(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.6.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.2 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@11.2.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 5.0.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + esutils@2.0.3: {} + + etag@1.8.1: {} + + expect-type@1.3.0: {} + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.2 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + exsolve@1.0.8: {} + + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-safe-stringify@2.1.1: {} + + fast-uri@3.1.2: {} + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + file-type@21.3.4: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + + flatted@3.4.2: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-port-please@3.2.0: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + giget@3.2.0: {} + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + grammex@3.1.12: {} + + graphmatch@1.1.1: {} + + has-symbols@1.1.0: {} + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hono@4.12.23: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + http-status-codes@2.3.0: {} + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + imurmurhash@0.1.4: {} + + inherits@2.0.4: {} + + ioredis@5.10.1: + dependencies: + '@ioredis/commands': 1.5.1 + cluster-key-slot: 1.1.2 + debug: 4.4.3 + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + + ioredis@5.11.0: + dependencies: + '@ioredis/commands': 1.10.0 + cluster-key-slot: 1.1.1 + debug: 4.4.3 + denque: 2.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + + ipaddr.js@1.9.1: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-promise@4.0.0: {} + + is-property@1.0.2: {} + + isexe@2.0.0: {} + + iterare@1.2.1: {} + + jiti@2.7.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + load-esm@1.0.3: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.defaults@4.2.0: {} + + lodash.isarguments@3.1.0: {} + + long@5.3.2: {} + + lru.min@1.1.4: {} + + luxon@3.7.2: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + media-typer@0.3.0: {} + + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + + mime-db@1.52.0: {} + + mime-db@1.54.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.6 + + ms@2.1.3: {} + + msgpackr-extract@3.0.4: + dependencies: + node-gyp-build-optional-packages: 5.2.2 + optionalDependencies: + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.4 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.4 + optional: true + + msgpackr@2.0.1: + optionalDependencies: + msgpackr-extract: 3.0.4 + + multer@2.1.1: + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 2.0.0 + type-is: 1.6.18 + + mysql2@3.15.3: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.2 + long: 5.3.2 + lru.min: 1.1.4 + named-placeholders: 1.1.6 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + + named-placeholders@1.1.6: + dependencies: + lru.min: 1.1.4 + + nanoid@3.3.12: {} + + natural-compare@1.4.0: {} + + negotiator@1.0.0: {} + + next@16.2.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + dependencies: + '@next/env': 16.2.6 + '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.10.33 + caniuse-lite: 1.0.30001793 + postcss: 8.4.31 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + styled-jsx: 5.1.6(react@19.2.6) + optionalDependencies: + '@next/swc-darwin-arm64': 16.2.6 + '@next/swc-darwin-x64': 16.2.6 + '@next/swc-linux-arm64-gnu': 16.2.6 + '@next/swc-linux-arm64-musl': 16.2.6 + '@next/swc-linux-x64-gnu': 16.2.6 + '@next/swc-linux-x64-musl': 16.2.6 + '@next/swc-win32-arm64-msvc': 16.2.6 + '@next/swc-win32-x64-msvc': 16.2.6 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-abort-controller@3.1.1: {} + + node-gyp-build-optional-packages@5.2.2: + dependencies: + detect-libc: 2.1.2 + optional: true + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + obug@2.1.1: {} + + ohash@2.0.11: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parseurl@1.3.3: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-to-regexp@8.4.2: {} + + pathe@2.0.3: {} + + perfect-debounce@2.1.0: {} + + pg-cloudflare@1.4.0: + optional: true + + pg-connection-string@2.13.0: {} + + pg-int8@1.0.1: {} + + pg-pool@3.14.0(pg@8.21.0): + dependencies: + pg: 8.21.0 + + pg-protocol@1.14.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.21.0: + dependencies: + pg-connection-string: 2.13.0 + pg-pool: 3.14.0(pg@8.21.0) + pg-protocol: 1.14.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.4.0 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + + postcss@8.4.31: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postgres-array@2.0.0: {} + + postgres-array@3.0.4: {} + + postgres-bytea@1.0.1: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + + postgres@3.4.7: {} + + prelude-ls@1.2.1: {} + + prisma@7.8.0(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@6.0.3): + dependencies: + '@prisma/config': 7.8.0 + '@prisma/dev': 0.24.3(typescript@6.0.3) + '@prisma/engines': 7.8.0 + '@prisma/studio-core': 0.27.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + mysql2: 3.15.3 + postgres: 3.4.7 + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + - magicast + - react + - react-dom + + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + punycode@2.3.1: {} + + pure-rand@6.1.0: {} + + qs@6.15.2: + dependencies: + side-channel: 1.1.0 + + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + + rc9@3.0.1: + dependencies: + defu: 6.1.7 + destr: 2.0.5 + + react-dom@19.2.6(react@19.2.6): + dependencies: + react: 19.2.6 + scheduler: 0.27.0 + + react@19.2.6: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@5.0.0: {} + + redis-errors@1.2.0: {} + + redis-parser@3.0.0: + dependencies: + redis-errors: 1.2.0 + + reflect-metadata@0.2.2: {} + + remeda@2.33.4: {} + + require-from-string@2.0.2: {} + + retry@0.12.0: {} + + rolldown@1.0.2: + dependencies: + '@oxc-project/types': 0.132.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.2 + '@rolldown/binding-darwin-arm64': 1.0.2 + '@rolldown/binding-darwin-x64': 1.0.2 + '@rolldown/binding-freebsd-x64': 1.0.2 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.2 + '@rolldown/binding-linux-arm64-gnu': 1.0.2 + '@rolldown/binding-linux-arm64-musl': 1.0.2 + '@rolldown/binding-linux-ppc64-gnu': 1.0.2 + '@rolldown/binding-linux-s390x-gnu': 1.0.2 + '@rolldown/binding-linux-x64-gnu': 1.0.2 + '@rolldown/binding-linux-x64-musl': 1.0.2 + '@rolldown/binding-openharmony-arm64': 1.0.2 + '@rolldown/binding-wasm32-wasi': 1.0.2 + '@rolldown/binding-win32-arm64-msvc': 1.0.2 + '@rolldown/binding-win32-x64-msvc': 1.0.2 + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + scheduler@0.27.0: {} + + semver@7.8.0: {} + + semver@7.8.1: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + seq-queue@0.0.5: {} + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.1 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + source-map-js@1.2.1: {} + + split2@4.2.0: {} + + sqlstring@2.3.3: {} + + stackback@0.0.2: {} + + standard-as-callback@2.1.0: {} + + statuses@2.0.2: {} + + std-env@3.10.0: {} + + std-env@4.1.0: {} + + streamsearch@1.1.0: {} + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strtok3@10.3.5: + dependencies: + '@tokenizer/token': 0.3.0 + + styled-jsx@5.1.6(react@19.2.6): + dependencies: + client-only: 0.0.1 + react: 19.2.6 + + tinybench@2.9.0: {} + + tinyexec@1.2.4: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinyrainbow@3.1.0: {} + + toidentifier@1.0.1: {} + + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + ts-api-utils@2.5.0(typescript@6.0.3): + dependencies: + typescript: 6.0.3 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + type-is@2.1.0: + dependencies: + content-type: 2.0.0 + media-typer: 1.1.0 + mime-types: 3.0.2 + + typedarray@0.0.6: {} + + typescript-eslint@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.60.0(@typescript-eslint/parser@8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.60.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.60.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.4.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + typescript@6.0.3: {} + + uid@2.0.2: + dependencies: + '@lukeed/csprng': 1.1.0 + + uint8array-extras@1.5.0: {} + + undici-types@7.24.6: {} + + unpipe@1.0.0: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + valibot@1.2.0(typescript@6.0.3): + optionalDependencies: + typescript: 6.0.3 + + vary@1.1.2: {} + + vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.2 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 25.9.1 + fsevents: 2.3.3 + jiti: 2.7.0 + + vitest@4.1.7(@types/node@25.9.1)(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)): + dependencies: + '@vitest/expect': 4.1.7 + '@vitest/mocker': 4.1.7(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0)) + '@vitest/pretty-format': 4.1.7 + '@vitest/runner': 4.1.7 + '@vitest/snapshot': 4.1.7 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.0.14(@types/node@25.9.1)(jiti@2.7.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.9.1 + transitivePeerDependencies: + - msw + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + word-wrap@1.2.5: {} + + wrappy@1.0.2: {} + + xtend@4.0.2: {} + + yocto-queue@0.1.0: {} + + zeptomatch@2.1.0: + dependencies: + grammex: 3.1.12 + graphmatch: 1.1.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..3ff5faaa --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: + - "apps/*" + - "packages/*" diff --git a/scripts/check-s1-scope.mjs b/scripts/check-s1-scope.mjs new file mode 100644 index 00000000..70eb9c07 --- /dev/null +++ b/scripts/check-s1-scope.mjs @@ -0,0 +1,2975 @@ +import { mkdir, mkdtemp, readdir, readFile, rm, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; + +const scanRoots = ["apps", "packages"]; +const ignoredScanSegments = new Set(["node_modules", "dist", ".vite", "coverage", ".next", "generated"]); +const sourceLikeFilePattern = /\.(?:ts|tsx|js|jsx|mjs|cjs|json|sql|prisma)$/; +const prismaMigrationPrefix = "apps/api/prisma/migrations/"; +const generatedPrismaPrefix = "apps/api/src/generated/prisma/"; +const stateTransitionModulePrefix = "apps/api/src/modules/state-transition/"; +const auditModulePrefix = "apps/api/src/modules/audit/"; +const jobsModulePrefix = "apps/api/src/modules/jobs/"; +const jobExecutionStorePath = "apps/api/src/modules/jobs/index.ts"; +const initialAuditLogAppendOnlyFunctionMigration = "apps/api/prisma/migrations/20260601040253_s1_app_foundation/migration.sql"; +const historicalPrismaSchemaTest = "apps/api/src/prisma.schema.spec.ts"; +const auditTriggerAssertionFiles = new Set([historicalPrismaSchemaTest, "apps/api/src/modules/audit/audit.spec.ts"]); +const stateTransitionImportFixtureTests = new Set([ + "apps/api/src/modules/jobs/jobs.spec.ts", + "apps/api/src/modules/jobs/jobs.api.spec.ts" +]); + +const laterPhaseDeniedTerms = [ + "creation-agent/messages", + "compile-game-ir", + "web-runtime", + "mini-game-conversion", + "AIGameDesignDraft", + "GameIRArtifact", + "GameIR", + "ConversionReport", + "ValidationReport", + "MiniGameProject", + "MiniGameCodeConversion", + "FeedItem", + "GameDailyStats", + "CreatorDailyStats", + "/events/batch" +]; + +const harnessValidationContractTerms = new Set([ + "AIGameDesignDraft", + "GameIR", + "ConversionReport", + "ValidationReport", + "MiniGameProject", + "MiniGameCodeConversion" +]); + +const harnessClientContractWatchTerms = new Set(harnessValidationContractTerms); +const jobRuntimeFields = [ + "status", + "attempts", + "nextRetryAt", + "errorCode", + "leaseToken", + "leasedBy", + "leaseExpiresAt", + "lockVersion", + "timeoutAt" +]; +const rawSqlVariableResolutionMaxDepth = 6; +const dynamicSqlIdentifierMarker = "__HUJING_DYNAMIC_SQL_IDENTIFIER__"; +const auditLogAppendOnlyFunctionName = "app_reject_audit_log_mutation"; +const auditPrismaMutationMethods = ["update", "updateMany", "updateManyAndReturn", "upsert", "delete", "deleteMany"]; +const guardedPrismaWriteMethods = ["create", "update", "upsert", "createMany", "updateMany", "delete", "deleteMany"]; +const jobPrismaWriteMethods = ["create", "createMany", "createManyAndReturn", "update", "updateMany", "updateManyAndReturn", "upsert"]; + +const s1AnchorTerms = ["MainCreationAgentSession", "AgentTask", "ReviewRecord", "LifecycleEvent"]; +const allowedStateTransitionImportPrefixes = [stateTransitionModulePrefix, "apps/api/src/modules/projects/"]; + +function normalizePath(filePath) { + return filePath.split(path.sep).join("/"); +} + +function isIgnoredScanPath(filePath) { + return filePath.split("/").some((segment) => ignoredScanSegments.has(segment)); +} + +function isHarnessClientTestPath(filePath) { + return /^packages\/harness-client\/.*\.(?:spec|test)\.(?:ts|tsx|js|jsx|mjs|cjs)$/.test(filePath); +} + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +function sqlBareIdentifierPattern() { + return String.raw`[A-Za-z_][\w$]*`; +} + +function sqlTriggerIdentifierPattern() { + // SQL 扫描会去掉双引号,quoted trigger name 里的连字符需作为同一 token fail-closed。 + return String.raw`[^\s(),;]+`; +} + +function validationContractReferenceSpans(content, term) { + const spans = []; + const pattern = new RegExp(`\\bvalidateContract\\s*\\(\\s*(["'])${escapeRegExp(term)}\\1`, "g"); + for (const match of content.matchAll(pattern)) { + const termOffset = match[0].lastIndexOf(term); + if (typeof match.index === "number" && termOffset >= 0) { + spans.push({ start: match.index + termOffset, end: match.index + termOffset + term.length }); + } + } + return spans; +} + +function enclosingBraceSpan(content, index) { + const structure = maskCommentsOutsideStringLiterals(content); + let smallestSpan = null; + + for (let cursor = 0; cursor < structure.length; cursor += 1) { + if (structure[cursor] !== "{") continue; + const closeBraceIndex = findMatchingBrace(structure, cursor); + if (closeBraceIndex === -1 || index < cursor || index > closeBraceIndex) continue; + + const span = { start: cursor, end: closeBraceIndex + 1 }; + if (!smallestSpan || span.end - span.start < smallestSpan.end - smallestSpan.start) { + smallestSpan = span; + } + } + + return smallestSpan; +} + +function hasHarnessCliContractArgumentContext(content, assertionIndex) { + const span = enclosingBraceSpan(content, assertionIndex); + const contextStart = Math.max(span?.start ?? 0, assertionIndex - 400); + const contextEnd = Math.min(span?.end ?? content.length, assertionIndex + 220); + const context = content.slice(contextStart, contextEnd); + + // args[2] 只有在同一 runner 小窗口内已证明 args[0..1] 指向真实 harness CLI contract 调用时才可作为合同名断言。 + return /\bexpect\s*\(\s*args\s*\.\s*slice\s*\(\s*0\s*,\s*2\s*\)\s*\)\s*\.\s*to(?:Strict)?Equal\s*\(\s*\[\s*(?:realHarnessCli|[^\]]*validate-harness\.mjs[^\]]*)\s*,\s*(["'])--contract\1\s*\]\s*\)/s.test( + context + ); +} + +function harnessCliContractArgumentAssertionSpans(content, term) { + const spans = []; + const pattern = new RegExp( + `\\bexpect\\s*\\(\\s*args\\s*\\[\\s*2\\s*\\]\\s*\\)\\s*\\.\\s*toBe\\s*\\(\\s*(["'])${escapeRegExp(term)}\\1\\s*\\)`, + "g" + ); + for (const match of content.matchAll(pattern)) { + const termOffset = match[0].lastIndexOf(term); + if (typeof match.index === "number" && termOffset >= 0 && hasHarnessCliContractArgumentContext(content, match.index)) { + spans.push({ start: match.index + termOffset, end: match.index + termOffset + term.length }); + } + } + return spans; +} + +function isInSpan(index, spans) { + return spans.some((span) => index >= span.start && index < span.end); +} + +function isHarnessGateValidationTestPath(filePath) { + return /^apps\/api\/src\/modules\/harness-gate\/.*\.(?:spec|test)\.(?:ts|tsx|js|jsx|mjs|cjs)$/.test(filePath); +} + +function isAllowedHarnessValidationContractReferenceAt(filePath, content, term, index) { + if (!harnessValidationContractTerms.has(term)) return false; + if (!isHarnessClientTestPath(filePath) && !isHarnessGateValidationTestPath(filePath)) return false; + if (isInSpan(index, validationContractReferenceSpans(content, term))) return true; + + // harness-client 的 runner 断言 `args[2]` 是 `--contract` 的合同名;这是 CLI validation 证据。 + return isHarnessClientTestPath(filePath) && isInSpan(index, harnessCliContractArgumentAssertionSpans(content, term)); +} + +function isAllowedHarnessClientContractReferenceAt(filePath, content, term, index) { + if (!isHarnessClientTestPath(filePath)) return false; + return isAllowedHarnessValidationContractReferenceAt(filePath, content, term, index); +} + +function normalizeDeniedPathTerm(term) { + return term.split(path.sep).join("/").replace(/^\/+|\/+$/g, ""); +} + +function kebabCaseContractTerm(term) { + return term + .replace(/([a-z0-9])([A-Z])/g, "$1-$2") + .replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2") + .toLowerCase(); +} + +function pathContainsLaterPhaseTerm(filePath, term) { + const deniedPathTerm = normalizeDeniedPathTerm(term); + if (!deniedPathTerm) return false; + + const normalizedFilePath = normalizePath(filePath).replace(/^\/+|\/+$/g, ""); + const pathWithBoundaries = `/${normalizedFilePath}/`; + + // route/module fragment 要按路径边界匹配,同时覆盖同名单文件模块。 + if (deniedPathTerm.includes("/")) { + const deniedSourceFilePattern = new RegExp(`(?:^|/)${escapeRegExp(deniedPathTerm)}${sourceLikeFilePattern.source}`); + return pathWithBoundaries.includes(`/${deniedPathTerm}/`) || deniedSourceFilePattern.test(normalizedFilePath); + } + + // symbol-like term 在路径中按 segment/filename 命中,覆盖 AIGameDesignDraft.ts 这类文件名。 + const pathTermVariants = new Set([deniedPathTerm, kebabCaseContractTerm(deniedPathTerm)]); + return normalizedFilePath + .split("/") + .some((segment) => [...pathTermVariants].some((pathTermVariant) => segment.includes(pathTermVariant))); +} + +function contentDeniedTermVariants(term) { + if (!term.startsWith("/")) return [term]; + + // 内容扫描把同一路由片段的绝对/相对写法视为等价,避免 "/events/batch" 漏掉 "events/batch"。 + const normalizedTerm = term.replace(/^\/+/, ""); + return normalizedTerm ? [term, normalizedTerm] : [term]; +} + +function isTestFile(filePath) { + return /\.(?:spec|test)\.(?:ts|tsx|js|jsx|mjs|cjs)$/.test(filePath); +} + +function isHistoricalTestFile(filePath) { + return filePath === historicalPrismaSchemaTest; +} + +function isGeneratedPrismaFile(filePath) { + return filePath.startsWith(generatedPrismaPrefix); +} + +function allowsAuditLogAppendOnlyFunctionDefinition(filePath) { + // S1 初始 migration 安装 append-only trigger function;后续 DDL 或运行时代码仍按 denylist 扫描。 + return filePath === initialAuditLogAppendOnlyFunctionMigration; +} + +function isAllowedAuditTriggerAssertion(filePath, content, structure, mutationIndex) { + if (!auditTriggerAssertionFiles.has(filePath)) return false; + + let searchCursor = mutationIndex; + while (searchCursor >= 0) { + const assertionIndex = structure.lastIndexOf("expectPrismaRejectedInSavepoint", searchCursor); + if (assertionIndex === -1) return false; + + const openParenIndex = structure.indexOf("(", assertionIndex); + if (openParenIndex === -1 || openParenIndex > mutationIndex) { + searchCursor = assertionIndex - 1; + continue; + } + + const closeParenIndex = findMatchingParen(structure, openParenIndex); + if (closeParenIndex === -1 || closeParenIndex < mutationIndex) { + searchCursor = assertionIndex - 1; + continue; + } + + const assertionSource = content.slice(openParenIndex, closeParenIndex + 1); + return /AuditLog is append-only/.test(assertionSource); + } + + return false; +} + +function hasForbiddenAuditMutation(filePath, content) { + const structure = stripStringLiteralsExceptPropertyKeys(maskCommentsOutsideStringLiterals(content)); + + for (const match of prismaModelMethodCallMatchesInStructure(structure, ["auditLog"], auditPrismaMutationMethods)) { + if (typeof match.index === "number" && isAllowedAuditTriggerAssertion(filePath, content, structure, match.index)) continue; + return true; + } + + return hasForbiddenRawAuditLogMutation(filePath, content, structure); +} + +function hasGuardedPrismaWrite(content) { + const guardedModels = ["gameVersion", "reviewRecord", "lifecycleEvent"]; + const hasPrismaWrite = prismaModelMethodCallMatches(content, guardedModels, guardedPrismaWriteMethods).length > 0; + const hasSqlWrite = /\b(?:INSERT\s+INTO|UPDATE|DELETE\s+FROM)\s+"?(?:GameVersion|ReviewRecord|LifecycleEvent)"?/i.test( + content + ); + return hasPrismaWrite || hasSqlWrite; +} + +function hasRuntimeGuardSetter(content) { + return /app\.state_transition_guard|set_config\s*\(|SET\s+LOCAL/i.test(content); +} + +function stripSqlComments(content) { + return content + .replace(/\/\*[\s\S]*?\*\//g, "") + .split("\n") + .map((line) => line.replace(/--.*$/, "")) + .join("\n"); +} + +function normalizeRawSqlScanSource(content) { + return stripSqlComments(content) + .replace(/\\(["'`])/g, "$1") + .replace(/\\n/g, "\n") + .replace(/\\r/g, "\r") + .replace(/\\t/g, "\t") + .replace( + /\$\{\s*Prisma\s*\.\s*raw\s*\(\s*((?:"(?:\\.|[^"\\])*")|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`)\s*\)\s*\}/gs, + " $1 " + ) + .replace(/\$\{[\s\S]*?\}/g, " ? ") + .replace(/["'`]/g, " ") + .replace(/\s*\+\s*/g, " ") + .replace(/\s+/g, " "); +} + +function sqlTableReferencePattern(tableName) { + const identifier = sqlBareIdentifierPattern(); + return String.raw`(?:${identifier}\s*\.\s*)?${escapeRegExp(tableName)}`; +} + +function sqlAnyTableReferencePattern() { + const identifier = sqlBareIdentifierPattern(); + return String.raw`(?:${identifier}\s*\.\s*)?${identifier}`; +} + +function sqlFunctionReferencePattern(functionName) { + const identifier = sqlBareIdentifierPattern(); + return String.raw`(?:${identifier}\s*\.\s*)?${escapeRegExp(functionName)}\s*(?:\([^)]*\))?`; +} + +function staticStringLiteralAlternatives(values) { + return values.flatMap((value) => { + const escapedValue = escapeRegExp(value); + return [`"${escapedValue}"`, `'${escapedValue}'`, `\`${escapedValue}\``]; + }); +} + +function staticPrismaPropertyAccessPattern(values) { + const dotNames = values.map(escapeRegExp).join("|"); + const bracketNames = staticStringLiteralAlternatives(values).join("|"); + return String.raw`(?:(?:\.|\?\.)\s*(?:${dotNames})|(?:\?\.\s*)?\[\s*(?:${bracketNames})\s*\])`; +} + +function prismaModelMethodCallPattern(models, methods) { + return new RegExp( + `${staticPrismaPropertyAccessPattern(models)}\\s*${staticPrismaPropertyAccessPattern(methods)}\\s*(?:\\?\\.)?\\s*\\(`, + "g" + ); +} + +function findStaticPrismaDelegateAliases(structure, models) { + const aliases = []; + const modelAccess = staticPrismaPropertyAccessPattern(models); + const declarationPattern = new RegExp( + String.raw`\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\b(?:\s*:[^=;]+)?\s*=\s*[A-Za-z_$][\w$]*\s*${modelAccess}`, + "g" + ); + + for (const match of structure.matchAll(declarationPattern)) { + if (typeof match.index !== "number") continue; + + const aliasEnd = match.index + match[0].length; + const nextIndex = skipWhitespaceForward(structure, aliasEnd); + // 只接受 `const jobs = db.job;` 这类完整 delegate alias,避免把 `db.job.update` 误判成 alias。 + if (structure[nextIndex] === "." || structure[nextIndex] === "[" || structure[nextIndex] === "(" || structure[nextIndex] === "?") { + continue; + } + + aliases.push({ name: match[1], index: match.index }); + } + + return aliases; +} + +function prismaDelegateAliasMethodCallPattern(aliasNames, methods) { + const aliases = aliasNames.map(escapeRegExp).join("|"); + return new RegExp(String.raw`\b(${aliases})\b\s*${staticPrismaPropertyAccessPattern(methods)}\s*(?:\?\.)?\s*\(`, "g"); +} + +function prismaModelMethodCallMatchesInStructure(structure, models, methods) { + const matches = []; + + for (const match of structure.matchAll(prismaModelMethodCallPattern(models, methods))) { + if (typeof match.index === "number") matches.push({ index: match.index }); + } + + const aliases = findStaticPrismaDelegateAliases(structure, models); + if (aliases.length === 0) return matches; + + const aliasPattern = prismaDelegateAliasMethodCallPattern( + [...new Set(aliases.map((alias) => alias.name))], + methods + ); + + for (const match of structure.matchAll(aliasPattern)) { + if (typeof match.index !== "number") continue; + const aliasName = match[1]; + if (aliases.some((alias) => alias.name === aliasName && alias.index < match.index)) { + matches.push({ index: match.index }); + } + } + + return matches.toSorted((left, right) => left.index - right.index); +} + +function prismaModelMethodCallMatches(content, models, methods) { + const structure = stripStringLiteralsExceptPropertyKeys(maskCommentsOutsideStringLiterals(content)); + return prismaModelMethodCallMatchesInStructure(structure, models, methods); +} + +function sqlTableListContainingPattern(targetTableReference) { + const tableReference = sqlAnyTableReferencePattern(); + const tableListItem = String.raw`(?:ONLY\s+)?${tableReference}(?:\s*\*)?`; + const targetTableListItem = String.raw`(?:ONLY\s+)?${targetTableReference}\b(?:\s*\*)?`; + // 表列表允许目标表出现在任意位置,避免只匹配列表首尾造成绕过。 + return String.raw`(?:${tableListItem}\s*,\s*)*${targetTableListItem}(?:\s*,\s*${tableListItem})*`; +} + +function sqlTruncateTableListPattern(targetTableReference) { + return String.raw`\bTRUNCATE(?:\s+TABLE)?\s+${sqlTableListContainingPattern(targetTableReference)}`; +} + +function sqlDropTableListPattern(targetTableReference) { + return String.raw`\bDROP\s+TABLE\s+(?:IF\s+EXISTS\s+)?${sqlTableListContainingPattern(targetTableReference)}`; +} + +function stripStringLiterals(content) { + return content + .replace(/"(?:\\.|[^"\\])*"/gs, '""') + .replace(/'(?:\\.|[^'\\])*'/gs, "''") + .replace(/`(?:\\.|[^`\\])*`/gs, "``"); +} + +function skipWhitespaceForward(content, index) { + let cursor = index; + while (cursor < content.length && /\s/.test(content[cursor])) cursor += 1; + return cursor; +} + +function skipWhitespaceBackward(content, index) { + let cursor = index; + while (cursor >= 0 && /\s/.test(content[cursor])) cursor -= 1; + return cursor; +} + +function isStaticQuotedPropertyKeyOrAccess(content, literalStart, literalEnd) { + const afterLiteral = skipWhitespaceForward(content, literalEnd); + if (content[afterLiteral] === ":") return true; + + const afterComputedKey = skipWhitespaceForward(content, afterLiteral + 1); + if (content[afterLiteral] !== "]") return false; + + const beforeLiteral = skipWhitespaceBackward(content, literalStart - 1); + if (content[beforeLiteral] !== "[") return false; + + // 保留静态 bracket key,覆盖对象 key 与 Prisma property access 两种源码形态。 + return ( + content[afterComputedKey] === ":" || + content[afterComputedKey] === "." || + content[afterComputedKey] === "?" || + content[afterComputedKey] === "[" || + content[afterComputedKey] === "(" + ); +} + +function stripStringLiteralsExceptPropertyKeys(content) { + let output = ""; + + for (let index = 0; index < content.length; index += 1) { + const quote = content[index]; + if (quote === "/" && isRegexLiteralStart(content, index)) { + const literalEnd = findRegexLiteralEnd(content, index); + if (literalEnd !== -1) { + output += "/".padEnd(literalEnd - index, " ") + "/"; + index = literalEnd; + continue; + } + } + if (quote !== '"' && quote !== "'" && quote !== "`") { + output += quote; + continue; + } + + const literalStart = index; + let literalEnd = literalStart + 1; + while (literalEnd < content.length) { + const char = content[literalEnd]; + if (char === "\\") { + literalEnd += 2; + continue; + } + literalEnd += 1; + if (char === quote) break; + } + + const literal = content.slice(literalStart, literalEnd); + // 只保留静态 key/access,普通字符串值仍等长剥离,避免破坏源码索引。 + output += isStaticQuotedPropertyKeyOrAccess(content, literalStart, literalEnd) + ? literal + : `${quote}${" ".repeat(Math.max(0, literal.length - 2))}${quote}`; + index = literalEnd - 1; + } + + return output; +} + +function maskCommentsOutsideStringLiterals(content) { + let output = ""; + let index = 0; + + while (index < content.length) { + const char = content[index]; + const next = content[index + 1]; + + if (char === "/" && next === "/") { + output += " "; + index += 2; + while (index < content.length && content[index] !== "\n" && content[index] !== "\r") { + output += " "; + index += 1; + } + continue; + } + + if (char === "/" && next === "*") { + output += " "; + index += 2; + while (index < content.length) { + const blockChar = content[index]; + const blockNext = content[index + 1]; + if (blockChar === "*" && blockNext === "/") { + output += " "; + index += 2; + break; + } + output += blockChar === "\n" || blockChar === "\r" ? blockChar : " "; + index += 1; + } + continue; + } + + if (char === "/" && isRegexLiteralStart(content, index)) { + const literalEnd = findRegexLiteralEnd(content, index); + if (literalEnd !== -1) { + output += content.slice(index, literalEnd + 1); + index = literalEnd + 1; + continue; + } + } + + if (char !== '"' && char !== "'" && char !== "`") { + output += char; + index += 1; + continue; + } + + output += char; + index += 1; + while (index < content.length) { + const stringChar = content[index]; + output += stringChar; + index += 1; + if (stringChar === "\\") { + if (index < content.length) { + output += content[index]; + index += 1; + } + continue; + } + if (stringChar === char) break; + } + } + + return output; +} + +function isRegexLiteralStart(content, slashIndex) { + let cursor = skipWhitespaceBackward(content, slashIndex - 1); + if (cursor < 0) return true; + + const previous = content[cursor]; + if ("([{:;,=!?&|+-*%^~<>".includes(previous)) return true; + return /\b(?:return|throw|case|delete|typeof|void|new|in|of|yield|await)\b/.test(content.slice(Math.max(0, cursor - 12), cursor + 1)); +} + +function findRegexLiteralEnd(content, slashIndex) { + let inCharClass = false; + for (let cursor = slashIndex + 1; cursor < content.length; cursor += 1) { + const char = content[cursor]; + if (char === "\\") { + cursor += 1; + continue; + } + if (char === "[") inCharClass = true; + if (char === "]") inCharClass = false; + if (char === "/" && !inCharClass) { + let end = cursor + 1; + while (end < content.length && /[a-z]/i.test(content[end])) end += 1; + return end - 1; + } + } + return -1; +} + +function findMatchingParen(content, openParenIndex) { + let depth = 0; + for (let index = openParenIndex; index < content.length; index += 1) { + const char = content[index]; + if (char === "(") depth += 1; + if (char === ")") { + depth -= 1; + if (depth === 0) return index; + } + } + return -1; +} + +function findMatchingBrace(content, openBraceIndex) { + let depth = 0; + for (let index = openBraceIndex; index < content.length; index += 1) { + const char = content[index]; + if (char === "{") depth += 1; + if (char === "}") { + depth -= 1; + if (depth === 0) return index; + } + } + return -1; +} + +function maskStringLiterals(content) { + let output = ""; + let index = 0; + + while (index < content.length) { + const quote = content[index]; + if (quote === "/" && isRegexLiteralStart(content, index)) { + const literalEnd = findRegexLiteralEnd(content, index); + if (literalEnd !== -1) { + output += "/".padEnd(literalEnd - index, " ") + "/"; + index = literalEnd + 1; + continue; + } + } + if (quote !== '"' && quote !== "'" && quote !== "`") { + output += quote; + index += 1; + continue; + } + + output += quote; + index += 1; + while (index < content.length) { + const char = content[index]; + if (char === "\\") { + output += " "; + index += 1; + if (index < content.length) { + output += " "; + index += 1; + } + continue; + } + if (char === quote) { + output += quote; + index += 1; + break; + } + output += " "; + index += 1; + } + } + + return output; +} + +function findStringLiteralEnd(content, literalStart) { + const quote = content[literalStart]; + let cursor = literalStart + 1; + + while (cursor < content.length) { + const char = content[cursor]; + if (char === "\\") { + cursor += 2; + continue; + } + if (char === quote) return cursor; + cursor += 1; + } + + return -1; +} + +function hasPrismaCallContaining(content, callPattern, termPattern) { + // 结构匹配只看源码骨架;注释中的括号/花括号不能参与调用体边界计算。 + const scanContent = stripStringLiteralsExceptPropertyKeys(maskCommentsOutsideStringLiterals(content)); + for (const match of scanContent.matchAll(callPattern)) { + const openParenIndex = scanContent.indexOf("(", match.index); + if (openParenIndex === -1) continue; + const closeParenIndex = findMatchingParen(scanContent, openParenIndex); + if (closeParenIndex === -1) continue; + const callBody = scanContent.slice(openParenIndex, closeParenIndex + 1); + if (termPattern.test(callBody)) return true; + } + return false; +} + +function hasPrismaModelMethodCallContaining(content, models, methods, termPattern) { + // delegate alias 与直接 model access 共用同一调用体解析,避免 Job/Audit/guarded 边界分叉。 + const scanContent = stripStringLiteralsExceptPropertyKeys(maskCommentsOutsideStringLiterals(content)); + for (const match of prismaModelMethodCallMatchesInStructure(scanContent, models, methods)) { + const openParenIndex = scanContent.indexOf("(", match.index); + if (openParenIndex === -1) continue; + const closeParenIndex = findMatchingParen(scanContent, openParenIndex); + if (closeParenIndex === -1) continue; + const callBody = scanContent.slice(openParenIndex, closeParenIndex + 1); + if (termPattern.test(callBody)) return true; + } + return false; +} + +function hasVariableizedOrSpreadJobData(callBody) { + return ( + /\bdata\s*(?:[,}])/.test(callBody) || + /\bdata\s*:\s*[A-Za-z_$][\w$]*\b/.test(callBody) || + /\bdata\s*:\s*(?:\{|\[)[\s\S]*\.\.\./.test(callBody) + ); +} + +function hasComputedJobDataKey(callBody) { + const dataObjectPattern = /\bdata\s*:\s*\{/g; + for (const match of callBody.matchAll(dataObjectPattern)) { + const openBraceIndex = callBody.indexOf("{", match.index); + if (openBraceIndex === -1) continue; + const closeBraceIndex = findMatchingBrace(callBody, openBraceIndex); + if (closeBraceIndex === -1) continue; + const dataObjectBody = callBody.slice(openBraceIndex, closeBraceIndex + 1); + // Job 运行态字段必须由 JobExecutionStore 单写;computed key 无法静态证明安全,按违规处理。 + if (/\[[^\]]+\]\s*:/.test(dataObjectBody)) return true; + } + return false; +} + +function hasForbiddenJobWriteCallBody(callBody) { + const runtimeFieldPattern = new RegExp(`\\b(?:${jobRuntimeFields.map(escapeRegExp).join("|")})\\b`); + return runtimeFieldPattern.test(callBody) || hasVariableizedOrSpreadJobData(callBody) || hasComputedJobDataKey(callBody); +} + +function hasRawJobRuntimeFieldWrite(sqlSource) { + const sql = normalizeRawSqlScanSource(sqlSource); + const jobTable = sqlTableReferencePattern("Job"); + const identifier = sqlBareIdentifierPattern(); + const runtimeField = String.raw`(?:${jobRuntimeFields.map(escapeRegExp).join("|")})`; + const maybeQualifiedRuntimeField = String.raw`(?:${identifier}\s*\.\s*)?${runtimeField}`; + const updateJobRuntimeFieldPattern = new RegExp( + String.raw`\bUPDATE\s+(?:ONLY\s+)?${jobTable}(?:\s+(?:AS\s+)?${identifier})?\s+SET\b[\s\S]*?\b${maybeQualifiedRuntimeField}\s*=`, + "i" + ); + const updateJobTablePattern = new RegExp( + String.raw`\bUPDATE\s+(?:ONLY\s+)?${jobTable}(?:\s+(?:AS\s+)?${identifier})?\s+SET\b`, + "i" + ); + const mergeJobTablePattern = new RegExp(String.raw`\bMERGE\s+INTO\s+${jobTable}(?:\s+(?:AS\s+)?${identifier})?\b`, "i"); + + return ( + updateJobRuntimeFieldPattern.test(sql) || + updateJobTablePattern.test(sql) || + mergeJobTablePattern.test(sql) || + new RegExp(String.raw`\bINSERT\s+INTO\s+${jobTable}\b`, "i").test(sql) || + new RegExp(String.raw`\bDELETE\s+FROM\s+(?:ONLY\s+)?${jobTable}\b`, "i").test(sql) || + new RegExp(sqlTruncateTableListPattern(jobTable), "i").test(sql) + ); +} + +function findStatementEnd(structure, startIndex) { + const semicolonIndex = structure.indexOf(";", startIndex); + return semicolonIndex === -1 ? structure.length : semicolonIndex; +} + +function findVariableInitializerSources(content, structure, variableName, beforeIndex) { + const sources = []; + const escapedName = escapeRegExp(variableName); + const declarationPattern = new RegExp( + String.raw`\b(?:const|let|var)\s+${escapedName}\b(?:\s*:[^=;]+)?\s*=|\b${escapedName}\s*=`, + "g" + ); + + for (const match of structure.matchAll(declarationPattern)) { + if (typeof match.index !== "number" || match.index >= beforeIndex) continue; + const equalsIndex = structure.indexOf("=", match.index); + if (equalsIndex === -1 || equalsIndex >= beforeIndex) continue; + const initializerStart = skipWhitespaceForward(structure, equalsIndex + 1); + const initializerEnd = findStatementEnd(structure, initializerStart); + sources.push({ index: initializerStart, end: initializerEnd, source: content.slice(initializerStart, initializerEnd) }); + } + + return sources; +} + +function findLatestVariableInitializerSource(content, structure, variableName, beforeIndex) { + const sources = findVariableInitializerSources(content, structure, variableName, beforeIndex); + return sources.length === 0 ? null : sources.at(-1); +} + +function isStaticStringLiteralSource(source) { + const trimmed = source.trim(); + if (trimmed.length < 2) return false; + + const quote = trimmed[0]; + if (quote !== '"' && quote !== "'" && quote !== "`") return false; + const literalEnd = findStringLiteralEnd(trimmed, 0); + if (literalEnd !== trimmed.length - 1) return false; + + // 带表达式的 template literal 不是静态 SQL 片段,不能当成确定表名/字段名展开。 + return quote !== "`" || !/\$\{/.test(trimmed); +} + +function isStaticPrismaRawExpressionSource(source) { + const trimmed = source.trim(); + const rawCallPattern = /\bPrisma\s*\.\s*raw\s*\(/; + const rawCallMatch = rawCallPattern.exec(trimmed); + if (!rawCallMatch || rawCallMatch.index !== 0) return false; + + const openParenIndex = trimmed.indexOf("(", rawCallMatch.index + rawCallMatch[0].length - 1); + if (openParenIndex === -1) return false; + const closeParenIndex = findMatchingParen(maskCommentsOutsideStringLiterals(trimmed), openParenIndex); + if (closeParenIndex !== trimmed.length - 1) return false; + + return isStaticStringLiteralSource(trimmed.slice(openParenIndex + 1, closeParenIndex)); +} + +function isStaticSqlFragmentSource(source) { + return isStaticStringLiteralSource(source) || isStaticPrismaRawExpressionSource(source); +} + +function applyTextReplacements(source, replacements) { + let output = source; + for (const replacement of [...replacements].sort((left, right) => right.start - left.start)) { + output = `${output.slice(0, replacement.start)}${replacement.value}${output.slice(replacement.end)}`; + } + return output; +} + +function staticSqlFragmentReplacementSource(content, structure, variableName, beforeIndex, seenVariables, depth) { + if (depth >= rawSqlVariableResolutionMaxDepth || seenVariables.has(variableName)) return null; + + const initializer = findLatestVariableInitializerSource(content, structure, variableName, beforeIndex); + if (!initializer) return null; + + const nestedSeenVariables = new Set(seenVariables); + nestedSeenVariables.add(variableName); + const expandedSource = expandStaticSqlSource( + content, + structure, + initializer.source, + initializer.index, + initializer.end, + initializer.index, + nestedSeenVariables, + depth + 1 + ); + + return isStaticSqlFragmentSource(expandedSource) ? expandedSource.trim() : null; +} + +function expandIdentifiersOutsideStringLiterals(content, structure, source, sourceStart, sourceEnd, seenVariables, depth) { + const sourceStructure = structure.slice(sourceStart, sourceEnd); + const replacements = []; + const identifierPattern = /\b[A-Za-z_$][\w$]*\b/g; + + for (const match of sourceStructure.matchAll(identifierPattern)) { + if (typeof match.index !== "number") continue; + + const variableName = match[0]; + const replacement = staticSqlFragmentReplacementSource( + content, + structure, + variableName, + sourceStart + match.index, + seenVariables, + depth + ); + if (!replacement) continue; + + replacements.push({ + start: match.index, + end: match.index + variableName.length, + value: replacement + }); + } + + return applyTextReplacements(source, replacements); +} + +function expandPrismaRawIdentifierArguments(content, structure, source, sourceStart, seenVariables, depth) { + return source.replace(/\bPrisma\s*\.\s*raw\s*\(\s*([A-Za-z_$][\w$]*)\s*\)/g, (match, variableName, offset) => { + const variableOffset = offset + match.lastIndexOf(variableName); + const replacement = staticSqlFragmentReplacementSource( + content, + structure, + variableName, + sourceStart + variableOffset, + seenVariables, + depth + ); + + return replacement ? match.replace(variableName, replacement) : match; + }); +} + +function expandStaticPrismaRawTemplateIdentifiers(content, structure, source, sourceStart, seenVariables, depth) { + return source.replace(/\$\{\s*([A-Za-z_$][\w$]*)\s*\}/g, (match, variableName, offset) => { + const variableOffset = offset + match.lastIndexOf(variableName); + const replacement = staticSqlFragmentReplacementSource( + content, + structure, + variableName, + sourceStart + variableOffset, + seenVariables, + depth + ); + + // 只有已证明是 Prisma.raw(...) 的片段才当作 SQL 文本;普通 template 变量仍是参数。 + return replacement && isStaticPrismaRawExpressionSource(replacement) ? `\${${replacement}}` : match; + }); +} + +function expandStaticSqlSource(content, structure, source, sourceStart, sourceEnd, beforeIndex, seenVariables = new Set(), depth = 0) { + if (depth >= rawSqlVariableResolutionMaxDepth) return source; + + // 先展开字符串拼接里的静态中间变量,再补齐 Prisma.sql 模板中 Prisma.raw(...) 的静态参数。 + const withConcatenatedIdentifiers = expandIdentifiersOutsideStringLiterals( + content, + structure, + source, + sourceStart, + sourceEnd, + seenVariables, + depth + ); + const withRawArguments = expandPrismaRawIdentifierArguments( + content, + structure, + withConcatenatedIdentifiers, + sourceStart, + seenVariables, + depth + ); + return expandStaticPrismaRawTemplateIdentifiers(content, structure, withRawArguments, sourceStart, seenVariables, depth); +} + +function markDynamicTemplateSqlExpressions(source) { + return source.replace(/\$\{[\s\S]*?\}/g, (match) => { + const expressionSource = match.slice(2, -1).trim(); + // Prisma.raw 静态字面量已可证明为 identifier;其他模板表达式在 SQL 结构位按动态片段处理。 + return isStaticPrismaRawExpressionSource(expressionSource) ? match : ` ${dynamicSqlIdentifierMarker} `; + }); +} + +function markDynamicCallExpressionsOutsideStringLiterals(source) { + const structure = maskStringLiterals(maskCommentsOutsideStringLiterals(source)); + const replacements = []; + const callPattern = /\b[A-Za-z_$][\w$]*(?:\s*\.\s*[A-Za-z_$][\w$]*)*\s*\(/g; + const skippedCalls = new Set(["Prisma.raw", "Prisma.sql"]); + + for (const match of structure.matchAll(callPattern)) { + if (typeof match.index !== "number") continue; + const openParenIndex = structure.indexOf("(", match.index + match[0].length - 1); + if (openParenIndex === -1) continue; + const closeParenIndex = findMatchingParen(structure, openParenIndex); + if (closeParenIndex === -1) continue; + + const callName = match[0] + .slice(0, match[0].lastIndexOf("(")) + .replace(/\s+/g, ""); + if (skippedCalls.has(callName)) continue; + + // 写 SQL 结构位的函数调用无法静态证明目标表/字段,统一当动态 identifier。 + replacements.push({ + start: match.index, + end: closeParenIndex + 1, + value: dynamicSqlIdentifierMarker + }); + } + + return applyTextReplacements(source, replacements); +} + +function markDynamicIdentifiersOutsideStringLiterals(source) { + const structure = maskStringLiterals(maskCommentsOutsideStringLiterals(source)); + const replacements = []; + const skippedIdentifiers = new Set(["Prisma", "sql", "raw", "true", "false", "null", "undefined"]); + const identifierPattern = /\b[A-Za-z_$][\w$]*\b/g; + + for (const match of structure.matchAll(identifierPattern)) { + if (typeof match.index !== "number" || skippedIdentifiers.has(match[0])) continue; + replacements.push({ + start: match.index, + end: match.index + match[0].length, + value: dynamicSqlIdentifierMarker + }); + } + + return applyTextReplacements(source, replacements); +} + +function markDynamicSqlIdentifierFragments(source) { + return markDynamicIdentifiersOutsideStringLiterals(markDynamicCallExpressionsOutsideStringLiterals(markDynamicTemplateSqlExpressions(source))); +} + +function rawSqlScanCandidateSources(content, structure, source, sourceStart, sourceEnd, beforeIndex) { + const expandedSource = expandStaticSqlSource(content, structure, source, sourceStart, sourceEnd, beforeIndex); + const dynamicMarkedSource = markDynamicSqlIdentifierFragments(expandedSource); + return [...new Set([source, expandedSource, dynamicMarkedSource])]; +} + +function firstCallArgumentSource(content, structure, openParenIndex, closeParenIndex) { + const argumentStart = skipWhitespaceForward(structure, openParenIndex + 1); + if (argumentStart >= closeParenIndex) return null; + + let parenDepth = 0; + let braceDepth = 0; + let bracketDepth = 0; + + for (let cursor = argumentStart; cursor < closeParenIndex; cursor += 1) { + const char = structure[cursor]; + if (char === "(") parenDepth += 1; + if (char === ")") parenDepth -= 1; + if (char === "{") braceDepth += 1; + if (char === "}") braceDepth -= 1; + if (char === "[") bracketDepth += 1; + if (char === "]") bracketDepth -= 1; + if (char === "," && parenDepth === 0 && braceDepth === 0 && bracketDepth === 0) { + return { + index: argumentStart, + end: cursor, + source: content.slice(argumentStart, cursor) + }; + } + } + + return { + index: argumentStart, + end: closeParenIndex, + source: content.slice(argumentStart, closeParenIndex) + }; +} + +function hasDynamicRawSqlWrite(sqlSource) { + const sql = normalizeRawSqlScanSource(sqlSource); + const dynamicIdentifier = escapeRegExp(dynamicSqlIdentifierMarker); + const identifier = sqlBareIdentifierPattern(); + const triggerIdentifier = sqlTriggerIdentifierPattern(); + const dynamicTableReference = String.raw`(?:${dynamicIdentifier}|${identifier}\s*\.\s*${dynamicIdentifier}|${dynamicIdentifier}\s*\.\s*${identifier})`; + const dynamicFieldReference = String.raw`(?:${dynamicIdentifier}|${identifier}\s*\.\s*${dynamicIdentifier}|${dynamicIdentifier}\s*\.\s*${identifier})`; + const anyTableReference = sqlAnyTableReferencePattern(); + + // raw 写 SQL 里的动态表/字段/trigger identifier 无法静态证明边界,必须 fail-closed。 + return ( + new RegExp(String.raw`\bUPDATE\s+(?:ONLY\s+)?${dynamicTableReference}(?:\s+(?:AS\s+)?${identifier})?\s+SET\b`, "i").test( + sql + ) || + new RegExp(String.raw`\bUPDATE\b[\s\S]*?\bSET\b[\s\S]*?\b${dynamicFieldReference}\s*=`, "i").test(sql) || + new RegExp(String.raw`\bINSERT\s+INTO\s+${dynamicTableReference}\b`, "i").test(sql) || + new RegExp(String.raw`\bINSERT\s+INTO\b[\s\S]*?\([^)]*\b${dynamicFieldReference}\b[^)]*\)\s+VALUES\b`, "i").test(sql) || + new RegExp(String.raw`\bDELETE\s+FROM\s+(?:ONLY\s+)?${dynamicTableReference}\b`, "i").test(sql) || + new RegExp(sqlTruncateTableListPattern(dynamicTableReference), "i").test(sql) || + new RegExp(sqlDropTableListPattern(dynamicTableReference), "i").test(sql) || + new RegExp(String.raw`\bDROP\s+TRIGGER\s+(?:IF\s+EXISTS\s+)?${dynamicFieldReference}\s+ON\s+${anyTableReference}\b`, "i").test( + sql + ) || + new RegExp( + String.raw`\bDROP\s+TRIGGER\s+(?:IF\s+EXISTS\s+)?${triggerIdentifier}\s+ON\s+(?:ONLY\s+)?${dynamicTableReference}\b`, + "i" + ).test(sql) || + new RegExp(String.raw`\bALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?(?:ONLY\s+)?${dynamicTableReference}\b`, "i").test(sql) || + new RegExp(String.raw`\bALTER\s+TABLE\b[\s\S]*?\bDISABLE\s+TRIGGER\s+${dynamicFieldReference}\b`, "i").test(sql) + ); +} + +function hasDynamicRawSqlWriteCandidate(content, structure, source, sourceStart, sourceEnd, beforeIndex) { + return rawSqlScanCandidateSources(content, structure, source, sourceStart, sourceEnd, beforeIndex).some((candidateSource) => + hasDynamicRawSqlWrite(candidateSource) + ); +} + +function firstCallIdentifierArgument(structure, openParenIndex, closeParenIndex) { + const argumentStart = skipWhitespaceForward(structure, openParenIndex + 1); + if (argumentStart >= closeParenIndex) return null; + + const match = /^[A-Za-z_$][\w$]*/.exec(structure.slice(argumentStart, closeParenIndex)); + if (!match) return null; + const identifierEnd = argumentStart + match[0].length; + const nextIndex = skipWhitespaceForward(structure, identifierEnd); + + // 只跟踪 `raw(query)` 或 `raw(query, ...)` 这种简单变量,避免误读属性访问或函数调用。 + if (structure[nextIndex] !== "," && nextIndex !== closeParenIndex) return null; + return match[0]; +} + +function nthCallArgumentSource(content, structure, openParenIndex, closeParenIndex, argumentIndex) { + const argumentStart = skipWhitespaceForward(structure, openParenIndex + 1); + if (argumentStart >= closeParenIndex) return null; + + let parenDepth = 0; + let braceDepth = 0; + let bracketDepth = 0; + let currentArgumentIndex = 0; + let currentArgumentStart = argumentStart; + + for (let cursor = argumentStart; cursor < closeParenIndex; cursor += 1) { + const char = structure[cursor]; + if (char === "(") parenDepth += 1; + if (char === ")") parenDepth -= 1; + if (char === "{") braceDepth += 1; + if (char === "}") braceDepth -= 1; + if (char === "[") bracketDepth += 1; + if (char === "]") bracketDepth -= 1; + if (char === "," && parenDepth === 0 && braceDepth === 0 && bracketDepth === 0) { + if (currentArgumentIndex === argumentIndex) { + const end = skipWhitespaceBackward(structure, cursor - 1) + 1; + return { index: currentArgumentStart, end, source: content.slice(currentArgumentStart, end) }; + } + + currentArgumentIndex += 1; + currentArgumentStart = skipWhitespaceForward(structure, cursor + 1); + } + } + + if (currentArgumentIndex !== argumentIndex || currentArgumentStart >= closeParenIndex) return null; + const end = skipWhitespaceBackward(structure, closeParenIndex - 1) + 1; + return { index: currentArgumentStart, end, source: content.slice(currentArgumentStart, end) }; +} + +const rawSqlExecutorNames = ["$executeRawUnsafe", "$executeRaw", "$queryRawUnsafe", "$queryRaw"]; +const rawSqlExecutorPatternSource = + String.raw`${staticPrismaPropertyAccessPattern(rawSqlExecutorNames)}\s*(?:<[^>()` + "`" + String.raw`]*>)?\s*`; + +function rawSqlExecutorPattern() { + return new RegExp(rawSqlExecutorPatternSource, "g"); +} + +function rawSqlStructure(content) { + // raw executor 需要保留 db["$executeRawUnsafe"] 这类静态 bracket key;SQL 参数本体仍等长遮蔽。 + return stripStringLiteralsExceptPropertyKeys(maskCommentsOutsideStringLiterals(content)); +} + +function rawSqlMemberOperation(structure, callStart) { + const operationStart = skipWhitespaceForward(structure, callStart); + + if (structure[operationStart] === "(") { + return { kind: "direct", callStart: operationStart }; + } + + if (structure[operationStart] === "`") { + return { kind: "template", templateStart: operationStart }; + } + + if (structure.startsWith("?.", operationStart)) { + const optionalTargetStart = skipWhitespaceForward(structure, operationStart + 2); + if (structure[optionalTargetStart] === "(") { + return { kind: "direct", callStart: optionalTargetStart }; + } + + // `raw?.call(...)` / `raw?.bind(...)` 的 method name 在 `?.` 后面,不能先吃掉 `?.` 再要求 method 前缀。 + const optionalMethodMatch = /^(call|bind)\b/.exec(structure.slice(optionalTargetStart)); + if (optionalMethodMatch) { + return { + kind: optionalMethodMatch[1], + methodNameEnd: optionalTargetStart + optionalMethodMatch[1].length + }; + } + } + + const methodMatch = /^(?:\.|\?\.)\s*(call|bind)\b/.exec(structure.slice(operationStart)); + if (!methodMatch) return null; + + return { + kind: methodMatch[1], + methodNameEnd: operationStart + methodMatch[0].length + }; +} + +function rawSqlBindCloseParenIndex(structure, rawMatchEnd, statementEnd = structure.length) { + const operation = rawSqlMemberOperation(structure, rawMatchEnd); + if (operation?.kind !== "bind") return -1; + + const methodOpenParenIndex = structure.indexOf("(", operation.methodNameEnd); + if (methodOpenParenIndex === -1 || methodOpenParenIndex >= statementEnd) return -1; + + const methodCloseParenIndex = findMatchingParen(structure, methodOpenParenIndex); + return methodCloseParenIndex !== -1 && methodCloseParenIndex <= statementEnd ? methodCloseParenIndex : -1; +} + +function hasLineTerminator(source) { + return /[\n\r\u2028\u2029]/.test(source); +} + +function isRawSqlBoundAliasExpressionContinuation(structure, index) { + if (index >= structure.length) return false; + if (structure.startsWith("?.", index)) return true; + + // 换行后这些 token 仍可能继续前一条表达式;此时不能把 `.bind(...)` 当作 ASI 结束。 + return "([.`+-/*%,".includes(structure[index]); +} + +function rawSqlBoundAliasInitializerEnd(structure, bindCloseParenIndex, statementEnd) { + const nextTokenIndex = skipWhitespaceForward(structure, bindCloseParenIndex + 1); + if (nextTokenIndex === statementEnd) return statementEnd; + + const gapAfterBind = structure.slice(bindCloseParenIndex + 1, nextTokenIndex); + if (!hasLineTerminator(gapAfterBind)) return -1; + if (isRawSqlBoundAliasExpressionContinuation(structure, nextTokenIndex)) return -1; + + // 无分号合法代码依靠 ASI 在换行处结束 initializer;alias.end 只覆盖 `.bind(...)` 表达式本身。 + return bindCloseParenIndex + 1; +} + +function isSimpleRawSqlBoundAliasInitializerPrefix(structure, initializerStart, rawMatchStart) { + const prefix = structure.slice(initializerStart, rawMatchStart).trim(); + if (prefix.length === 0) return false; + + // 防止无分号场景把后续语句里的 raw executor 误归到当前声明 initializer。 + return !/[;\n\r\u2028\u2029]/.test(prefix) && !/\b(?:const|let|var|await|return|throw|if|for|while|switch|class|function|import|export)\b/.test(prefix); +} + +function findRawSqlBoundExecutorAliases(structure) { + const aliases = []; + const declarationPattern = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\b(?:\s*:[^=;]+)?\s*=/g; + + for (const declarationMatch of structure.matchAll(declarationPattern)) { + if (typeof declarationMatch.index !== "number") continue; + + const equalsIndex = structure.indexOf("=", declarationMatch.index); + if (equalsIndex === -1) continue; + + const initializerStart = skipWhitespaceForward(structure, equalsIndex + 1); + const statementEnd = findStatementEnd(structure, initializerStart); + + for (const rawMatch of structure.slice(initializerStart, statementEnd).matchAll(rawSqlExecutorPattern())) { + if (typeof rawMatch.index !== "number") continue; + + const rawMatchStart = initializerStart + rawMatch.index; + if (!isSimpleRawSqlBoundAliasInitializerPrefix(structure, initializerStart, rawMatchStart)) continue; + + const rawMatchEnd = rawMatchStart + rawMatch[0].length; + const bindCloseParenIndex = rawSqlBindCloseParenIndex(structure, rawMatchEnd, statementEnd); + if (bindCloseParenIndex === -1) continue; + + const initializerEnd = rawSqlBoundAliasInitializerEnd(structure, bindCloseParenIndex, statementEnd); + if (initializerEnd === -1) continue; + + // 只跟踪同文件的简单 bound executor alias;复杂重赋值/跨函数数据流继续交给后续 review 扩展。 + aliases.push({ + name: declarationMatch[1], + index: declarationMatch.index, + end: initializerEnd + }); + break; + } + } + + return aliases; +} + +function isMemberIdentifierReference(structure, identifierIndex) { + const previousIndex = skipWhitespaceBackward(structure, identifierIndex - 1); + return previousIndex >= 0 && structure[previousIndex] === "."; +} + +function rawSqlBoundAliasInvocationSources(content, structure) { + const sources = []; + const aliases = findRawSqlBoundExecutorAliases(structure); + + for (const alias of aliases) { + const aliasCallPattern = new RegExp(String.raw`\b${escapeRegExp(alias.name)}\b\s*(?:<[^>()` + "`" + String.raw`]*>)?\s*`, "g"); + + for (const aliasMatch of structure.matchAll(aliasCallPattern)) { + if (typeof aliasMatch.index !== "number" || aliasMatch.index <= alias.end) continue; + if (isMemberIdentifierReference(structure, aliasMatch.index)) continue; + + let callStart = skipWhitespaceForward(structure, aliasMatch.index + aliasMatch[0].length); + if (structure.startsWith("?.", callStart)) { + callStart = skipWhitespaceForward(structure, callStart + 2); + } + + if (structure[callStart] !== "(") continue; + + const closeParenIndex = findMatchingParen(structure, callStart); + if (closeParenIndex === -1) continue; + + const sqlArgument = nthCallArgumentSource(content, structure, callStart, closeParenIndex, 0); + if (sqlArgument) sources.push({ ...sqlArgument, beforeIndex: aliasMatch.index }); + } + } + + return sources; +} + +function rawSqlInvocationSources(content, structure = rawSqlStructure(content)) { + const sources = []; + + for (const match of structure.matchAll(rawSqlExecutorPattern())) { + if (typeof match.index !== "number") continue; + let callStart = skipWhitespaceForward(structure, match.index + match[0].length); + const operation = rawSqlMemberOperation(structure, callStart); + + if (operation?.kind === "direct") { + const closeParenIndex = findMatchingParen(structure, operation.callStart); + if (closeParenIndex === -1) continue; + const sqlArgument = nthCallArgumentSource(content, structure, operation.callStart, closeParenIndex, 0); + if (sqlArgument) sources.push({ ...sqlArgument, beforeIndex: match.index }); + continue; + } + + if (operation?.kind === "template") { + const templateEnd = findStringLiteralEnd(content, operation.templateStart); + if (templateEnd !== -1) { + sources.push({ + source: content.slice(operation.templateStart, templateEnd + 1), + index: operation.templateStart, + end: templateEnd + 1, + beforeIndex: match.index + }); + } + continue; + } + + if (operation?.kind !== "call" && operation?.kind !== "bind") continue; + + const methodOpenParenIndex = structure.indexOf("(", operation.methodNameEnd); + if (methodOpenParenIndex === -1) continue; + const methodCloseParenIndex = findMatchingParen(structure, methodOpenParenIndex); + if (methodCloseParenIndex === -1) continue; + + if (operation.kind === "call") { + // .call(thisArg, sql, ...) 的 SQL 是第二个参数。 + const sqlArgument = nthCallArgumentSource(content, structure, methodOpenParenIndex, methodCloseParenIndex, 1); + if (sqlArgument) sources.push({ ...sqlArgument, beforeIndex: match.index }); + continue; + } + + let boundCallStart = skipWhitespaceForward(structure, methodCloseParenIndex + 1); + if (structure.startsWith("?.", boundCallStart)) { + boundCallStart = skipWhitespaceForward(structure, boundCallStart + 2); + } + + if (structure[boundCallStart] !== "(") continue; + const boundCloseParenIndex = findMatchingParen(structure, boundCallStart); + if (boundCloseParenIndex === -1) continue; + const sqlArgument = nthCallArgumentSource(content, structure, boundCallStart, boundCloseParenIndex, 0); + if (sqlArgument) sources.push({ ...sqlArgument, beforeIndex: match.index }); + } + + return sources.concat(rawSqlBoundAliasInvocationSources(content, structure)); +} + +function simpleIdentifierSourceName(structure, sourceStart, sourceEnd) { + const identifierStart = skipWhitespaceForward(structure, sourceStart); + const identifierEnd = skipWhitespaceBackward(structure, sourceEnd - 1) + 1; + if (identifierStart >= identifierEnd) return null; + + const source = structure.slice(identifierStart, identifierEnd); + return /^[A-Za-z_$][\w$]*$/.test(source) ? source : null; +} + +function hasRawSqlInvocationMatching(content, predicate, structure = rawSqlStructure(content)) { + for (const invocation of rawSqlInvocationSources(content, structure)) { + const { source, index, end, beforeIndex } = invocation; + if (rawSqlScanCandidateSources(content, structure, source, index, end, beforeIndex).some((candidateSource) => predicate(candidateSource))) { + return true; + } + + const variableName = simpleIdentifierSourceName(structure, index, end); + if ( + variableName && + findVariableInitializerSources(content, structure, variableName, beforeIndex).some(({ source: variableSource, index: variableIndex, end: variableEnd }) => + rawSqlScanCandidateSources(content, structure, variableSource, variableIndex, variableEnd, beforeIndex).some((candidateSource) => + predicate(candidateSource) + ) + ) + ) { + return true; + } + } + + return false; +} + +function hasDynamicIdentifierRawSqlWrite(content) { + return hasRawSqlInvocationMatching(content, hasDynamicRawSqlWrite); +} + +function hasRawJobStatusWrite(content) { + // raw SQL 检测仍从原始 content 切片读取 SQL 字符串;structure 只负责可靠找到调用边界。 + return hasRawSqlInvocationMatching(content, hasRawJobRuntimeFieldWrite); +} + +function hasForbiddenRawJobStatusWrite(filePath, content) { + // migration.sql 没有 Prisma raw 调用包装,必须直接扫描 SQL 文件本体。 + if (filePath.endsWith(".sql")) return hasRawJobRuntimeFieldWrite(content); + return hasRawJobStatusWrite(content); +} + +function hasRawAuditLogMutation(sqlSource, options = {}) { + const sql = normalizeRawSqlScanSource(sqlSource); + const auditLogTable = sqlTableReferencePattern("AuditLog"); + const auditLogAppendOnlyFunction = sqlFunctionReferencePattern(auditLogAppendOnlyFunctionName); + const identifier = sqlBareIdentifierPattern(); + const triggerIdentifier = sqlTriggerIdentifierPattern(); + const createsAuditLogAppendOnlyFunction = new RegExp( + String.raw`\bCREATE\s+(?:OR\s+REPLACE\s+)?FUNCTION\s+${auditLogAppendOnlyFunction}\b`, + "i" + ).test(sql); + return ( + new RegExp(String.raw`\bUPDATE\s+(?:ONLY\s+)?${auditLogTable}(?:\s+(?:AS\s+)?${identifier})?\s+SET\b`, "i").test(sql) || + new RegExp(String.raw`\bDELETE\s+FROM\s+(?:ONLY\s+)?${auditLogTable}\b`, "i").test(sql) || + new RegExp(sqlTruncateTableListPattern(auditLogTable), "i").test(sql) || + new RegExp(sqlDropTableListPattern(auditLogTable), "i").test(sql) || + new RegExp(String.raw`\bDROP\s+TRIGGER\s+(?:IF\s+EXISTS\s+)?${triggerIdentifier}\s+ON\s+(?:ONLY\s+)?${auditLogTable}\b`, "i").test(sql) || + new RegExp( + String.raw`\bALTER\s+TABLE\s+(?:IF\s+EXISTS\s+)?(?:ONLY\s+)?${auditLogTable}\s+(?:DISABLE\s+(?:TRIGGER|RULE)\b|DROP\b|RENAME\b)`, + "i" + ).test(sql) || + new RegExp(String.raw`\bDROP\s+FUNCTION\s+(?:IF\s+EXISTS\s+)?${auditLogAppendOnlyFunction}\b`, "i").test(sql) || + (!options.allowAuditLogAppendOnlyFunctionCreate && createsAuditLogAppendOnlyFunction) || + new RegExp(String.raw`\bALTER\s+FUNCTION\s+${auditLogAppendOnlyFunction}\b`, "i").test(sql) + ); +} + +function hasForbiddenRawAuditLogMutation(filePath, content, structure) { + const auditSqlOptions = { + allowAuditLogAppendOnlyFunctionCreate: allowsAuditLogAppendOnlyFunctionDefinition(filePath) + }; + + if (filePath.endsWith(".sql")) return hasRawAuditLogMutation(content, auditSqlOptions); + + for (const invocation of rawSqlInvocationSources(content, structure)) { + const { source, index, end, beforeIndex } = invocation; + const hasForbiddenSql = + rawSqlScanCandidateSources(content, structure, source, index, end, beforeIndex).some((candidateSource) => + hasRawAuditLogMutation(candidateSource, auditSqlOptions) + ) || + (() => { + const variableName = simpleIdentifierSourceName(structure, index, end); + return ( + variableName !== null && + findVariableInitializerSources(content, structure, variableName, beforeIndex).some( + ({ source: variableSource, index: variableIndex, end: variableEnd }) => + rawSqlScanCandidateSources(content, structure, variableSource, variableIndex, variableEnd, beforeIndex).some((candidateSource) => + hasRawAuditLogMutation(candidateSource, auditSqlOptions) + ) + ) + ); + })(); + + if (!hasForbiddenSql) continue; + if (isAllowedAuditTriggerAssertion(filePath, content, structure, beforeIndex)) continue; + return true; + } + + return false; +} + +function jobExecutionStoreClassSpans(content) { + const spans = []; + const structure = maskStringLiterals(maskCommentsOutsideStringLiterals(content)); + const classPattern = /\b(?:export\s+)?class\s+JobExecutionStore\b/g; + + for (const match of structure.matchAll(classPattern)) { + if (typeof match.index !== "number") continue; + const openBraceIndex = structure.indexOf("{", match.index + match[0].length); + if (openBraceIndex === -1) continue; + const closeBraceIndex = findMatchingBrace(structure, openBraceIndex); + if (closeBraceIndex === -1) continue; + spans.push({ start: match.index, end: closeBraceIndex + 1 }); + } + + return spans; +} + +function maskSpans(content, spans) { + if (spans.length === 0) return content; + let output = ""; + let cursor = 0; + + for (const span of spans.toSorted((left, right) => left.start - right.start)) { + if (span.start < cursor) continue; + output += content.slice(cursor, span.start); + output += " ".repeat(span.end - span.start); + cursor = span.end; + } + + return output + content.slice(cursor); +} + +function maskJobExecutionStoreClassBodies(content) { + // 只遮蔽 JobExecutionStore 自身;同文件里的 API service / controller 仍要按普通边界扫描。 + return maskSpans(content, jobExecutionStoreClassSpans(content)); +} + +function hasForbiddenMigrationGuardSetter(content) { + const sql = stripSqlComments(content); + return /set_config\s*\(|SET\s+LOCAL/i.test(sql); +} + +function hasStateTransitionServiceImport(content) { + return /from\s+["'][^"']*state-transition(?:\/index\.js)?["']|StateTransitionService/.test(content); +} + +function isAllowedStateTransitionImportPath(filePath) { + // jobs 测试需要 StateTransitionService 创建受 guard 保护的版本夹具;这不是生产调用入口。 + if (stateTransitionImportFixtureTests.has(filePath)) return true; + return allowedStateTransitionImportPrefixes.some((prefix) => filePath.startsWith(prefix)); +} + +function isAllowedS1AnchorPath(filePath) { + return ( + filePath.startsWith("apps/api/prisma/") || + filePath.startsWith(stateTransitionModulePrefix) || + filePath.startsWith(auditModulePrefix) || + filePath === historicalPrismaSchemaTest + ); +} + +function hasJobStatusWrite(content) { + // Job 创建路径同样会写入运行态字段,S1 必须统一收敛到 JobExecutionStore。 + return ( + hasPrismaModelMethodCallContaining(content, ["job"], jobPrismaWriteMethods, { test: hasForbiddenJobWriteCallBody }) || + hasRawJobStatusWrite(content) + ); +} + +function hasForbiddenJobStatusWrite(filePath, content) { + // SQL 文件走原始 SQL 扫描;源码文件继续复用 Prisma 与 raw 调用扫描。 + if (filePath.endsWith(".sql")) return hasForbiddenRawJobStatusWrite(filePath, content); + return hasJobStatusWrite(content); +} + +function isAllowedJobExecutionStorePath(filePath) { + return filePath === jobExecutionStorePath; +} + +async function collectFiles(root, relativeDir) { + const absoluteDir = path.join(root, relativeDir); + const entries = await readdir(absoluteDir, { withFileTypes: true }).catch((error) => { + if (error && error.code === "ENOENT") return []; + throw error; + }); + const files = []; + + for (const entry of entries) { + const relativePath = normalizePath(path.join(relativeDir, entry.name)); + if (entry.isDirectory()) { + if (ignoredScanSegments.has(entry.name)) continue; + files.push(...(await collectFiles(root, relativePath))); + continue; + } + + if (entry.isFile() && sourceLikeFilePattern.test(entry.name) && !isIgnoredScanPath(relativePath)) { + files.push({ + path: relativePath, + content: await readFile(path.join(root, relativePath), "utf8") + }); + } + } + + return files; +} + +async function collectWorkspaceFiles(root) { + const files = []; + for (const scanRoot of scanRoots) { + files.push(...(await collectFiles(root, scanRoot))); + } + return files; +} + +function pushViolation(violations, filePath, reason, detail) { + violations.push({ path: filePath, reason, detail }); +} + +function findLaterPhaseScopeViolations(file, violations) { + for (const term of laterPhaseDeniedTerms) { + // 路径名本身不能提供 validateContract 调用上下文;harness-client 测试也不能按路径泛化放行。 + if (pathContainsLaterPhaseTerm(file.path, term)) { + pushViolation(violations, file.path, "LATER_PHASE_SCOPE_LEAK", term); + continue; + } + + let hasContentViolation = false; + for (const contentTerm of contentDeniedTermVariants(term)) { + let index = file.content.indexOf(contentTerm); + while (index !== -1) { + if (!isAllowedHarnessValidationContractReferenceAt(file.path, file.content, contentTerm, index)) { + pushViolation(violations, file.path, "LATER_PHASE_SCOPE_LEAK", term); + hasContentViolation = true; + break; + } + index = file.content.indexOf(contentTerm, index + contentTerm.length); + } + if (hasContentViolation) break; + } + } +} + +function findHarnessClientContractReferenceViolations(file, violations) { + if (!isHarnessClientTestPath(file.path)) return; + + for (const term of harnessClientContractWatchTerms) { + let index = file.content.indexOf(term); + while (index !== -1) { + if (!isAllowedHarnessClientContractReferenceAt(file.path, file.content, term, index)) { + pushViolation(violations, file.path, "HARNESS_CONTRACT_REFERENCE_OUTSIDE_VALIDATION", term); + break; + } + index = file.content.indexOf(term, index + term.length); + } + } +} + +function findS1AnchorScopeViolations(file, violations) { + if (isAllowedS1AnchorPath(file.path)) return; + for (const term of s1AnchorTerms) { + if (file.content.includes(term)) { + pushViolation(violations, file.path, "S1_ANCHOR_SCOPE_MISUSE", term); + } + } +} + +function findAuditBoundaryViolations(file, violations) { + if (isGeneratedPrismaFile(file.path)) return; + if (hasForbiddenAuditMutation(file.path, file.content)) { + pushViolation(violations, file.path, "AUDIT_UPDATE_DELETE_FORBIDDEN", "auditLog update/delete/upsert"); + } +} + +function findDynamicRawSqlViolations(file, violations) { + if (isGeneratedPrismaFile(file.path)) return; + if (hasDynamicIdentifierRawSqlWrite(file.content)) { + pushViolation(violations, file.path, "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", "dynamic raw SQL write identifier"); + } +} + +function findStateBoundaryViolations(file, violations) { + if (isHistoricalTestFile(file.path) || isGeneratedPrismaFile(file.path)) return; + + if (file.path.startsWith("apps/worker/")) { + if (/@prisma\/client|generated\/prisma|PrismaClient/.test(file.content)) { + pushViolation(violations, file.path, "WORKER_DB_IMPORT_FORBIDDEN", "Prisma import in worker"); + } + if (/state-transition|StateTransitionService|app\.state_transition_guard|set_config\s*\(|SET\s+LOCAL/i.test(file.content)) { + pushViolation(violations, file.path, "WORKER_STATE_TRANSITION_IMPORT_FORBIDDEN", "state transition coupling in worker"); + } + return; + } + + if (hasStateTransitionServiceImport(file.content) && !isAllowedStateTransitionImportPath(file.path)) { + pushViolation(violations, file.path, "STATE_TRANSITION_SERVICE_IMPORT_FORBIDDEN", "state-transition service import"); + } + + if (file.path.startsWith(stateTransitionModulePrefix)) return; + + if (file.path.startsWith(prismaMigrationPrefix)) { + // migration 允许安装 trigger/current_setting guard,但不允许写运行时 guard setter。 + if (hasForbiddenMigrationGuardSetter(file.content)) { + pushViolation(violations, file.path, "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION", "migration runtime guard setter"); + } + if (hasGuardedPrismaWrite(file.content)) { + pushViolation(violations, file.path, "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION", "migration guarded model write"); + } + return; + } + + if (hasGuardedPrismaWrite(file.content)) { + pushViolation(violations, file.path, "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION", "guarded model write"); + } + if (hasRuntimeGuardSetter(file.content)) { + pushViolation(violations, file.path, "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION", "runtime guard setter"); + } +} + +function findJobExecutionBoundaryViolations(file, violations) { + const scanContent = isAllowedJobExecutionStorePath(file.path) ? maskJobExecutionStoreClassBodies(file.content) : file.content; + if (hasForbiddenJobStatusWrite(file.path, scanContent)) { + pushViolation(violations, file.path, "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", "Job status write"); + } +} + +function findViolationsInFiles(files) { + const violations = []; + for (const file of files) { + if (isIgnoredScanPath(file.path) || isGeneratedPrismaFile(file.path)) continue; + findLaterPhaseScopeViolations(file, violations); + findHarnessClientContractReferenceViolations(file, violations); + findS1AnchorScopeViolations(file, violations); + findAuditBoundaryViolations(file, violations); + findStateBoundaryViolations(file, violations); + findDynamicRawSqlViolations(file, violations); + findJobExecutionBoundaryViolations(file, violations); + } + return violations; +} + +async function findS1ScopeViolations(root) { + return findViolationsInFiles(await collectWorkspaceFiles(root)); +} + +async function withFixture(files, callback) { + const root = await mkdtemp(path.join(os.tmpdir(), "huijing-s1-scope-")); + try { + for (const [relativePath, content] of Object.entries(files)) { + const absolutePath = path.join(root, relativePath); + await mkdir(path.dirname(absolutePath), { recursive: true }); + await writeFile(absolutePath, content); + } + return await callback(root); + } finally { + await rm(root, { recursive: true, force: true }); + } +} + +function assertHasReason(violations, reason, label) { + if (!violations.some((violation) => violation.reason === reason)) { + throw new Error(`${label}: expected ${reason}`); + } +} + +function assertNoViolations(violations, label) { + if (violations.length > 0) { + const details = violations.map(formatViolation).join("; "); + throw new Error(`${label}: expected no violations, got ${details}`); + } +} + +function formatViolation(violation) { + return `${violation.path}: ${violation.reason}${violation.detail ? ` (${violation.detail})` : ""}`; +} + +async function runSelfTests() { + await withFixture( + { + "apps/api/src/modules/creator/index.ts": 'export const route = "creation-agent/messages";' + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertHasReason(violations, "LATER_PHASE_SCOPE_LEAK", "later-phase app route"); + } + ); + + await withFixture( + { + "packages/harness-client/src/index.spec.ts": + 'createHarnessClient().validateContract("MiniGameCodeConversion", { id: "fixture" });' + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertNoViolations(violations, "harness-client S0 contract fixture reference"); + } + ); + + await withFixture( + { + "packages/harness-client/src/probe.spec.ts": + 'createHarnessClient(); const businessModelName = "MiniGameProject";' + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertHasReason(violations, "LATER_PHASE_SCOPE_LEAK", "harness-client non-validation S0 contract probe"); + } + ); + + await withFixture( + { + "packages/harness-client/src/bad-game-ir.spec.ts": 'const contractName = "GameIR";' + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertHasReason(violations, "LATER_PHASE_SCOPE_LEAK", "harness-client non-validation GameIR contract name"); + } + ); + + await withFixture( + { + "packages/harness-client/src/bad-validation-report.spec.ts": 'const contractName = "ValidationReport";' + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertHasReason( + violations, + "HARNESS_CONTRACT_REFERENCE_OUTSIDE_VALIDATION", + "harness-client non-validation ValidationReport contract name" + ); + } + ); + + await withFixture( + { + "packages/harness-client/src/index.spec.ts": + 'createHarnessClient().validateContract("GameIR", { id: "fixture" });' + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertNoViolations(violations, "harness-client GameIR validation reference"); + } + ); + + await withFixture( + { + "packages/harness-client/src/index.spec.ts": + 'createHarnessClient().validateContract("ValidationReport", { id: "fixture" });' + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertNoViolations(violations, "harness-client ValidationReport validation reference"); + } + ); + + await withFixture( + { + "packages/harness-client/src/index.spec.ts": 'expect(args[2]).toBe("GameIR");' + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertHasReason(violations, "LATER_PHASE_SCOPE_LEAK", "isolated harness-client args[2] contract assertion"); + } + ); + + await withFixture( + { + "packages/harness-client/src/index.spec.ts": ` +const runner = async (_file, args) => { + expect(args.slice(0, 2)).toEqual([realHarnessCli, "--contract"]); + expect(args[2]).toBe("GameIR"); +}; +` + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertNoViolations(violations, "harness-client args[2] assertion with runner contract context"); + } + ); + + const harnessClientPathOnlyLaterPhaseFixtures = [ + "packages/harness-client/src/game-ir.spec.ts", + "packages/harness-client/src/game-ir/index.spec.ts", + "packages/harness-client/src/game-ir-artifact.spec.ts", + "packages/harness-client/src/validation-report.spec.ts" + ]; + + for (const filePath of harnessClientPathOnlyLaterPhaseFixtures) { + await withFixture( + { + [filePath]: "export const harmless = true;" + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertHasReason(violations, "LATER_PHASE_SCOPE_LEAK", `harness-client path-only later-phase leak ${filePath}`); + } + ); + } + + await withFixture( + { + "apps/api/src/modules/projects/index.ts": 'const contractName = "MiniGameCodeConversion";' + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertHasReason(violations, "LATER_PHASE_SCOPE_LEAK", "API business later-phase contract"); + } + ); + + await withFixture( + { + "apps/api/src/modules/projects/agent.ts": "export class MainCreationAgentSessionController {}" + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertHasReason(violations, "S1_ANCHOR_SCOPE_MISUSE", "S1 anchor business misuse"); + } + ); + + await withFixture( + { + "apps/api/prisma/migrations/20260601000000_guard/migration.sql": ` +CREATE OR REPLACE FUNCTION app_require_state_transition_guard() +RETURNS trigger AS $$ +BEGIN + IF current_setting('app.state_transition_guard', true) IS DISTINCT FROM 'on' THEN + RAISE EXCEPTION 'guard required'; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; +CREATE TRIGGER "LifecycleEvent_a_guard_insert" BEFORE INSERT ON "LifecycleEvent" +FOR EACH ROW EXECUTE FUNCTION app_require_state_transition_guard(); +` + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertNoViolations(violations, "migration trigger/current_setting guard"); + } + ); + + const failingFixtures = [ + { + label: "migration set_config guard setter", + reason: "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/prisma/migrations/20260601000001_bad_guard/migration.sql": + "SELECT set_config('app.state_transition_guard', 'on', true);" + } + }, + { + label: "app SET LOCAL guard setter", + reason: "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/src/modules/projects/bad.ts": 'await db.$executeRawUnsafe("SET LOCAL app.state_transition_guard = on");' + } + }, + { + label: "app raw SQL guard setter", + reason: "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/src/modules/projects/raw.ts": + 'await db.$executeRawUnsafe("SELECT set_config(\'app.state_transition_guard\', \'on\', true)");' + } + }, + { + label: "API spec raw SQL guard setter", + reason: "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/src/modules/projects/bad.spec.ts": + 'await db.$executeRawUnsafe("SELECT set_config(\'app.state_transition_guard\', \'on\', true)");' + } + }, + { + label: "API spec SET LOCAL guard setter", + reason: "STATE_GUARD_SETTER_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/src/modules/projects/bad-set-local.spec.ts": + 'await db.$executeRawUnsafe("SET LOCAL app.state_transition_guard = on");' + } + }, + { + label: "audit update/delete outside audit module", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit.ts": + "await db.auditLog.update({ where: { id }, data: {} }); await db.auditLog.delete({ where: { id } });" + } + }, + { + label: "audit bracket model update outside audit module", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-bracket-model.ts": + 'await db["auditLog"].update({ where: { id }, data: {} });' + } + }, + { + label: "audit bracket method delete outside audit module", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-bracket-method.ts": + 'await db.auditLog["delete"]({ where: { id } });' + } + }, + { + label: "audit bracket model and method delete outside audit module", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-bracket-model-method.ts": + 'await db["auditLog"]["delete"]({ where: { id } });' + } + }, + { + label: "audit optional delete outside audit module", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-optional-delete.ts": "await db.auditLog?.delete({ where: { id } });" + } + }, + { + label: "audit optional bracket delete outside audit module", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-optional-bracket-delete.ts": + 'await db["auditLog"]?.["delete"]({ where: { id } });' + } + }, + { + label: "audit delegate alias delete outside audit module", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-alias-delete.ts": + "const logs = db.auditLog; await logs.delete({ where: { id } });" + } + }, + { + label: "audit update/delete in API spec outside audit module", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit.spec.ts": "await db.auditLog.update({ where: { id }, data: {} });" + } + }, + { + label: "audit update/delete inside audit module implementation", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/audit/bad.ts": + "await db.auditLog.update({ where: { id }, data: {} }); await db.auditLog.delete({ where: { id } });" + } + }, + { + label: "state-transition service import outside allowed path", + reason: "STATE_TRANSITION_SERVICE_IMPORT_FORBIDDEN", + files: { + "apps/api/src/modules/assets/state.ts": 'import { StateTransitionService } from "../state-transition/index.js";' + } + }, + { + label: "Prisma import in worker", + reason: "WORKER_DB_IMPORT_FORBIDDEN", + files: { + "apps/worker/src/index.ts": 'import { PrismaClient } from "@prisma/client";' + } + }, + { + label: "worker state-transition import", + reason: "WORKER_STATE_TRANSITION_IMPORT_FORBIDDEN", + files: { + "apps/worker/src/state.ts": 'import { StateTransitionService } from "../../api/src/modules/state-transition/index.js";' + } + }, + { + label: "direct Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job.ts": "await db.job.update({ where: { id }, data: { status: 'failed' } });" + } + }, + { + label: "direct Job bracket model status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-bracket-model.ts": + 'await db["job"].update({ where: { id }, data: { status: "failed" } });' + } + }, + { + label: "direct Job bracket method status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-bracket-method.ts": + 'await db.job["update"]({ where: { id }, data: { status: "failed" } });' + } + }, + { + label: "direct Job bracket model and method status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-bracket-model-method.ts": + 'await db["job"]["update"]({ where: { id }, data: { status: "failed" } });' + } + }, + { + label: "direct Job optional status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-optional-update.ts": + "await db.job?.update({ where: { id }, data: { status } });" + } + }, + { + label: "direct Job optional bracket status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-optional-bracket-update.ts": + 'await db["job"]?.["update"]({ where: { id }, data: { status } });' + } + }, + { + label: "direct Job delegate alias status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-alias-update.ts": + "const jobs = db.job; await jobs.update({ where: { id }, data: { status } });" + } + }, + { + label: "direct Job status write with comment paren outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-comment-paren.ts": ` +await db.job.update({ // ) + where: { id }, + data: { status: "failed" } +}); +` + } + }, + { + label: "direct Job status write with data identifier outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-data-identifier.ts": + 'const patch = { status: "failed" }; await db.job.update({ where: { id }, data: patch });' + } + }, + { + label: "direct Job status write with quoted keys outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-quoted.ts": + 'await db.job.update({ where: { id }, data: { "status": "failed", \'attempts\': 1, [`nextRetryAt`]: null } });' + } + }, + { + label: "direct Job lease token write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-lease-token.ts": + 'await db.job.update({ where: { id }, data: { leaseToken: "stolen" } });' + } + }, + { + label: "direct Job timeoutAt write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-timeout-at.ts": + 'await db.job.update({ where: { id }, data: { timeoutAt: new Date() } });' + } + }, + { + label: "direct Job runtime write with dynamic computed key outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-computed.ts": + 'const field = "status"; await db.job.update({ where: { id }, data: { [field]: "failed" } });' + } + }, + { + label: "direct Job status create outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-create.ts": + 'await db.job.create({ data: { projectId, actorId, status: "queued", attempts: 0, nextRetryAt: null } });' + } + }, + { + label: "variableized Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-variable-data.ts": + 'const data = { status: "failed" }; await db.job.update({ where: { id }, data });' + } + }, + { + label: "spread Job data write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-spread-data.ts": + 'const patch = { attempts: 1 }; await db.job.update({ where: { id }, data: { ...patch } });' + } + }, + { + label: "raw SQL Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-status.ts": + `await db.$executeRawUnsafe("UPDATE \\"Job\\" SET \\"status\\" = 'failed' WHERE id = $1", id);` + } + }, + { + label: "optional raw SQL Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-optional-status.ts": + 'await db.$executeRawUnsafe?.("UPDATE \\"Job\\" SET \\"status\\" = $1 WHERE id = $2", status, id);' + } + }, + { + label: "bound raw SQL Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-bind-status.ts": + 'await db.$executeRawUnsafe.bind(db)("UPDATE \\"Job\\" SET \\"status\\" = $1 WHERE id = $2", status, id);' + } + }, + { + label: "optional bound raw SQL Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-optional-bind-status.ts": + 'await db.$executeRawUnsafe?.bind(db)("UPDATE \\"Job\\" SET \\"status\\" = $1 WHERE id = $2", status, id);' + } + }, + { + label: "no-semicolon bound raw SQL Job status alias outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-bound-alias-no-semicolon.ts": ` +const execRaw = db.$executeRawUnsafe.bind(db) +await execRaw("UPDATE \\"Job\\" SET \\"status\\" = $1 WHERE id = $2", status, id) +` + } + }, + { + label: "no-semicolon optional bound raw SQL Job status alias outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-optional-bound-alias-no-semicolon.ts": ` +const execRaw = db.$executeRawUnsafe?.bind(db) +await execRaw("UPDATE \\"Job\\" SET \\"status\\" = $1 WHERE id = $2", status, id) +` + } + }, + { + label: "raw SQL Job status write with comment paren outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-comment-paren.ts": ` +await db.$executeRawUnsafe( // ) + "UPDATE \\"Job\\" SET \\"status\\" = 'failed' WHERE id = $1", + id +); +` + } + }, + { + label: "raw SQL Job attempts write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-attempts.ts": + 'await db.$executeRawUnsafe("UPDATE Job SET attempts = attempts + 1 WHERE id = $1", id);' + } + }, + { + label: "raw SQL Job nextRetryAt write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-next-retry.ts": + 'await db.$executeRawUnsafe("UPDATE \\"Job\\" SET \\"nextRetryAt\\" = NULL WHERE id = $1", id);' + } + }, + { + label: "raw SQL Job insert status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-insert-status.ts": + 'await db.$executeRawUnsafe("INSERT INTO \\"Job\\" (\\"id\\", \\"status\\") VALUES ($1, \'queued\')", id);' + } + }, + { + label: "raw SQL Job lease fields update outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-lease.ts": + 'await db.$executeRawUnsafe("UPDATE \\"Job\\" SET \\"leaseToken\\" = $1, \\"lockVersion\\" = \\"lockVersion\\" + 1 WHERE id = $2", token, id);' + } + }, + { + label: "raw SQL Job multi-column SET outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-multi-column-set.ts": + 'await db.$executeRawUnsafe("UPDATE \\"Job\\" SET (\\"status\\", \\"attempts\\") = (\'failed\', 1) WHERE id = $1", id);' + } + }, + { + label: "raw SQL Job MERGE update outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-merge.ts": + 'await db.$executeRawUnsafe("MERGE INTO \\"Job\\" j USING \\"JobPatch\\" p ON j.id = p.id WHEN MATCHED THEN UPDATE SET \\"status\\" = \'failed\'");' + } + }, + { + label: "raw SQL Job multi-table truncate outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-multi-truncate.ts": + 'await db.$executeRawUnsafe("TRUNCATE TABLE \\"Other\\", \\"Job\\"");' + } + }, + { + label: "migration SQL Job status update outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/prisma/migrations/20260602000000_bad_job_update/migration.sql": + 'UPDATE "Job" SET "status" = \'failed\' WHERE id = \'x\';' + } + }, + { + label: "migration SQL Job MERGE update outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/prisma/migrations/20260602000001_bad_job_merge/migration.sql": + 'MERGE INTO "Job" j USING "JobPatch" p ON j.id = p.id WHEN MATCHED THEN UPDATE SET "status" = \'failed\';' + } + }, + { + label: "migration SQL Job multi-table truncate outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/prisma/migrations/20260602000003_bad_job_truncate/migration.sql": + 'TRUNCATE TABLE "Other", "Job";' + } + }, + { + label: "raw SQL Job timeout insert outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-timeout.ts": + 'await db.$executeRawUnsafe("INSERT INTO Job (id, timeoutAt) VALUES ($1, NOW())", id);' + } + }, + { + label: "raw SQL schema-qualified Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-schema-qualified.ts": + 'await db.$executeRawUnsafe("UPDATE public.\\"Job\\" SET \\"status\\" = $1 WHERE id = $2", status, id);' + } + }, + { + label: "raw SQL aliased Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-alias.ts": + 'await db.$executeRawUnsafe("UPDATE \\"Job\\" j SET \\"status\\" = $1 WHERE j.id = $2", status, id);' + } + }, + { + label: "raw SQL ONLY Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-only.ts": + 'await db.$executeRawUnsafe("UPDATE ONLY \\"Job\\" SET \\"status\\" = $1 WHERE id = $2", status, id);' + } + }, + { + label: "Prisma.sql variable Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-prisma-sql-variable.ts": + 'const query = Prisma.sql`UPDATE public."Job" SET "status" = ${status} WHERE id = ${id}`; await db.$executeRaw(query);' + } + }, + { + label: "concatenated SQL variable Job status write outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-concatenated-variable.ts": + 'const query = "UPDATE " + "\\"Job\\"" + " SET " + "\\"status\\"" + " = $1 WHERE id = $2"; await db.$executeRawUnsafe(query, status, id);' + } + }, + { + label: "raw SQL Job status write through intermediate constants outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-raw-intermediate-constants.ts": ` +const tableName = '"Job"'; +const fieldName = '"status"'; +const query = "UPDATE " + tableName + " SET " + fieldName + " = $1 WHERE id = $2"; +await db.$executeRawUnsafe(query, status, id); +` + } + }, + { + label: "raw SQL Job status write through dynamic table variable outside JobExecutionStore", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/job-raw-dynamic-table.ts": ` +const tableName = process.env.JOB_TABLE ?? '"Job"'; +const fieldName = '"status"'; +const query = "UPDATE " + tableName + " SET " + fieldName + " = $1 WHERE id = $2"; +await db.$executeRawUnsafe(query, status, id); +` + } + }, + { + label: "raw SQL Job write through dynamic table function call outside JobExecutionStore", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/job-raw-dynamic-table-call.ts": ` +const query = "UPDATE " + resolveTable() + " SET status = $1 WHERE id = $2"; +await db.$executeRawUnsafe(query, status, id); +` + } + }, + { + label: "raw SQL Job write through dynamic field function call outside JobExecutionStore", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/job-raw-dynamic-field-call.ts": ` +const query = "UPDATE Job SET " + resolveField() + " = $1 WHERE id = $2"; +await db.$executeRawUnsafe(query, value, id); +` + } + }, + { + label: "Prisma.sql Job status write through Prisma.raw intermediate constants outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/projects/job-prisma-raw-intermediate-constants.ts": ` +const tableName = '"Job"'; +const fieldName = '"status"'; +const query = Prisma.sql\`UPDATE \${Prisma.raw(tableName)} SET \${Prisma.raw(fieldName)} = \${status} WHERE id = \${id}\`; +await db.$executeRaw(query); +` + } + }, + { + label: "Prisma.sql Job status write through dynamic Prisma.raw table outside JobExecutionStore", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/job-prisma-raw-dynamic-table.ts": ` +const tableName = process.env.JOB_TABLE ?? '"Job"'; +const fieldName = '"status"'; +const query = Prisma.sql\`UPDATE \${Prisma.raw(tableName)} SET \${Prisma.raw(fieldName)} = \${status} WHERE id = \${id}\`; +await db.$executeRaw(query); +` + } + }, + { + label: "raw SQL AuditLog update outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-update.ts": + 'await db.$executeRawUnsafe("UPDATE \\"AuditLog\\" SET \\"action\\" = $1 WHERE id = $2", action, id);' + } + }, + { + label: "raw SQL AuditLog delete outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-delete.ts": + 'await db.$executeRawUnsafe("DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "raw SQL AuditLog delete through dot whitespace executor access", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-dot-whitespace-delete.ts": + 'await db. $executeRawUnsafe("DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "raw SQL AuditLog delete through optional receiver executor access", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-optional-receiver-delete.ts": + 'await db?.$executeRawUnsafe("DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "raw SQL AuditLog delete through bracket executor access", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-bracket-delete.ts": + 'await db["$executeRawUnsafe"]("DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "raw SQL AuditLog delete through optional bracket executor access", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-optional-bracket-delete.ts": + 'await db?.["$executeRawUnsafe"]("DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "raw SQL AuditLog delete through bracket call executor access", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-bracket-call-delete.ts": + 'await db["$executeRawUnsafe"].call(db, "DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "raw SQL AuditLog delete through optional bracket call executor access", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-optional-bracket-call-delete.ts": + 'await db?.["$executeRawUnsafe"]?.call(db, "DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "raw SQL AuditLog delete through bracket bind executor access", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-bracket-bind-delete.ts": + 'await db["$executeRawUnsafe"].bind(db)("DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "raw SQL AuditLog delete through optional bracket bind executor access", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-optional-bracket-bind-delete.ts": + 'await db?.["$executeRawUnsafe"]?.bind(db)("DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "raw SQL AuditLog delete through bracket bound alias", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-bracket-bound-alias-delete.ts": ` +const execRaw = db["$executeRawUnsafe"].bind(db); +await execRaw("DELETE FROM \\"AuditLog\\" WHERE id = $1", id); +` + } + }, + { + label: "no-semicolon bracket raw SQL AuditLog delete through bound alias", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-bracket-bound-alias-no-semicolon-delete.ts": ` +const execRaw = db["$executeRawUnsafe"].bind(db) +await execRaw("DELETE FROM \\"AuditLog\\" WHERE id = $1", id) +` + } + }, + { + label: "no-semicolon optional bracket raw SQL AuditLog delete through bound alias", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-optional-bracket-bound-alias-no-semicolon-delete.ts": ` +const execRaw = db?.["$executeRawUnsafe"]?.bind(db) +await execRaw("DELETE FROM \\"AuditLog\\" WHERE id = $1", id) +` + } + }, + { + label: "raw SQL AuditLog delete through call outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-call-delete.ts": + 'await db.$executeRawUnsafe.call(db, "DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "optional raw SQL AuditLog delete through call outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-optional-call-delete.ts": + 'await db.$executeRawUnsafe?.call(db, "DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "optional raw SQL AuditLog delete outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-optional-delete.ts": + 'await db.$executeRawUnsafe?.("DELETE FROM \\"AuditLog\\" WHERE id = $1", id);' + } + }, + { + label: "bound raw SQL AuditLog delete alias outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-bound-alias-delete.ts": ` +const execRaw = db.$executeRawUnsafe.bind(db); +await execRaw("DELETE FROM \\"AuditLog\\" WHERE id = $1", id); +` + } + }, + { + label: "raw SQL AuditLog multi-table truncate outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-raw-multi-truncate.ts": + 'await db.$executeRawUnsafe("TRUNCATE TABLE \\"Other\\", \\"AuditLog\\"");' + } + }, + { + label: "raw SQL AuditLog IF EXISTS trigger disable outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-disable-trigger-if-exists.ts": + 'await db.$executeRawUnsafe("ALTER TABLE IF EXISTS \\"AuditLog\\" DISABLE TRIGGER ALL");' + } + }, + { + label: "raw SQL AuditLog trigger disable outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-disable-trigger.ts": + 'await db.$executeRawUnsafe("ALTER TABLE \\"AuditLog\\" DISABLE TRIGGER \\"AuditLog_reject_delete\\"");' + } + }, + { + label: "raw SQL AuditLog drop trigger outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-drop-trigger.ts": + 'await db.$executeRawUnsafe("DROP TRIGGER audit_append_only ON \\"AuditLog\\"");' + } + }, + { + label: "raw SQL AuditLog quoted drop trigger outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-drop-trigger-quoted.ts": + 'await db.$executeRawUnsafe("DROP TRIGGER \\"audit-append-only\\" ON \\"AuditLog\\";");' + } + }, + { + label: "raw SQL AuditLog multi-table drop outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-drop-table-list.ts": + 'await db.$executeRawUnsafe("DROP TABLE \\"Other\\", \\"AuditLog\\"");' + } + }, + { + label: "raw SQL AuditLog alter table drop outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-alter-table-drop.ts": + 'await db.$executeRawUnsafe("ALTER TABLE \\"AuditLog\\" DROP CONSTRAINT foo");' + } + }, + { + label: "raw SQL AuditLog drop append-only function outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-drop-function.ts": + 'await db.$executeRawUnsafe("DROP FUNCTION app_reject_audit_log_mutation() CASCADE");' + } + }, + { + label: "raw SQL AuditLog replace append-only function outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-replace-function.ts": + 'await db.$executeRawUnsafe("CREATE OR REPLACE FUNCTION app_reject_audit_log_mutation() RETURNS trigger AS $$ BEGIN RETURN OLD; END; $$ LANGUAGE plpgsql");' + } + }, + { + label: "raw SQL AuditLog alter append-only function outside trigger assertion", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-alter-function.ts": + 'await db.$executeRawUnsafe("ALTER FUNCTION app_reject_audit_log_mutation() OWNER TO app");' + } + }, + { + label: "raw SQL AuditLog trigger disable through intermediate table constant", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-disable-trigger-intermediate.ts": ` +const tableName = '"AuditLog"'; +const query = "ALTER TABLE " + tableName + " DISABLE TRIGGER ALL"; +await db.$executeRawUnsafe(query); +` + } + }, + { + label: "raw SQL AuditLog IF EXISTS trigger disable through dynamic table variable", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-disable-trigger-if-exists-dynamic-table.ts": ` +const tableName = process.env.AUDIT_TABLE ?? '"AuditLog"'; +const query = "ALTER TABLE IF EXISTS " + tableName + " DISABLE TRIGGER ALL"; +await db.$executeRawUnsafe(query); +` + } + }, + { + label: "raw SQL multi-table truncate through dynamic table variable", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-multi-truncate-dynamic-table.ts": ` +const tableName = process.env.AUDIT_TABLE ?? '"AuditLog"'; +const query = "TRUNCATE TABLE \\"Other\\", " + tableName; +await db.$executeRawUnsafe(query); +` + } + }, + { + label: "raw SQL AuditLog trigger disable through dynamic table variable", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-disable-trigger-dynamic-table.ts": ` +const tableName = process.env.AUDIT_TABLE ?? '"AuditLog"'; +const query = "ALTER TABLE " + tableName + " DISABLE TRIGGER ALL"; +await db.$executeRawUnsafe(query); +` + } + }, + { + label: "raw SQL drop trigger through dynamic trigger and table variables", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-drop-trigger-dynamic.ts": ` +const triggerName = process.env.TRIGGER_NAME ?? 'audit_append_only'; +const tableName = process.env.AUDIT_TABLE ?? '"AuditLog"'; +const query = "DROP TRIGGER " + triggerName + " ON " + tableName; +await db.$executeRawUnsafe(query); +` + } + }, + { + label: "raw SQL drop table through dynamic table variable", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-drop-table-dynamic.ts": ` +const tableName = process.env.AUDIT_TABLE ?? '"AuditLog"'; +const query = "DROP TABLE " + tableName; +await db.$executeRawUnsafe(query); +` + } + }, + { + label: "raw SQL alter table drop through dynamic table variable", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-alter-drop-dynamic.ts": ` +const tableName = process.env.AUDIT_TABLE ?? '"AuditLog"'; +const query = "ALTER TABLE " + tableName + " DROP CONSTRAINT foo"; +await db.$executeRawUnsafe(query); +` + } + }, + { + label: "Prisma.sql AuditLog delete through Prisma.raw intermediate table constant", + reason: "AUDIT_UPDATE_DELETE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-prisma-raw-intermediate.ts": ` +const tableName = '"AuditLog"'; +const query = Prisma.sql\`DELETE FROM \${Prisma.raw(tableName)} WHERE id = \${id}\`; +await db.$executeRaw(query); +` + } + }, + { + label: "Prisma.sql AuditLog delete through dynamic Prisma.raw table", + reason: "DYNAMIC_RAW_SQL_WRITE_FORBIDDEN", + files: { + "apps/api/src/modules/projects/audit-prisma-raw-dynamic-table.ts": ` +const tableName = process.env.AUDIT_TABLE ?? '"AuditLog"'; +const query = Prisma.sql\`DELETE FROM \${Prisma.raw(tableName)} WHERE id = \${id}\`; +await db.$executeRaw(query); +` + } + }, + { + label: "direct Job status write inside jobs module outside JobExecutionStore", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/jobs/bad.ts": + 'await db.job.update({ where: { id }, data: { status: "failed", attempts: { increment: 1 }, nextRetryAt: null } });' + } + }, + { + label: "direct Job status write inside jobs index outside JobExecutionStore class", + reason: "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", + files: { + "apps/api/src/modules/jobs/index.ts": ` +export class JobExecutionStore { + async ok(db) { + await db.job.update({ where: { id: "ok" }, data: { status: "running" } }); + } +} + +export class JobApiService { + async bad(db) { + await db.job.update({ where: { id: "bad" }, data: { status: "failed" } }); + } +} +` + } + }, + { + label: "guarded Prisma write outside state-transition", + reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/src/modules/projects/version.ts": "await db.gameVersion.update({ where: { id }, data: { status: 'active' } });" + } + }, + { + label: "guarded optional Prisma write outside state-transition", + reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/src/modules/projects/version-optional.ts": + 'await db.gameVersion?.update({ where: { id }, data: { status: "active" } });' + } + }, + { + label: "guarded delegate alias Prisma write outside state-transition", + reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/src/modules/projects/version-alias.ts": + 'const versions = db.gameVersion; await versions.update({ where: { id }, data: { status: "active" } });' + } + }, + { + label: "guarded Prisma bracket model write outside state-transition", + reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/src/modules/projects/version-bracket-model.ts": + 'await db["gameVersion"].update({ where: { id }, data: { status: "active" } });' + } + }, + { + label: "guarded Prisma bracket method write outside state-transition", + reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/src/modules/projects/review-bracket-method.ts": + 'await db.reviewRecord["update"]({ where: { id }, data: { status: "approved" } });' + } + }, + { + label: "guarded Prisma bracket model and method write outside state-transition", + reason: "GUARDED_PRISMA_WRITE_OUTSIDE_STATE_TRANSITION", + files: { + "apps/api/src/modules/projects/lifecycle-bracket-model-method.ts": + 'await db["lifecycleEvent"]["delete"]({ where: { eventId } });' + } + }, + { + label: "later-phase creation-agent messages path", + reason: "LATER_PHASE_SCOPE_LEAK", + files: { + "apps/api/src/modules/creation-agent/messages/index.ts": "export const harmless = true;" + } + }, + { + label: "later-phase creation-agent messages single-file path", + reason: "LATER_PHASE_SCOPE_LEAK", + files: { + "apps/api/src/modules/creation-agent/messages.ts": "export const harmless = true;" + } + }, + { + label: "later-phase compile-game-ir module path", + reason: "LATER_PHASE_SCOPE_LEAK", + files: { + "apps/api/src/modules/compile-game-ir/index.ts": "export const harmless = true;" + } + }, + { + label: "later-phase events batch route path", + reason: "LATER_PHASE_SCOPE_LEAK", + files: { + "apps/api/src/modules/events/batch/index.ts": "export const harmless = true;" + } + }, + { + label: "later-phase events batch route content without leading slash", + reason: "LATER_PHASE_SCOPE_LEAK", + files: { + "apps/api/src/modules/events/index.ts": 'export const route = "events/batch";' + } + }, + { + label: "later-phase events batch single-file path", + reason: "LATER_PHASE_SCOPE_LEAK", + files: { + "apps/api/src/modules/events/batch.ts": "export const harmless = true;" + } + }, + { + label: "later-phase AIGameDesignDraft filename path", + reason: "LATER_PHASE_SCOPE_LEAK", + files: { + "apps/api/src/modules/AIGameDesignDraft.ts": "export const harmless = true;" + } + }, + { + label: "later-phase GameIR app module path", + reason: "LATER_PHASE_SCOPE_LEAK", + files: { + "apps/api/src/modules/projects/game-ir.ts": "export const harmless = true;" + } + }, + { + label: "later-phase GameIR app implementation content", + reason: "LATER_PHASE_SCOPE_LEAK", + files: { + "apps/api/src/modules/projects/index.ts": "class GameIRService {}" + } + } + ]; + + for (const fixture of failingFixtures) { + await withFixture(fixture.files, async (root) => { + const violations = await findS1ScopeViolations(root); + assertHasReason(violations, fixture.reason, fixture.label); + }); + } + + await withFixture( + { + "apps/api/prisma/schema.prisma": ` +model MainCreationAgentSession { id String @id } +model AgentTask { id String @id } +model ReviewRecord { id String @id } +model LifecycleEvent { eventId String @id } +` + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertNoViolations(violations, "S1 anchor models"); + } + ); + + await withFixture( + { + "apps/api/src/prisma.schema.spec.ts": ` +const route = "creation-agent/messages"; +await db.job.update({ where: { id }, data: { status: "failed" } }); +` + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertHasReason(violations, "LATER_PHASE_SCOPE_LEAK", "historical prisma schema test later-phase leak"); + assertHasReason(violations, "JOB_STATUS_WRITE_OUTSIDE_EXECUTION_STORE", "historical prisma schema test Job write"); + } + ); + + await withFixture( + { + "apps/api/src/modules/audit/audit.spec.ts": ` +await expectPrismaRejectedInSavepoint( + tx, + () => tx.$executeRawUnsafe('UPDATE "AuditLog" SET "action" = $1 WHERE id = $2', action, id), + /AuditLog is append-only/ +); +` + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertNoViolations(violations, "AuditLog append-only raw SQL trigger assertion"); + } + ); + + await withFixture( + { + "apps/api/src/modules/projects/dynamic-select.ts": ` +const tableName = process.env.READ_TABLE ?? '"Job"'; +const query = "SELECT * FROM " + tableName + " WHERE id = $1"; +await db.$queryRawUnsafe(query, id); +` + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertNoViolations(violations, "dynamic raw SQL SELECT"); + } + ); + + await withFixture( + { + "apps/api/prisma/migrations/20260602000002_job_schema_ddl/migration.sql": ` +CREATE TABLE "Job" ("id" TEXT PRIMARY KEY, "status" TEXT NOT NULL); +CREATE INDEX "Job_status_idx" ON "Job" ("status"); +` + }, + async (root) => { + const violations = await findS1ScopeViolations(root); + assertNoViolations(violations, "Job schema DDL migration"); + } + ); +} + +try { + await runSelfTests(); + const violations = await findS1ScopeViolations(process.cwd()); + if (violations.length > 0) { + console.error("S1 scope check failed:"); + for (const violation of violations) { + console.error(`- ${formatViolation(violation)}`); + } + process.exitCode = 1; + } else { + console.log("S1 scope check passed."); + } +} catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; +} diff --git a/scripts/check-workspace-scripts.mjs b/scripts/check-workspace-scripts.mjs new file mode 100644 index 00000000..20b877fb --- /dev/null +++ b/scripts/check-workspace-scripts.mjs @@ -0,0 +1,95 @@ +import { readdir, readFile } from "node:fs/promises"; +import path from "node:path"; + +const rootDir = process.cwd(); +const requiredScripts = ["lint", "typecheck", "test", "build", "dev:smoke"]; + +// 只支持当前仓库声明的一层通配符,例如 apps/* 和 packages/*。 +function parseWorkspacePatterns(source) { + return source + .split("\n") + .map((line) => line.trim()) + .filter((line) => line.startsWith("- ")) + .map((line) => line.slice(2).trim().replace(/^["']|["']$/g, "")); +} + +async function pathExists(filePath) { + try { + await readFile(filePath, "utf8"); + return true; + } catch (error) { + if (error && error.code === "ENOENT") { + return false; + } + throw error; + } +} + +async function findWorkspaceManifests(patterns) { + const manifests = []; + + for (const pattern of patterns) { + if (!pattern.endsWith("/*")) { + throw new Error(`不支持的 workspace pattern: ${pattern}`); + } + + const baseDir = path.join(rootDir, pattern.slice(0, -2)); + try { + const entries = await readdir(baseDir, { withFileTypes: true }); + for (const entry of entries) { + if (!entry.isDirectory()) { + continue; + } + + const manifestPath = path.join(baseDir, entry.name, "package.json"); + if (await pathExists(manifestPath)) { + manifests.push(manifestPath); + } + } + } catch (error) { + if (error && error.code === "ENOENT") { + continue; + } + throw error; + } + } + + return manifests; +} + +async function readManifest(manifestPath) { + const raw = await readFile(manifestPath, "utf8"); + try { + return JSON.parse(raw); + } catch (error) { + throw new Error(`${path.relative(rootDir, manifestPath)} 不是有效 JSON: ${error.message}`); + } +} + +const workspaceConfigPath = path.join(rootDir, "pnpm-workspace.yaml"); +const workspaceConfig = await readFile(workspaceConfigPath, "utf8"); +const manifests = await findWorkspaceManifests(parseWorkspacePatterns(workspaceConfig)); +const failures = []; + +for (const manifestPath of manifests) { + const manifest = await readManifest(manifestPath); + const missingScripts = requiredScripts.filter((scriptName) => !manifest.scripts?.[scriptName]); + + if (missingScripts.length > 0) { + failures.push({ + packageName: manifest.name || path.relative(rootDir, path.dirname(manifestPath)), + manifestPath, + missingScripts + }); + } +} + +if (failures.length > 0) { + console.error("以下 workspace package 缺少必需脚本:"); + for (const failure of failures) { + console.error( + `- ${failure.packageName} (${path.relative(rootDir, failure.manifestPath)}): ${failure.missingScripts.join(", ")}` + ); + } + process.exitCode = 1; +} diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 00000000..73dedc12 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022"], + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "exactOptionalPropertyTypes": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true + } +}