diff --git a/.env.example b/.env.example index 794663c..088dc16 100644 --- a/.env.example +++ b/.env.example @@ -10,12 +10,57 @@ # Web NEXT_PUBLIC_API_URL=http://localhost:3001 +NEXT_PUBLIC_GOOGLE_AUTH_ENABLED=false # API NODE_ENV=development HOST=0.0.0.0 PORT=3001 CORS_ORIGIN=http://localhost:3000 +TRUST_PROXY=false + +AUTH_JWT_SECRET=replace-with-a-long-random-secret +AUTH_REFRESH_SECRET=replace-with-a-different-long-random-secret +AUTH_JWT_ISSUER=hivelore +AUTH_JWT_AUDIENCE=hivelore-web +AUTH_ACCESS_TOKEN_TTL_SECONDS=900 +AUTH_REFRESH_TOKEN_TTL_SECONDS=1209600 +AUTH_CHALLENGE_TTL_SECONDS=300 +AUTH_COOKIE_DOMAIN= +AUTH_COOKIE_SECURE=true +PROPOSAL_COMMENT_WRITE_RATE_LIMIT_CACHE=10000 +PROPOSAL_COMMENT_WRITE_RATE_LIMIT_MAX=5 +PROPOSAL_COMMENT_WRITE_RATE_LIMIT_WINDOW_SECONDS=60 +HIVE_RPC_URL=https://api.hive.blog +HIVE_AUTH_AUDIENCE=hivelore-local-api +HIVE_MAINNET_CHAIN_ID=beeab0de00000000000000000000000000000000000000000000000000000000 +HIVE_MAINNET_RPC_NODES=https://api.hive.blog +HIVE_MAINNET_HAF_URL=https://api.hive.blog/hafbe-api +HIVE_BROADCAST_MAX_ATTEMPTS=4 +HIVE_BROADCAST_INITIAL_DELAY_MS=500 +HIVE_BROADCAST_MAX_DELAY_MS=5000 +HIVE_BROADCAST_BACKOFF_MULTIPLIER=2 +HIVE_BROADCAST_JITTER_RATIO=0.2 +HIVE_BROADCAST_TIMEOUT_MS=10000 +HIVE_BROADCAST_TOTAL_DEADLINE_MS=90000 +HIVE_CONFIRMATION_POLL_INTERVAL_MS=3000 +HIVE_CONFIRMATION_TIMEOUT_MS=60000 +HIVE_NODE_MAX_CONSECUTIVE_FAILURES=1 +HIVE_NODE_COOLDOWN_MS=30000 + +# Local-only irreversible Hive mainnet smoke command inputs. +# Set these only in your local shell when running the smoke script; never commit real keys. +HIVE_SMOKE_ACCOUNT= + +GOOGLE_AUTH_ENABLED=false +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= +GOOGLE_REDIRECT_URI=http://localhost:3001/auth/google/callback + +GOOGLE_HIVE_PROVISIONING_ENABLED=false +HIVE_RC_DELEGATION_ENABLED=false +HIVE_RC_DELEGATOR_ACCOUNT= +HIVE_RC_DELEGATION_AMOUNT= # PostgreSQL application connection through the Supabase pooler. DATABASE_URL="postgresql://USER:PASSWORD@POOLER_HOST:6543/postgres?pgbouncer=true" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d0a4c0..807dcd5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,13 +12,28 @@ permissions: env: CI: true NEXT_PUBLIC_API_URL: http://localhost:3001 - DATABASE_URL: postgresql://USER:PASSWORD@POOLER_HOST:6543/postgres?pgbouncer=true - DIRECT_URL: postgresql://USER:PASSWORD@DIRECT_HOST:5432/postgres + DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/postgres + DIRECT_URL: postgresql://postgres:postgres@127.0.0.1:5432/postgres jobs: quality: name: Quality runs-on: ubuntu-latest + timeout-minutes: 20 + services: + postgres: + image: postgres:16 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U postgres -d postgres" + --health-interval 10s + --health-timeout 5s + --health-retries 5 steps: - name: Checkout @@ -33,9 +48,6 @@ jobs: - name: Install dependencies run: npm ci - - name: Check formatting - run: npm run format:check - - name: Format Prisma schema run: npm run db:format @@ -45,11 +57,37 @@ jobs: - name: Generate Prisma Client run: npm run db:generate - - name: Lint - run: npm run lint + - name: Check fresh PostgreSQL migrations + run: npm run db:migrate:check:fresh + env: + TEST_DATABASE_ADMIN_URL: postgresql://postgres:postgres@127.0.0.1:5432/postgres + + - name: Check PostgreSQL migration upgrade from develop + run: | + git fetch origin develop --depth=1 + mkdir -p /tmp/hivelore-develop + git archive origin/develop apps/api/prisma | tar -x -C /tmp/hivelore-develop + npm run db:migrate:check:upgrade + env: + TEST_DATABASE_ADMIN_URL: postgresql://postgres:postgres@127.0.0.1:5432/postgres + TEST_DATABASE_BASE_PRISMA_SCHEMA: /tmp/hivelore-develop/apps/api/prisma/schema.prisma - name: Type-check run: npm run typecheck + - name: Test + run: npm test + env: + NODE_ENV: test + AUTH_JWT_SECRET: test-only-jwt-secret-with-enough-entropy + AUTH_REFRESH_SECRET: test-only-refresh-secret-with-enough-entropy + TEST_DATABASE_ADMIN_URL: postgresql://postgres:postgres@127.0.0.1:5432/postgres + + - name: Lint + run: npm run lint + + - name: Check formatting + run: npm run format:check + - name: Build run: npm run build diff --git a/.gitignore b/.gitignore index 4155036..845cd4f 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ build/Release # Dependency directories node_modules/ jspm_packages/ +.worktrees/ # Snowpack dependency directory (https://snowpack.dev/) web_modules/ diff --git a/.prettierignore b/.prettierignore index 168b846..9acb5e5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,5 @@ node_modules +.worktrees .next dist coverage diff --git a/README.md b/README.md index 296e805..7917ff3 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,7 @@ Stores mutable application state optimized for querying. - Drafts - Proposals +- Proposal comments - AI reports - Lore graph - Search index @@ -190,6 +191,16 @@ Authentication flow: Private keys are never stored. Authentication is entirely non-custodial. +HiveLore supports Hive Keychain and HiveSigner through the same backend challenge-response flow. The API creates a short-lived, single-use, human-readable challenge containing the username, nonce, issued timestamp, expiration timestamp, configured audience, and a statement that signing does not authorize a Hive transaction or transfer. Users sign the exact challenge with posting authority. The backend verifies the signature against the account's current Hive posting authority from a trusted Hive RPC endpoint before creating or updating the local user projection. + +The current verifier supports a single posting public key whose configured key weight satisfies the account's posting threshold. Accounts requiring multiple posting signatures or delegated account authorities are not accepted by the login flow yet; that avoids falsely authenticating a key that cannot independently satisfy posting authority. + +Successful authentication issues a short-lived access JWT and a long-lived opaque refresh token. Refresh tokens are stored only as one-way HMAC hashes in PostgreSQL using a dedicated refresh-token secret, rotate on every successful refresh, and revoke the session family if a rotated token is reused. Browser refresh tokens are set in an `httpOnly` cookie and are not returned in JSON responses; access tokens are returned to the client for authenticated API requests. Authenticated API requests verify the access token session id against a non-revoked refresh session so logout invalidates already-issued access tokens. Logout is idempotent and revokes the submitted refresh session or session family when requested. + +HiveLore never requests, receives, logs, stores, or returns Hive posting, active, owner, or memo private keys. Login proves identity only. It does not grant the backend permission to publish content, vote, transfer funds, or perform any on-chain action for the user. + +Google authentication is an optional extension and is disabled by default. When disabled, Google routes return a not-enabled response and no Google environment variables are required. The schema includes Google identity-linking and provisioning state boundaries, but Google OAuth, automatic Hive account provisioning, and RC delegation are not part of the base MVP unless separately configured and implemented with a secure non-custodial key-delivery process. + --- # Governance @@ -233,6 +244,58 @@ Default MVP: These rules provide basic protection against Sybil attacks while keeping governance simple. +### Canon Voting MVP Rule + +Submitted contributions enter `VOTING` immediately with `votingStartedAt` set by the backend and +`votingEndsAt = votingStartedAt + 48 hours`. The voting service never accepts client-supplied +voter identity, role, tally, result, or authoritative timestamps. Authenticated world members with +`VOTE_ON_PROPOSAL` may cast one vote per proposal and may change that vote only before +`votingEndsAt`. + +Supported choices are `APPROVE`, `REJECT`, `NEEDS_REVISION`, and `ALTERNATE_TIMELINE`. +`totalVotes` counts all four choices. Approval arithmetic is exact integer basis points: +`approvalNumerator = APPROVE`, `approvalDenominator = all four choices`, and +`approvalPercentageBps = floor(APPROVE * 10000 / approvalDenominator)`, or `0` when the denominator +is zero. `NEEDS_REVISION` and `ALTERNATE_TIMELINE` count toward both participation and the approval +denominator. + +The MVP policy is centralized in `apps/api/src/lib/canon-voting-policy.ts`: + +- Minimum eligible internal votes: 5. +- Approval threshold: 7000 basis points, so exactly 70% passes. +- Voting window: 48 hours. +- A proposal can pass only after the full window has ended. +- Founder or author status never bypasses the rule. +- A major AI warning remains attached and visible; it does not automatically reject a proposal. + +If the approval rule does not pass after the window closes, the deterministic terminal outcome is +the plurality among `NEEDS_REVISION`, `ALTERNATE_TIMELINE`, and `REJECT`; ties resolve in that order. +If no failed-outcome choice has votes, the result is `REJECTED`. If the proposal's recorded base canon +version is stale at decision time, the outcome is `STALE_BASE_CONFLICT` and the proposal is surfaced +as needing revision instead of silently applying to newer canon. + +Finalization creates one immutable `ProposalDecision` snapshot with per-choice counts, threshold +version, content hash, AI-warning state, branch/conflict metadata, and a deterministic decision +payload hash. Passing governance sets the proposal to `APPROVED_FOR_PUBLICATION`; it does not make a +`LoreEntry` `PUBLISHED_CANON`. Published canon still requires a separately confirmed Hive lore +post/comment and indexed `HiveReference`. + +Approved decisions use a non-custodial Hive signing handoff. The API returns an unsigned posting +authority `custom_json` operation with HiveLore's stable custom JSON id (`hivelore`), schema version, +world ID, proposal ID, content hash, outcome, timestamps, tally, thresholds, AI-warning state, and +branch/base-canon references. The contributor signs and broadcasts through Hive Keychain or +HiveSigner; HiveLore never requests or stores private keys. + +When a client reports broadcast details, the backend retrieves the operation through the configured +HAF/Hive indexing abstraction and verifies confirmation, operation type, custom JSON id, posting +signer, world/proposal/decision IDs, frozen tally/payload hash, timestamps, and duplicate operation +state before linking the result to `HiveEvent` and `ProposalDecision` idempotently. + +Branching metadata keeps alternate continuations readable without deleting competing branches. +Alternate-timeline decisions are excluded from canon-only projections; canonizing one branch does not +remove other branches, which can later be revised, archived, merged, or retained under moderation +permissions. + ## Hive Voting Hive votes determine: @@ -297,6 +360,42 @@ REST API modules: - Profiles - Moderation +Implemented authentication endpoints: + +- `POST /auth/challenge`: accepts a Hive username and `keychain` or `hivesigner` provider, creates a five-minute challenge, and returns only the challenge ID, exact message, expiration, normalized Hive username, and provider. +- `POST /auth/verify`: accepts the challenge ID, username, provider, exact message, signature, and optional public key, verifies posting authority through Hive RPC, consumes the challenge, upserts the user projection, returns an access token, and sets the refresh cookie. +- `POST /auth/refresh`: validates the opaque refresh token from the `httpOnly` cookie or request body, checks trusted browser origins for cookie-based refreshes, rotates it, revokes the previous token, returns a new access token, and revokes the session family on reuse detection. +- `POST /auth/logout`: revokes the current refresh session or session family when requested and clears the refresh cookie. Repeated logout is safe. +- `GET /me`: requires a valid access JWT and returns the safe canonical Hive-linked user representation. + +Auth challenge, verification, and refresh endpoints use Fastify rate limiting backed by PostgreSQL buckets so limits are shared across API instances. Set `TRUST_PROXY=true` on deployments that run behind a trusted proxy or load balancer so client IPs are resolved from trusted forwarding headers. + +Google auth routes are not registered as a default login path. With `GOOGLE_AUTH_ENABLED=false`, `/auth/google/*` returns a not-enabled response. Enabling Google currently exposes the guarded boundary only; Google OAuth account linking and automatic Hive provisioning remain deferred until secure non-custodial account creation and key delivery are specified. + +Implemented world endpoints: + +- `POST /worlds`: requires authentication, creates a mutable off-chain World Seed and initial `WorldBibleVersion` in one transaction, and assigns the authenticated user an active `FOUNDER` membership. The route never accepts a client-supplied founder or role and does not publish to Hive. +- `GET /worlds`: browses discoverable worlds with pagination and basic title/description, genre, and tone filters. +- `GET /worlds/:worldId`: returns one world with its founder, seed, and current latest World Bible version. +- `GET /worlds/:worldId/hub`: returns the World Hub aggregate for the frontend, including world seed, current bible preview, simple canon/proposal stats, and latest canon lore entry summaries. +- `PATCH /worlds/:worldId`: requires `EDIT_INITIAL_CANON` world permission and updates mutable off-chain world title/description, seed, and latest initial bible content only. It does not create proposals, canonize content, or publish to Hive. + +Implemented contribution endpoints: + +- `POST /worlds/:worldId/contributions`: requires authentication and `CREATE_LORE_DRAFT` world permission, creates an author-owned structured contribution draft for lore or story content, and optionally links it to a lore entry in the same world. +- `GET /worlds/:worldId/contributions`: requires authentication and lists only the authenticated writer's contributions in the world with page/pageSize pagination and optional status/kind filters. +- `GET /worlds/:worldId/contributions/:contributionId`: returns an authenticated writer's own contribution draft or submitted contribution without exposing other writers' private drafts. +- `PATCH /worlds/:worldId/contributions/:contributionId`: requires `EDIT_OWN_DRAFT`, updates only mutable draft fields, and rejects submitted contributions. +- `DELETE /worlds/:worldId/contributions/:contributionId`: requires `EDIT_OWN_DRAFT`, deletes only draft contributions, and never deletes submitted proposals. +- `POST /worlds/:worldId/contributions/:contributionId/submit`: requires `SUBMIT_PROPOSAL`, atomically locks the draft, creates exactly one submitted proposal with an immutable `proposedContent` snapshot, and does not publish to Hive. + +Implemented proposal discussion endpoints: + +- `GET /worlds/:worldId/proposals/:proposalId/comments`: lists flat chronological off-chain proposal comments with cursor pagination. The proposal must belong to the route world. Deleted comments are returned as tombstones without the original body. +- `POST /worlds/:worldId/proposals/:proposalId/comments`: requires authentication and the existing `VOTE_ON_PROPOSAL` world permission, derives the author from the verified session, trims plain-text body content, enforces a 3,000-character maximum, and rate-limits comment writes to 5 per verified user per minute by default. + +Proposal comments are stored in PostgreSQL as mutable discussion records. They are not Hive comments, not immutable canon records, and never count as AppVote rows, approval totals, proposal outcomes, reputation, rewards, or canon status. Soft deletion preserves the discussion audit shape while normal API responses hide moderated comment bodies. Comment write rate limits use the existing PostgreSQL-backed Fastify rate-limit store in the API app, so limits are shared across API instances that use the same database. + --- # Reputation & Rewards @@ -458,11 +557,56 @@ DATABASE_URL="postgresql://USER:PASSWORD@POOLER_HOST:6543/postgres?pgbouncer=tru # Direct PostgreSQL connection used for Prisma migrations and administrative operations. DIRECT_URL="postgresql://USER:PASSWORD@DIRECT_HOST:5432/postgres" + +# Hive authentication and secure session settings. +AUTH_JWT_SECRET="replace-with-a-long-random-secret" +AUTH_REFRESH_SECRET="replace-with-a-different-long-random-secret" +AUTH_JWT_ISSUER="hivelore" +AUTH_JWT_AUDIENCE="hivelore-web" +AUTH_ACCESS_TOKEN_TTL_SECONDS=900 +AUTH_REFRESH_TOKEN_TTL_SECONDS=1209600 +AUTH_CHALLENGE_TTL_SECONDS=300 +AUTH_COOKIE_DOMAIN= +AUTH_COOKIE_SECURE=true +HIVE_AUTH_AUDIENCE="hivelore-local-api" +ERROR_TRACKING_ENABLED=false +ERROR_TRACKING_WEBHOOK_URL= + +# Hive integration defaults to public development endpoints. +HIVE_RPC_URL="https://api.hive.blog" +HAF_API_URL="https://api.hive.blog/hafbe-api" +HIVELORE_APP_ID="hivelore/0.1.0" +HIVE_MAINNET_CHAIN_ID="beeab0de00000000000000000000000000000000000000000000000000000000" +HIVE_MAINNET_RPC_NODES="https://api.hive.blog" +HIVE_MAINNET_HAF_URL="https://api.hive.blog/hafbe-api" +HIVE_BROADCAST_MAX_ATTEMPTS=4 +HIVE_BROADCAST_INITIAL_DELAY_MS=500 +HIVE_BROADCAST_MAX_DELAY_MS=5000 +HIVE_BROADCAST_BACKOFF_MULTIPLIER=2 +HIVE_BROADCAST_JITTER_RATIO=0.2 +HIVE_BROADCAST_TIMEOUT_MS=10000 +HIVE_BROADCAST_TOTAL_DEADLINE_MS=90000 +HIVE_CONFIRMATION_POLL_INTERVAL_MS=3000 +HIVE_CONFIRMATION_TIMEOUT_MS=60000 +HIVE_NODE_MAX_CONSECUTIVE_FAILURES=1 +HIVE_NODE_COOLDOWN_MS=30000 + +# Optional Google-to-Hive linking and onboarding. Disabled for the base MVP. +GOOGLE_AUTH_ENABLED=false +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= +GOOGLE_REDIRECT_URI= +GOOGLE_HIVE_PROVISIONING_ENABLED=false + +# Optional RC delegation. Disabled for the base MVP. +HIVE_RC_DELEGATION_ENABLED=false +HIVE_RC_DELEGATOR_ACCOUNT= +HIVE_RC_DELEGATION_AMOUNT= ``` `DATABASE_URL` is the pooled connection used by normal API queries. `DIRECT_URL` is the direct PostgreSQL connection Prisma uses for migrations and administrative operations. Supabase service-role keys are not required for Prisma's PostgreSQL connection. Hive private keys must never be stored. -Use separate credentials and databases for development and production. Do not reset a shared development database without team coordination. +Use separate credentials and databases for development and production. Any internet-facing API environment, including shared development hosts, must set long random `AUTH_JWT_SECRET` and `AUTH_REFRESH_SECRET` values and `AUTH_COOKIE_SECURE=true`. Deployments behind a trusted proxy or load balancer must set `TRUST_PROXY=true`. Do not reset a shared development database without team coordination. ### Supabase Setup @@ -525,6 +669,29 @@ Review generated SQL under `apps/api/prisma/migrations`, commit the schema and m Feature branches must include migration files. Resolve migration conflicts before merge. +### Baseline Migration History + +`20260718131500_init_hivelore_schema` is the authoritative Prisma baseline. A later historical migration, `20260718154842_init`, accidentally duplicated the same baseline SQL and caused fresh PostgreSQL databases to fail during `prisma migrate deploy` when the second migration tried to recreate enums, tables, indexes, and foreign keys that already existed. + +The duplicate migration directory is intentionally retained, but its SQL body is a no-op. This preserves the historical migration name while allowing a new developer, CI job, preview environment, or empty hosted database to run: + +```bash +npm run db:migrate:deploy +npm run db:generate +``` + +Existing databases that already recorded both baseline migrations do not need data changes before deploying this repository repair. Prisma may warn that `20260718154842_init` was modified after it was applied because the stored checksum reflects the old duplicate SQL. That warning is expected for those environments; do not reset or recreate the database to clear it. If an environment is blocked by a failed `20260718154842_init` row after the duplicate SQL already created the baseline objects, inspect `_prisma_migrations` and the actual schema first, then run `npx prisma migrate resolve --rolled-back 20260718154842_init --schema apps/api/prisma/schema.prisma` before `npm run db:migrate:deploy`. If an environment has only the first baseline recorded, the retained no-op second migration can be applied normally. + +CI validates the full migration history against a disposable PostgreSQL database with: + +```bash +TEST_DATABASE_ADMIN_URL=postgresql://postgres:postgres@127.0.0.1:5432/postgres npm run db:migrate:check:fresh +``` + +The check creates a uniquely named `hivelore_migrate_check_*` database, runs `prisma migrate deploy` twice, compares the deployed schema with `schema.prisma`, generates Prisma Client, runs the development seed, smoke-checks representative tables/enums/constraints/indexes, and drops only the generated disposable database. + +CI also validates the upgrade path from `develop` with `npm run db:migrate:check:upgrade`. That job deploys the base branch migration history into a disposable PostgreSQL database, applies the documented `20260718154842_init` recovery when needed, deploys this branch's repaired migrations, checks for schema drift, and drops the disposable database. + ### Seed Behavior The seed at `apps/api/prisma/seed.ts` is development-only and contains fictional Hive usernames, world content, lore, one lore relationship, one submitted proposal, and an advisory AI report. It does not seed real people, credentials, Hive private keys, real blockchain transactions, or financial payout projections. @@ -533,6 +700,73 @@ The seed at `apps/api/prisma/seed.ts` is development-only and contains fictional Hive is authoritative for on-chain publication, authorship, rewards, beneficiary metadata, and blockchain events. `HiveReference`, `HiveEvent`, `RewardRecord`, and `UserRewardSummary` are indexed or derived database projections. A local PostgreSQL flag or timestamp is never sufficient to prove canon; canon requires an approved publication that has been published to Hive and indexed by HiveLore. +All backend Hive access goes through `apps/api/src/lib/hive`. The module uses `@hiveio/wax` for transaction build, serialization, signing handoff, and broadcast; it exposes signer abstractions for Hive Keychain and HiveSigner flows without storing private keys. HAF reads use the configurable read-only `HAF_API_URL` client and are normalized before projection into PostgreSQL. The initial default is Hive's public HAF Block Explorer endpoint, using documented HAFBE paths such as `/last-synced-block`, `/block-search`, and `/accounts/{account}/operations/comments/{permlink}`; self-hosted HAF remains deferred. + +### Hive Network And Broadcast Reliability + +HiveLore is mainnet-only. It uses chain ID `beeab0de00000000000000000000000000000000000000000000000000000000`, address prefix `STM`, and the configured `HIVE_MAINNET_RPC_NODES`. The network config is built as one unit with chain ID, node list, HAF/indexer URL, address prefix, custom JSON ID, and transaction expiration policy. Empty node lists, malformed chain IDs, non-mainnet chain IDs, credential-bearing node URLs, and non-HTTPS production nodes fail startup validation. + +Backend-controlled broadcasts go through the typed reliability layer in `apps/api/src/lib/hive/broadcast-reliability.ts`. It broadcasts only already-signed transactions, never asks for private keys, and preserves the submitted transaction ID across retries. Transient RPC failures use bounded exponential backoff with jitter and node rotation; permanent transaction rejections such as invalid signatures, insufficient authority, malformed operations, expired transactions, and insufficient Resource Credits fail fast without rotating through every node. Ambiguous outcomes, including a timeout after a node may have accepted a transaction, enter confirmation polling before any retry and retry only the exact same signed transaction when still safe. + +An RPC broadcast acknowledgment is not confirmation. For the MVP, "confirmed" means included in a Hive block and located through HAF or a compatible indexing/read-back path; this is weaker than last-irreversible-block finality and is reported as block inclusion. Confirmation verifies the transaction ID, operation index when known, HiveLore operation type, `custom_json` ID, posting signer, world/proposal/decision IDs, and frozen payload hash before persistence. Client-supplied block numbers and timestamps are treated only as lookup hints; PostgreSQL state changes use chain/read-back data. Confirmation time is application time after verification, while blockchain timestamp comes from the block/indexer row. + +Successful confirmed broadcasts return a structured result containing the network, transaction ID, block number, operation indexes, blockchain timestamp, confirmation time, confirmation source, sanitized node URL when applicable, and attempt count. Timeouts return an unknown or delayed-confirmation state; they must be reconciled by retrying confirmation for the same transaction ID, not by creating a different transaction. + +### Hive Smoke Tests + +Mainnet smoke test: + +1. Build the harmless HiveLore `custom_json` operation with ID `hivelore_smoke`. +2. Use posting authority only: `required_auths` must be empty and `required_posting_auths` must contain the signing account. If active or owner authority is requested, treat it as a bug and stop. +3. Use this exact JSON payload, which contains no personal data or secrets: + +```json +{ + "app": "hivelore", + "type": "mainnet_smoke", + "version": 1, + "purpose": "broadcast_readback_verification" +} +``` + +4. Sign from the local process environment only. Never hardcode, print, persist, or commit a Hive private key. +5. Broadcast through the existing WAX client and reliability broadcaster, preserving multi-node RPC failover. +6. Confirm through `condenser_api.get_transaction`, verify transaction ID, signer, `custom_json` ID, posting authority, and payload, then read `block_num` from that transaction. +7. Call `condenser_api.get_block_header(block_num)` and use that header timestamp as the blockchain timestamp. Never use transaction expiration as the blockchain timestamp. +8. Print only the transaction ID, block number, block timestamp, RPC node used, and pass/fail verification summary after the irreversible broadcast. + +Run the real smoke test only after reviewing the account and permanence warning: + +```powershell +$env:HIVE_SMOKE_ACCOUNT = "" +$env:HIVE_SMOKE_POSTING_KEY = "" +npm run smoke:hive-mainnet +``` + +The command prompts for `BROADCAST HIVELORE SMOKE` immediately before broadcasting. Mainnet smoke tests must not be run without explicit approval of the account, exact operation, and expected permanence. + +### Standalone HAF Indexer + +The API workspace includes a resumable HAF sync skeleton. It reads HAF block-search pages, projects supported HiveLore operations into `HiveEvent`, and stores its durable resume point in `IndexerWatermark`. + +```bash +npm run indexer:run --workspace=@hivelore/api +``` + +Optional API environment variables: + +```env +INDEXER_NAME=hivelore-haf +INDEXER_START_BLOCK=1 +INDEXER_BATCH_SIZE=100 +INDEXER_MAX_BLOCKS_PER_RUN=1000 +INDEXER_MAX_READY_LAG_BLOCKS=1200 +``` + +Run `npm run db:generate` after pulling schema changes, then apply the committed Prisma migrations before running it against a real database. + +`GET /health` is the lightweight liveness endpoint. `GET /ready` verifies PostgreSQL connectivity and reports HAF indexer lag against `INDEXER_MAX_READY_LAG_BLOCKS`; it returns `503` when any dependency is degraded. API logs are structured JSON with an `x-request-id` request identifier, and `ERROR_TRACKING_ENABLED=true` posts unhandled error summaries to `ERROR_TRACKING_WEBHOOK_URL` without request headers or secret-bearing bodies. + ## Run Locally ```bash @@ -544,6 +778,7 @@ Local services: - Web: http://localhost:3000 - API: http://localhost:3001 - Health: http://localhost:3001/health +- Readiness: http://localhost:3001/ready Run one application at a time: @@ -640,7 +875,7 @@ hivelore/ Directory roles: - `apps/web` is the only frontend application. It is a Next.js App Router scaffold. -- `apps/api` is the only backend application. It is a Fastify TypeScript scaffold with `GET /health`. +- `apps/api` is the only backend application. It is a Fastify TypeScript API with liveness and readiness endpoints. - `apps/api/prisma` contains the canonical API Prisma schema, migrations, and development seed. - `packages` is reserved for shared workspace packages. `packages/config` is intentionally minimal until real shared configuration is needed. - `.github/workflows` contains CI checks for formatting, linting, type-checking, and builds. diff --git a/apps/api/.env.example b/apps/api/.env.example index e83cd8b..bc5cac4 100644 --- a/apps/api/.env.example +++ b/apps/api/.env.example @@ -10,6 +10,65 @@ NODE_ENV=development HOST=0.0.0.0 PORT=3001 CORS_ORIGIN=http://localhost:3000 +TRUST_PROXY=false + +AUTH_JWT_SECRET=replace-with-a-long-random-secret +AUTH_REFRESH_SECRET=replace-with-a-different-long-random-secret +AUTH_JWT_ISSUER=hivelore +AUTH_JWT_AUDIENCE=hivelore-web +AUTH_ACCESS_TOKEN_TTL_SECONDS=900 +AUTH_REFRESH_TOKEN_TTL_SECONDS=1209600 +AUTH_CHALLENGE_TTL_SECONDS=300 +AUTH_COOKIE_DOMAIN= +AUTH_COOKIE_SECURE=true +PROPOSAL_COMMENT_WRITE_RATE_LIMIT_CACHE=10000 +PROPOSAL_COMMENT_WRITE_RATE_LIMIT_MAX=5 +PROPOSAL_COMMENT_WRITE_RATE_LIMIT_WINDOW_SECONDS=60 +ERROR_TRACKING_ENABLED=false +ERROR_TRACKING_WEBHOOK_URL= + +# Hive integration is mainnet-only and defaults to public read/write endpoints for development. +# The chain ID is validated positively against Hive mainnet. +# Use comma-separated RPC node lists. Never include credentials in node URLs. +HIVE_RPC_URL=https://api.hive.blog +HIVE_AUTH_AUDIENCE=hivelore-local-api +HIVE_MAINNET_CHAIN_ID=beeab0de00000000000000000000000000000000000000000000000000000000 +HIVE_MAINNET_RPC_NODES=https://api.hive.blog +HIVE_MAINNET_HAF_URL=https://api.hive.blog/hafbe-api +HAF_API_URL=https://api.hive.blog/hafbe-api +HIVELORE_APP_ID=hivelore/0.1.0 +HIVE_BROADCAST_MAX_ATTEMPTS=4 +HIVE_BROADCAST_INITIAL_DELAY_MS=500 +HIVE_BROADCAST_MAX_DELAY_MS=5000 +HIVE_BROADCAST_BACKOFF_MULTIPLIER=2 +HIVE_BROADCAST_JITTER_RATIO=0.2 +HIVE_BROADCAST_TIMEOUT_MS=10000 +HIVE_BROADCAST_TOTAL_DEADLINE_MS=90000 +HIVE_CONFIRMATION_POLL_INTERVAL_MS=3000 +HIVE_CONFIRMATION_TIMEOUT_MS=60000 +HIVE_NODE_MAX_CONSECUTIVE_FAILURES=1 +HIVE_NODE_COOLDOWN_MS=30000 + +# Local-only irreversible Hive mainnet smoke command inputs. +# Set these only in your local shell when running the smoke script; never commit real keys. +HIVE_SMOKE_ACCOUNT= + +GOOGLE_AUTH_ENABLED=false +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= +GOOGLE_REDIRECT_URI=http://localhost:3001/auth/google/callback + +GOOGLE_HIVE_PROVISIONING_ENABLED=false +HIVE_RC_DELEGATION_ENABLED=false +HIVE_RC_DELEGATOR_ACCOUNT= +HIVE_RC_DELEGATION_AMOUNT= + +# Standalone HAF indexer controls. +INDEXER_NAME=hivelore-haf +INDEXER_START_BLOCK=1 +INDEXER_BATCH_SIZE=100 +INDEXER_MAX_BLOCKS_PER_RUN=1000 +INDEXER_MAX_READY_LAG_BLOCKS=1200 # PostgreSQL application connection through the Supabase pooler. DATABASE_URL="postgresql://USER:PASSWORD@POOLER_HOST:6543/postgres?pgbouncer=true" diff --git a/apps/api/package.json b/apps/api/package.json index 7673e38..755d79a 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -4,23 +4,36 @@ "private": true, "type": "module", "scripts": { + "predev": "prisma generate", "dev": "tsx watch src/server.ts", + "indexer:run": "tsx src/indexer/runner.ts", + "search:reindex": "tsx src/scripts/reindex-search.ts", + "smoke:hive-mainnet": "tsx src/scripts/hive-mainnet-smoke.ts", "prisma:generate": "prisma generate", "prisma:validate": "prisma validate", "prisma:format": "prisma format", + "prisma:migrate:check:fresh": "node scripts/check-fresh-prisma-migrations.mjs", + "prisma:migrate:check:upgrade": "node scripts/check-upgrade-prisma-migrations.mjs", "db:migrate:dev": "prisma migrate dev", "db:migrate:deploy": "prisma migrate deploy", "db:seed": "prisma db seed", "db:reset": "prisma migrate reset", "db:studio": "prisma studio", + "pretest": "prisma generate", + "test": "node scripts/run-tests.mjs", + "pretypecheck": "prisma generate", "lint": "eslint .", "typecheck": "tsc --noEmit", + "prebuild": "prisma generate", "build": "tsc", "start": "node dist/server.js", "clean": "node -e \"fs.rmSync('dist', { recursive: true, force: true })\"" }, "dependencies": { "@fastify/cors": "^11.0.1", + "@fastify/rate-limit": "^11.2.0", + "@hiveio/dhive": "^1.3.6", + "@hiveio/wax": "^2.0.2", "@prisma/adapter-pg": "^7.8.0", "@prisma/client": "^7.8.0", "@supabase/server": "^1.4.0", diff --git a/apps/api/prisma/migrations/20260718154842_init/migration.sql b/apps/api/prisma/migrations/20260718154842_init/migration.sql index 8b4a0f5..184a31c 100644 --- a/apps/api/prisma/migrations/20260718154842_init/migration.sql +++ b/apps/api/prisma/migrations/20260718154842_init/migration.sql @@ -1,529 +1,9 @@ --- CreateEnum -CREATE TYPE "LoreType" AS ENUM ('CHARACTER', 'LOCATION', 'FACTION', 'EVENT', 'ARTIFACT', 'HISTORY', 'RULE', 'OTHER'); - --- CreateEnum -CREATE TYPE "LoreStatus" AS ENUM ('DRAFT', 'SUBMITTED', 'APPROVED_FOR_PUBLICATION', 'PUBLISHED_CANON', 'ARCHIVED'); - --- CreateEnum -CREATE TYPE "ProposalType" AS ENUM ('ADD_LORE', 'UPDATE_LORE', 'UPDATE_WORLD_BIBLE'); - --- CreateEnum -CREATE TYPE "ProposalStatus" AS ENUM ('DRAFT', 'SUBMITTED', 'VOTING', 'APPROVED_FOR_PUBLICATION', 'REJECTED', 'PUBLISHED', 'WITHDRAWN'); - --- CreateEnum -CREATE TYPE "VoteChoice" AS ENUM ('APPROVE', 'REJECT', 'ABSTAIN'); - --- CreateEnum -CREATE TYPE "AIReportStatus" AS ENUM ('PENDING', 'COMPLETED', 'FAILED'); - --- CreateEnum -CREATE TYPE "ModerationStatus" AS ENUM ('OPEN', 'IN_REVIEW', 'RESOLVED', 'DISMISSED'); - --- CreateEnum -CREATE TYPE "ModerationTargetType" AS ENUM ('USER', 'WORLD', 'WORLD_BIBLE_VERSION', 'LORE_ENTRY', 'LORE_RELATIONSHIP', 'PROPOSAL', 'APP_VOTE', 'AI_REPORT', 'HIVE_REFERENCE', 'HIVE_EVENT', 'REWARD_RECORD'); - --- CreateEnum -CREATE TYPE "HiveEntityType" AS ENUM ('WORLD_SEED', 'WORLD_BIBLE_VERSION', 'LORE_ENTRY', 'STORY_CHAPTER', 'CANON_DECISION', 'LORE_RELATIONSHIP', 'METADATA'); - --- CreateEnum -CREATE TYPE "HiveEventType" AS ENUM ('POST', 'COMMENT', 'CUSTOM_JSON', 'VOTE', 'REWARD', 'BENEFICIARY', 'OTHER'); - --- CreateEnum -CREATE TYPE "RewardType" AS ENUM ('AUTHOR', 'CURATION', 'BENEFICIARY', 'OTHER'); - --- CreateEnum -CREATE TYPE "SearchEntityType" AS ENUM ('WORLD', 'WORLD_BIBLE_VERSION', 'LORE_ENTRY', 'PROPOSAL'); - --- CreateTable -CREATE TABLE "User" ( - "id" TEXT NOT NULL, - "hiveUsername" TEXT NOT NULL, - "normalizedHiveUsername" TEXT NOT NULL, - "displayName" TEXT, - "avatarUrl" TEXT, - "bio" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "User_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "World" ( - "id" TEXT NOT NULL, - "slug" TEXT NOT NULL, - "title" TEXT NOT NULL, - "description" TEXT NOT NULL, - "founderId" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "World_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "WorldBibleVersion" ( - "id" TEXT NOT NULL, - "worldId" TEXT NOT NULL, - "versionNumber" INTEGER NOT NULL, - "creatorId" TEXT NOT NULL, - "content" JSONB NOT NULL, - "changeSummary" TEXT, - "publishedAt" TIMESTAMP(3), - "hiveReferenceId" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "WorldBibleVersion_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "LoreEntry" ( - "id" TEXT NOT NULL, - "worldId" TEXT NOT NULL, - "authorId" TEXT NOT NULL, - "title" TEXT NOT NULL, - "slug" TEXT NOT NULL, - "loreType" "LoreType" NOT NULL, - "content" JSONB NOT NULL, - "status" "LoreStatus" NOT NULL DEFAULT 'DRAFT', - "publishedAt" TIMESTAMP(3), - "hiveReferenceId" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "LoreEntry_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "LoreRelationship" ( - "id" TEXT NOT NULL, - "worldId" TEXT NOT NULL, - "sourceId" TEXT NOT NULL, - "targetId" TEXT NOT NULL, - "relationType" TEXT NOT NULL, - "metadata" JSONB, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "LoreRelationship_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Proposal" ( - "id" TEXT NOT NULL, - "worldId" TEXT NOT NULL, - "authorId" TEXT NOT NULL, - "proposalType" "ProposalType" NOT NULL, - "status" "ProposalStatus" NOT NULL DEFAULT 'DRAFT', - "title" TEXT NOT NULL, - "summary" TEXT NOT NULL, - "proposedContent" JSONB NOT NULL, - "targetLoreEntryId" TEXT, - "resultingLoreEntryId" TEXT, - "resultingBibleVersionId" TEXT, - "submittedAt" TIMESTAMP(3), - "votingStartedAt" TIMESTAMP(3), - "approvedAt" TIMESTAMP(3), - "rejectedAt" TIMESTAMP(3), - "publishedAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "Proposal_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "AppVote" ( - "id" TEXT NOT NULL, - "proposalId" TEXT NOT NULL, - "voterId" TEXT NOT NULL, - "choice" "VoteChoice" NOT NULL, - "reputationScoreAtVote" DECIMAL(20,4), - "reputationSnapshotId" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "AppVote_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "AIReport" ( - "id" TEXT NOT NULL, - "proposalId" TEXT NOT NULL, - "provider" TEXT NOT NULL, - "model" TEXT NOT NULL, - "status" "AIReportStatus" NOT NULL DEFAULT 'PENDING', - "summary" TEXT, - "findings" JSONB, - "errorCode" TEXT, - "errorMessage" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "AIReport_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "ModerationReport" ( - "id" TEXT NOT NULL, - "reporterId" TEXT NOT NULL, - "reviewerId" TEXT, - "worldId" TEXT, - "proposalId" TEXT, - "targetType" "ModerationTargetType" NOT NULL, - "targetId" TEXT NOT NULL, - "reason" TEXT NOT NULL, - "details" TEXT, - "status" "ModerationStatus" NOT NULL DEFAULT 'OPEN', - "reviewedAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "ModerationReport_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "HiveReference" ( - "id" TEXT NOT NULL, - "entityType" "HiveEntityType" NOT NULL, - "entityId" TEXT NOT NULL, - "hiveAuthorUsername" TEXT NOT NULL, - "authorId" TEXT, - "permlink" TEXT NOT NULL, - "transactionId" TEXT, - "blockNumber" BIGINT, - "operationIndex" INTEGER, - "publicationMetadata" JSONB, - "publishedAt" TIMESTAMP(3) NOT NULL, - "indexedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "HiveReference_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "HiveEvent" ( - "id" TEXT NOT NULL, - "blockNumber" BIGINT NOT NULL, - "transactionId" TEXT NOT NULL, - "operationIndex" INTEGER NOT NULL, - "eventType" "HiveEventType" NOT NULL, - "blockchainTimestamp" TIMESTAMP(3) NOT NULL, - "payload" JSONB NOT NULL, - "processedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "HiveEvent_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "RewardRecord" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "hiveReferenceId" TEXT, - "rewardType" "RewardType" NOT NULL, - "assetSymbol" TEXT NOT NULL, - "amount" DECIMAL(38,18) NOT NULL, - "transactionId" TEXT NOT NULL, - "operationIndex" INTEGER NOT NULL, - "blockNumber" BIGINT NOT NULL, - "payoutAt" TIMESTAMP(3) NOT NULL, - "idempotencyKey" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "RewardRecord_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "UserRewardSummary" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "assetSymbol" TEXT NOT NULL, - "totalAmount" DECIMAL(38,18) NOT NULL, - "lastCalculatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "UserRewardSummary_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "UserReputationSnapshot" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "score" DECIMAL(20,4) NOT NULL, - "calculationVersion" TEXT NOT NULL, - "breakdown" JSONB NOT NULL, - "calculatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "UserReputationSnapshot_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "SearchIndex" ( - "id" TEXT NOT NULL, - "worldId" TEXT, - "entityType" "SearchEntityType" NOT NULL, - "entityId" TEXT NOT NULL, - "title" TEXT NOT NULL, - "searchableContent" TEXT NOT NULL, - "metadata" JSONB, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "SearchIndex_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "User_hiveUsername_key" ON "User"("hiveUsername"); - --- CreateIndex -CREATE UNIQUE INDEX "User_normalizedHiveUsername_key" ON "User"("normalizedHiveUsername"); - --- CreateIndex -CREATE INDEX "User_normalizedHiveUsername_idx" ON "User"("normalizedHiveUsername"); - --- CreateIndex -CREATE UNIQUE INDEX "World_slug_key" ON "World"("slug"); - --- CreateIndex -CREATE INDEX "World_founderId_idx" ON "World"("founderId"); - --- CreateIndex -CREATE INDEX "World_createdAt_idx" ON "World"("createdAt"); - --- CreateIndex -CREATE UNIQUE INDEX "WorldBibleVersion_hiveReferenceId_key" ON "WorldBibleVersion"("hiveReferenceId"); - --- CreateIndex -CREATE INDEX "WorldBibleVersion_worldId_versionNumber_idx" ON "WorldBibleVersion"("worldId", "versionNumber"); - --- CreateIndex -CREATE INDEX "WorldBibleVersion_creatorId_idx" ON "WorldBibleVersion"("creatorId"); - --- CreateIndex -CREATE UNIQUE INDEX "WorldBibleVersion_worldId_versionNumber_key" ON "WorldBibleVersion"("worldId", "versionNumber"); - --- CreateIndex -CREATE UNIQUE INDEX "LoreEntry_hiveReferenceId_key" ON "LoreEntry"("hiveReferenceId"); - --- CreateIndex -CREATE INDEX "LoreEntry_worldId_status_idx" ON "LoreEntry"("worldId", "status"); - --- CreateIndex -CREATE INDEX "LoreEntry_worldId_loreType_idx" ON "LoreEntry"("worldId", "loreType"); - --- CreateIndex -CREATE INDEX "LoreEntry_authorId_idx" ON "LoreEntry"("authorId"); - --- CreateIndex -CREATE UNIQUE INDEX "LoreEntry_worldId_slug_key" ON "LoreEntry"("worldId", "slug"); - --- CreateIndex -CREATE INDEX "LoreRelationship_worldId_idx" ON "LoreRelationship"("worldId"); - --- CreateIndex -CREATE INDEX "LoreRelationship_sourceId_idx" ON "LoreRelationship"("sourceId"); - --- CreateIndex -CREATE INDEX "LoreRelationship_targetId_idx" ON "LoreRelationship"("targetId"); - --- CreateIndex -CREATE UNIQUE INDEX "LoreRelationship_worldId_sourceId_targetId_relationType_key" ON "LoreRelationship"("worldId", "sourceId", "targetId", "relationType"); - --- CreateIndex -CREATE UNIQUE INDEX "Proposal_resultingBibleVersionId_key" ON "Proposal"("resultingBibleVersionId"); - --- CreateIndex -CREATE INDEX "Proposal_worldId_status_idx" ON "Proposal"("worldId", "status"); - --- CreateIndex -CREATE INDEX "Proposal_authorId_idx" ON "Proposal"("authorId"); - --- CreateIndex -CREATE INDEX "Proposal_targetLoreEntryId_idx" ON "Proposal"("targetLoreEntryId"); - --- CreateIndex -CREATE INDEX "AppVote_proposalId_idx" ON "AppVote"("proposalId"); - --- CreateIndex -CREATE INDEX "AppVote_voterId_idx" ON "AppVote"("voterId"); - --- CreateIndex -CREATE UNIQUE INDEX "AppVote_proposalId_voterId_key" ON "AppVote"("proposalId", "voterId"); - --- CreateIndex -CREATE INDEX "AIReport_proposalId_idx" ON "AIReport"("proposalId"); - --- CreateIndex -CREATE INDEX "AIReport_status_idx" ON "AIReport"("status"); - --- CreateIndex -CREATE INDEX "ModerationReport_reporterId_idx" ON "ModerationReport"("reporterId"); - --- CreateIndex -CREATE INDEX "ModerationReport_reviewerId_idx" ON "ModerationReport"("reviewerId"); - --- CreateIndex -CREATE INDEX "ModerationReport_worldId_status_idx" ON "ModerationReport"("worldId", "status"); - --- CreateIndex -CREATE INDEX "ModerationReport_proposalId_idx" ON "ModerationReport"("proposalId"); - --- CreateIndex -CREATE INDEX "ModerationReport_targetType_targetId_idx" ON "ModerationReport"("targetType", "targetId"); - --- CreateIndex -CREATE INDEX "HiveReference_authorId_idx" ON "HiveReference"("authorId"); - --- CreateIndex -CREATE INDEX "HiveReference_blockNumber_idx" ON "HiveReference"("blockNumber"); - --- CreateIndex -CREATE INDEX "HiveReference_publishedAt_idx" ON "HiveReference"("publishedAt"); - --- CreateIndex -CREATE UNIQUE INDEX "HiveReference_entityType_entityId_key" ON "HiveReference"("entityType", "entityId"); - --- CreateIndex -CREATE UNIQUE INDEX "HiveReference_hiveAuthorUsername_permlink_key" ON "HiveReference"("hiveAuthorUsername", "permlink"); - --- CreateIndex -CREATE UNIQUE INDEX "HiveReference_transactionId_operationIndex_key" ON "HiveReference"("transactionId", "operationIndex"); - --- CreateIndex -CREATE INDEX "HiveEvent_blockNumber_operationIndex_idx" ON "HiveEvent"("blockNumber", "operationIndex"); - --- CreateIndex -CREATE INDEX "HiveEvent_eventType_idx" ON "HiveEvent"("eventType"); - --- CreateIndex -CREATE INDEX "HiveEvent_blockchainTimestamp_idx" ON "HiveEvent"("blockchainTimestamp"); - --- CreateIndex -CREATE UNIQUE INDEX "HiveEvent_transactionId_operationIndex_key" ON "HiveEvent"("transactionId", "operationIndex"); - --- CreateIndex -CREATE UNIQUE INDEX "RewardRecord_idempotencyKey_key" ON "RewardRecord"("idempotencyKey"); - --- CreateIndex -CREATE INDEX "RewardRecord_userId_payoutAt_idx" ON "RewardRecord"("userId", "payoutAt"); - --- CreateIndex -CREATE INDEX "RewardRecord_hiveReferenceId_idx" ON "RewardRecord"("hiveReferenceId"); - --- CreateIndex -CREATE INDEX "RewardRecord_blockNumber_idx" ON "RewardRecord"("blockNumber"); - --- CreateIndex -CREATE INDEX "RewardRecord_transactionId_operationIndex_idx" ON "RewardRecord"("transactionId", "operationIndex"); - --- CreateIndex -CREATE INDEX "UserRewardSummary_assetSymbol_idx" ON "UserRewardSummary"("assetSymbol"); - --- CreateIndex -CREATE UNIQUE INDEX "UserRewardSummary_userId_assetSymbol_key" ON "UserRewardSummary"("userId", "assetSymbol"); - --- CreateIndex -CREATE INDEX "UserReputationSnapshot_userId_calculatedAt_idx" ON "UserReputationSnapshot"("userId", "calculatedAt"); - --- CreateIndex -CREATE INDEX "UserReputationSnapshot_calculationVersion_idx" ON "UserReputationSnapshot"("calculationVersion"); - --- CreateIndex -CREATE INDEX "SearchIndex_worldId_entityType_idx" ON "SearchIndex"("worldId", "entityType"); - --- CreateIndex -CREATE UNIQUE INDEX "SearchIndex_entityType_entityId_key" ON "SearchIndex"("entityType", "entityId"); - --- AddForeignKey -ALTER TABLE "World" ADD CONSTRAINT "World_founderId_fkey" FOREIGN KEY ("founderId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "WorldBibleVersion" ADD CONSTRAINT "WorldBibleVersion_worldId_fkey" FOREIGN KEY ("worldId") REFERENCES "World"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "WorldBibleVersion" ADD CONSTRAINT "WorldBibleVersion_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "WorldBibleVersion" ADD CONSTRAINT "WorldBibleVersion_hiveReferenceId_fkey" FOREIGN KEY ("hiveReferenceId") REFERENCES "HiveReference"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LoreEntry" ADD CONSTRAINT "LoreEntry_worldId_fkey" FOREIGN KEY ("worldId") REFERENCES "World"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LoreEntry" ADD CONSTRAINT "LoreEntry_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LoreEntry" ADD CONSTRAINT "LoreEntry_hiveReferenceId_fkey" FOREIGN KEY ("hiveReferenceId") REFERENCES "HiveReference"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LoreRelationship" ADD CONSTRAINT "LoreRelationship_worldId_fkey" FOREIGN KEY ("worldId") REFERENCES "World"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LoreRelationship" ADD CONSTRAINT "LoreRelationship_sourceId_fkey" FOREIGN KEY ("sourceId") REFERENCES "LoreEntry"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LoreRelationship" ADD CONSTRAINT "LoreRelationship_targetId_fkey" FOREIGN KEY ("targetId") REFERENCES "LoreEntry"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Proposal" ADD CONSTRAINT "Proposal_worldId_fkey" FOREIGN KEY ("worldId") REFERENCES "World"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Proposal" ADD CONSTRAINT "Proposal_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Proposal" ADD CONSTRAINT "Proposal_targetLoreEntryId_fkey" FOREIGN KEY ("targetLoreEntryId") REFERENCES "LoreEntry"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Proposal" ADD CONSTRAINT "Proposal_resultingLoreEntryId_fkey" FOREIGN KEY ("resultingLoreEntryId") REFERENCES "LoreEntry"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Proposal" ADD CONSTRAINT "Proposal_resultingBibleVersionId_fkey" FOREIGN KEY ("resultingBibleVersionId") REFERENCES "WorldBibleVersion"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "AppVote" ADD CONSTRAINT "AppVote_proposalId_fkey" FOREIGN KEY ("proposalId") REFERENCES "Proposal"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "AppVote" ADD CONSTRAINT "AppVote_voterId_fkey" FOREIGN KEY ("voterId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "AppVote" ADD CONSTRAINT "AppVote_reputationSnapshotId_fkey" FOREIGN KEY ("reputationSnapshotId") REFERENCES "UserReputationSnapshot"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "AIReport" ADD CONSTRAINT "AIReport_proposalId_fkey" FOREIGN KEY ("proposalId") REFERENCES "Proposal"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "ModerationReport" ADD CONSTRAINT "ModerationReport_reporterId_fkey" FOREIGN KEY ("reporterId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "ModerationReport" ADD CONSTRAINT "ModerationReport_reviewerId_fkey" FOREIGN KEY ("reviewerId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "ModerationReport" ADD CONSTRAINT "ModerationReport_worldId_fkey" FOREIGN KEY ("worldId") REFERENCES "World"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "ModerationReport" ADD CONSTRAINT "ModerationReport_proposalId_fkey" FOREIGN KEY ("proposalId") REFERENCES "Proposal"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "HiveReference" ADD CONSTRAINT "HiveReference_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "RewardRecord" ADD CONSTRAINT "RewardRecord_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "RewardRecord" ADD CONSTRAINT "RewardRecord_hiveReferenceId_fkey" FOREIGN KEY ("hiveReferenceId") REFERENCES "HiveReference"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "UserRewardSummary" ADD CONSTRAINT "UserRewardSummary_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "UserReputationSnapshot" ADD CONSTRAINT "UserReputationSnapshot_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "SearchIndex" ADD CONSTRAINT "SearchIndex_worldId_fkey" FOREIGN KEY ("worldId") REFERENCES "World"("id") ON DELETE CASCADE ON UPDATE CASCADE; +-- This migration originally duplicated the full baseline created by +-- 20260718131500_init_hivelore_schema. Re-running those CREATE TYPE, table, +-- index, and foreign-key statements breaks fresh PostgreSQL deployments because +-- the authoritative baseline has already created the same schema objects. +-- +-- Keep this migration directory so databases that have recorded the historical +-- migration name do not see a deleted migration. Its body is intentionally a +-- no-op for fresh databases and for environments that only applied the earlier +-- baseline. diff --git a/apps/api/prisma/migrations/20260725120000_add_world_memberships_and_audit_logs/migration.sql b/apps/api/prisma/migrations/20260725120000_add_world_memberships_and_audit_logs/migration.sql new file mode 100644 index 0000000..58c374a --- /dev/null +++ b/apps/api/prisma/migrations/20260725120000_add_world_memberships_and_audit_logs/migration.sql @@ -0,0 +1,167 @@ +-- CreateEnum +CREATE TYPE "PlatformRole" AS ENUM ('USER', 'ADMIN'); + +-- CreateEnum +CREATE TYPE "WorldRole" AS ENUM ('READER', 'CONTRIBUTOR', 'FOUNDER', 'CURATOR'); + +-- CreateEnum +CREATE TYPE "WorldAuditAction" AS ENUM ('ROLE_ASSIGNED', 'ROLE_CHANGED', 'ROLE_REMOVED', 'MODERATION_ACTION', 'CANON_STATUS_EXECUTED', 'AI_WARNING_RESOLVED'); + +-- CreateTable +ALTER TABLE "User" ADD COLUMN "platformRole" "PlatformRole" NOT NULL DEFAULT 'USER'; + +-- CreateTable +CREATE TABLE "WorldMembership" ( + "id" TEXT NOT NULL, + "worldId" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "role" "WorldRole" NOT NULL, + "grantedById" TEXT, + "grantedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "revokedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "WorldMembership_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "WorldAuditLog" ( + "id" TEXT NOT NULL, + "worldId" TEXT NOT NULL, + "actorId" TEXT, + "action" "WorldAuditAction" NOT NULL, + "targetType" TEXT NOT NULL, + "targetId" TEXT NOT NULL, + "metadata" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "WorldAuditLog_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "User_platformRole_idx" ON "User"("platformRole"); + +-- CreateIndex +CREATE INDEX "WorldMembership_worldId_role_idx" ON "WorldMembership"("worldId", "role"); + +-- CreateIndex +CREATE INDEX "WorldMembership_userId_role_idx" ON "WorldMembership"("userId", "role"); + +-- CreateIndex +CREATE INDEX "WorldMembership_grantedById_idx" ON "WorldMembership"("grantedById"); + +-- CreateIndex +CREATE INDEX "WorldMembership_revokedAt_idx" ON "WorldMembership"("revokedAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "WorldMembership_worldId_userId_key" ON "WorldMembership"("worldId", "userId"); + +-- CreateIndex +CREATE INDEX "WorldAuditLog_worldId_createdAt_idx" ON "WorldAuditLog"("worldId", "createdAt"); + +-- CreateIndex +CREATE INDEX "WorldAuditLog_actorId_createdAt_idx" ON "WorldAuditLog"("actorId", "createdAt"); + +-- CreateIndex +CREATE INDEX "WorldAuditLog_worldId_action_createdAt_idx" ON "WorldAuditLog"("worldId", "action", "createdAt"); + +-- CreateIndex +CREATE INDEX "WorldAuditLog_targetType_targetId_idx" ON "WorldAuditLog"("targetType", "targetId"); + +-- AddForeignKey +ALTER TABLE "WorldMembership" ADD CONSTRAINT "WorldMembership_worldId_fkey" FOREIGN KEY ("worldId") REFERENCES "World"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WorldMembership" ADD CONSTRAINT "WorldMembership_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WorldMembership" ADD CONSTRAINT "WorldMembership_grantedById_fkey" FOREIGN KEY ("grantedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WorldAuditLog" ADD CONSTRAINT "WorldAuditLog_worldId_fkey" FOREIGN KEY ("worldId") REFERENCES "World"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WorldAuditLog" ADD CONSTRAINT "WorldAuditLog_actorId_fkey" FOREIGN KEY ("actorId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- Backfill active FOUNDER memberships for worlds that existed before world memberships. +-- Ambiguous authorization state is rejected instead of silently changing roles or reactivating revoked memberships. +DO $$ +DECLARE + affected_worlds TEXT; +BEGIN + SELECT string_agg(format('worldId=%s founderId=%s', w."id", COALESCE(w."founderId", '')), E'\n') + INTO affected_worlds + FROM "World" w + LEFT JOIN "User" u ON u."id" = w."founderId" + WHERE u."id" IS NULL; + + IF affected_worlds IS NOT NULL THEN + RAISE EXCEPTION 'Cannot backfill founder memberships: one or more worlds have no valid founder user.' + USING DETAIL = affected_worlds, + HINT = 'Restore the missing founder user or assign a valid World.founderId before applying this migration.'; + END IF; + + SELECT string_agg( + format('worldId=%s founderId=%s membershipId=%s role=%s', w."id", w."founderId", wm."id", wm."role"), + E'\n' + ) + INTO affected_worlds + FROM "World" w + JOIN "WorldMembership" wm + ON wm."worldId" = w."id" + AND wm."userId" = w."founderId" + WHERE wm."revokedAt" IS NULL + AND wm."role" <> 'FOUNDER'; + + IF affected_worlds IS NOT NULL THEN + RAISE EXCEPTION 'Cannot backfill founder memberships: one or more founders already have a different active world role.' + USING DETAIL = affected_worlds, + HINT = 'Review each active membership and decide whether the founder should be promoted to FOUNDER manually.'; + END IF; + + SELECT string_agg( + format('worldId=%s founderId=%s membershipId=%s role=%s revokedAt=%s', w."id", w."founderId", wm."id", wm."role", wm."revokedAt"), + E'\n' + ) + INTO affected_worlds + FROM "World" w + JOIN "WorldMembership" wm + ON wm."worldId" = w."id" + AND wm."userId" = w."founderId" + WHERE wm."revokedAt" IS NOT NULL; + + IF affected_worlds IS NOT NULL THEN + RAISE EXCEPTION 'Cannot backfill founder memberships: one or more founder memberships are revoked.' + USING DETAIL = affected_worlds, + HINT = 'Review revoked founder memberships manually; this migration will not reactivate them.'; + END IF; + + INSERT INTO "WorldMembership" ( + "id", + "worldId", + "userId", + "role", + "grantedById", + "grantedAt", + "createdAt", + "updatedAt" + ) + SELECT + gen_random_uuid()::text, + w."id", + w."founderId", + 'FOUNDER', + w."founderId", + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP, + CURRENT_TIMESTAMP + FROM "World" w + WHERE NOT EXISTS ( + SELECT 1 + FROM "WorldMembership" wm + WHERE wm."worldId" = w."id" + AND wm."userId" = w."founderId" + ) + ON CONFLICT ("worldId", "userId") DO NOTHING; +END $$; diff --git a/apps/api/prisma/migrations/20260730120000_add_indexer_watermark/migration.sql b/apps/api/prisma/migrations/20260730120000_add_indexer_watermark/migration.sql new file mode 100644 index 0000000..7f74d6e --- /dev/null +++ b/apps/api/prisma/migrations/20260730120000_add_indexer_watermark/migration.sql @@ -0,0 +1,15 @@ +-- CreateTable +CREATE TABLE "IndexerWatermark" ( + "name" TEXT NOT NULL, + "lastProcessedBlock" BIGINT NOT NULL DEFAULT 0, + "lastProcessedOperationIndex" INTEGER NOT NULL DEFAULT -1, + "lastRunStartedAt" TIMESTAMP(3), + "lastRunFinishedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "IndexerWatermark_pkey" PRIMARY KEY ("name") +); + +-- CreateIndex +CREATE INDEX "IndexerWatermark_lastProcessedBlock_lastProcessedOperationIndex_idx" ON "IndexerWatermark"("lastProcessedBlock", "lastProcessedOperationIndex"); diff --git a/apps/api/prisma/migrations/20260801193000_add_authentication_sessions/migration.sql b/apps/api/prisma/migrations/20260801193000_add_authentication_sessions/migration.sql new file mode 100644 index 0000000..29be00f --- /dev/null +++ b/apps/api/prisma/migrations/20260801193000_add_authentication_sessions/migration.sql @@ -0,0 +1,175 @@ +-- CreateEnum +CREATE TYPE "AuthProvider" AS ENUM ('KEYCHAIN', 'HIVESIGNER'); + +-- CreateEnum +CREATE TYPE "ExternalIdentityProvider" AS ENUM ('GOOGLE'); + +-- CreateEnum +CREATE TYPE "HiveProvisioningStatus" AS ENUM ('PENDING', 'SUCCEEDED', 'FAILED', 'NOT_CONFIGURED'); + +-- CreateEnum +CREATE TYPE "RcDelegationStatus" AS ENUM ('PENDING', 'SUCCEEDED', 'FAILED', 'NOT_CONFIGURED'); + +-- CreateTable +CREATE TABLE "AuthChallenge" ( + "id" TEXT NOT NULL, + "userId" TEXT, + "normalizedHiveUsername" TEXT NOT NULL, + "provider" "AuthProvider" NOT NULL, + "intent" TEXT NOT NULL DEFAULT 'authentication', + "challengeHash" TEXT NOT NULL, + "nonceHash" TEXT NOT NULL, + "issuedAt" TIMESTAMP(3) NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "consumedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AuthChallenge_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "RefreshSession" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "sessionFamilyId" TEXT NOT NULL, + "refreshTokenHash" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "expiresAt" TIMESTAMP(3) NOT NULL, + "rotatedAt" TIMESTAMP(3), + "revokedAt" TIMESTAMP(3), + "replacedById" TEXT, + "lastUsedAt" TIMESTAMP(3), + "userAgent" TEXT, + "ipAddress" TEXT, + + CONSTRAINT "RefreshSession_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ExternalIdentityLink" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "provider" "ExternalIdentityProvider" NOT NULL, + "providerSubject" TEXT NOT NULL, + "verifiedEmail" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "ExternalIdentityLink_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "HiveProvisioningRequest" ( + "id" TEXT NOT NULL, + "userId" TEXT, + "externalIdentityLinkId" TEXT, + "requestedHiveUsername" TEXT NOT NULL, + "status" "HiveProvisioningStatus" NOT NULL DEFAULT 'NOT_CONFIGURED', + "failureReason" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "HiveProvisioningRequest_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "RcDelegation" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "hiveUsername" TEXT NOT NULL, + "delegatorAccount" TEXT NOT NULL, + "amount" TEXT NOT NULL, + "status" "RcDelegationStatus" NOT NULL DEFAULT 'NOT_CONFIGURED', + "transactionId" TEXT, + "operationIndex" INTEGER, + "idempotencyKey" TEXT NOT NULL, + "failureReason" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "RcDelegation_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "AuthChallenge_challengeHash_key" ON "AuthChallenge"("challengeHash"); + +-- CreateIndex +CREATE INDEX "AuthChallenge_normalizedHiveUsername_provider_idx" ON "AuthChallenge"("normalizedHiveUsername", "provider"); + +-- CreateIndex +CREATE INDEX "AuthChallenge_expiresAt_idx" ON "AuthChallenge"("expiresAt"); + +-- CreateIndex +CREATE INDEX "AuthChallenge_consumedAt_idx" ON "AuthChallenge"("consumedAt"); + +-- CreateIndex +CREATE INDEX "AuthChallenge_userId_idx" ON "AuthChallenge"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "RefreshSession_refreshTokenHash_key" ON "RefreshSession"("refreshTokenHash"); + +-- CreateIndex +CREATE UNIQUE INDEX "RefreshSession_replacedById_key" ON "RefreshSession"("replacedById"); + +-- CreateIndex +CREATE INDEX "RefreshSession_userId_idx" ON "RefreshSession"("userId"); + +-- CreateIndex +CREATE INDEX "RefreshSession_sessionFamilyId_idx" ON "RefreshSession"("sessionFamilyId"); + +-- CreateIndex +CREATE INDEX "RefreshSession_expiresAt_idx" ON "RefreshSession"("expiresAt"); + +-- CreateIndex +CREATE INDEX "RefreshSession_revokedAt_idx" ON "RefreshSession"("revokedAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "ExternalIdentityLink_provider_providerSubject_key" ON "ExternalIdentityLink"("provider", "providerSubject"); + +-- CreateIndex +CREATE UNIQUE INDEX "ExternalIdentityLink_userId_provider_key" ON "ExternalIdentityLink"("userId", "provider"); + +-- CreateIndex +CREATE INDEX "ExternalIdentityLink_userId_idx" ON "ExternalIdentityLink"("userId"); + +-- CreateIndex +CREATE INDEX "HiveProvisioningRequest_userId_idx" ON "HiveProvisioningRequest"("userId"); + +-- CreateIndex +CREATE INDEX "HiveProvisioningRequest_externalIdentityLinkId_idx" ON "HiveProvisioningRequest"("externalIdentityLinkId"); + +-- CreateIndex +CREATE INDEX "HiveProvisioningRequest_status_idx" ON "HiveProvisioningRequest"("status"); + +-- CreateIndex +CREATE UNIQUE INDEX "RcDelegation_idempotencyKey_key" ON "RcDelegation"("idempotencyKey"); + +-- CreateIndex +CREATE INDEX "RcDelegation_userId_idx" ON "RcDelegation"("userId"); + +-- CreateIndex +CREATE INDEX "RcDelegation_hiveUsername_idx" ON "RcDelegation"("hiveUsername"); + +-- CreateIndex +CREATE INDEX "RcDelegation_status_idx" ON "RcDelegation"("status"); + +-- AddForeignKey +ALTER TABLE "AuthChallenge" ADD CONSTRAINT "AuthChallenge_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "RefreshSession" ADD CONSTRAINT "RefreshSession_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "RefreshSession" ADD CONSTRAINT "RefreshSession_replacedById_fkey" FOREIGN KEY ("replacedById") REFERENCES "RefreshSession"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ExternalIdentityLink" ADD CONSTRAINT "ExternalIdentityLink_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "HiveProvisioningRequest" ADD CONSTRAINT "HiveProvisioningRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "HiveProvisioningRequest" ADD CONSTRAINT "HiveProvisioningRequest_externalIdentityLinkId_fkey" FOREIGN KEY ("externalIdentityLinkId") REFERENCES "ExternalIdentityLink"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "RcDelegation" ADD CONSTRAINT "RcDelegation_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/api/prisma/migrations/20260805123000_add_world_seed/migration.sql b/apps/api/prisma/migrations/20260805123000_add_world_seed/migration.sql new file mode 100644 index 0000000..d69a67b --- /dev/null +++ b/apps/api/prisma/migrations/20260805123000_add_world_seed/migration.sql @@ -0,0 +1,22 @@ +CREATE TABLE "WorldSeed" ( + "id" TEXT NOT NULL, + "worldId" TEXT NOT NULL, + "premise" TEXT NOT NULL, + "genre" TEXT NOT NULL, + "tone" TEXT NOT NULL, + "mainConflict" TEXT NOT NULL, + "startingLocation" TEXT, + "firstCharacters" JSONB, + "firstFactions" JSONB, + "firstHistoricalEvent" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "WorldSeed_pkey" PRIMARY KEY ("id") +); + +CREATE UNIQUE INDEX "WorldSeed_worldId_key" ON "WorldSeed"("worldId"); +CREATE INDEX "WorldSeed_genre_idx" ON "WorldSeed"("genre"); +CREATE INDEX "WorldSeed_tone_idx" ON "WorldSeed"("tone"); + +ALTER TABLE "WorldSeed" ADD CONSTRAINT "WorldSeed_worldId_fkey" FOREIGN KEY ("worldId") REFERENCES "World"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/api/prisma/migrations/20260805170000_add_auth_rate_limit_buckets/migration.sql b/apps/api/prisma/migrations/20260805170000_add_auth_rate_limit_buckets/migration.sql new file mode 100644 index 0000000..a18d796 --- /dev/null +++ b/apps/api/prisma/migrations/20260805170000_add_auth_rate_limit_buckets/migration.sql @@ -0,0 +1,11 @@ +CREATE TABLE "AuthRateLimitBucket" ( + "key" TEXT NOT NULL, + "count" INTEGER NOT NULL DEFAULT 0, + "expiresAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "AuthRateLimitBucket_pkey" PRIMARY KEY ("key") +); + +CREATE INDEX "AuthRateLimitBucket_expiresAt_idx" ON "AuthRateLimitBucket"("expiresAt"); diff --git a/apps/api/prisma/migrations/20260805170000_add_contribution_drafts/migration.sql b/apps/api/prisma/migrations/20260805170000_add_contribution_drafts/migration.sql new file mode 100644 index 0000000..2f95fad --- /dev/null +++ b/apps/api/prisma/migrations/20260805170000_add_contribution_drafts/migration.sql @@ -0,0 +1,70 @@ +-- CreateEnum +CREATE TYPE "ContributionKind" AS ENUM ('LORE', 'STORY'); + +-- CreateEnum +CREATE TYPE "ContributionStatus" AS ENUM ('DRAFT', 'SUBMITTED'); + +-- AlterEnum +ALTER TYPE "ProposalType" ADD VALUE 'ADD_STORY'; + +-- AlterEnum +ALTER TYPE "WorldAuditAction" ADD VALUE 'CONTRIBUTION_CREATED'; +ALTER TYPE "WorldAuditAction" ADD VALUE 'CONTRIBUTION_UPDATED'; +ALTER TYPE "WorldAuditAction" ADD VALUE 'CONTRIBUTION_DELETED'; +ALTER TYPE "WorldAuditAction" ADD VALUE 'CONTRIBUTION_SUBMITTED'; +ALTER TYPE "WorldAuditAction" ADD VALUE 'PROPOSAL_CREATED'; + +-- AlterTable +ALTER TABLE "Proposal" ADD COLUMN "contributionKind" "ContributionKind"; + +-- CreateTable +CREATE TABLE "ContributionDraft" ( + "id" TEXT NOT NULL, + "worldId" TEXT NOT NULL, + "authorId" TEXT NOT NULL, + "targetLoreEntryId" TEXT, + "kind" "ContributionKind" NOT NULL, + "title" TEXT NOT NULL, + "summary" TEXT, + "content" JSONB NOT NULL, + "status" "ContributionStatus" NOT NULL DEFAULT 'DRAFT', + "proposalId" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "submittedAt" TIMESTAMP(3), + + CONSTRAINT "ContributionDraft_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "ContributionDraft_proposalId_key" ON "ContributionDraft"("proposalId"); + +-- CreateIndex +CREATE INDEX "ContributionDraft_worldId_idx" ON "ContributionDraft"("worldId"); + +-- CreateIndex +CREATE INDEX "ContributionDraft_authorId_idx" ON "ContributionDraft"("authorId"); + +-- CreateIndex +CREATE INDEX "ContributionDraft_worldId_status_idx" ON "ContributionDraft"("worldId", "status"); + +-- CreateIndex +CREATE INDEX "ContributionDraft_worldId_authorId_status_idx" ON "ContributionDraft"("worldId", "authorId", "status"); + +-- CreateIndex +CREATE INDEX "ContributionDraft_targetLoreEntryId_idx" ON "ContributionDraft"("targetLoreEntryId"); + +-- CreateIndex +CREATE INDEX "Proposal_worldId_contributionKind_idx" ON "Proposal"("worldId", "contributionKind"); + +-- AddForeignKey +ALTER TABLE "ContributionDraft" ADD CONSTRAINT "ContributionDraft_worldId_fkey" FOREIGN KEY ("worldId") REFERENCES "World"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ContributionDraft" ADD CONSTRAINT "ContributionDraft_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ContributionDraft" ADD CONSTRAINT "ContributionDraft_targetLoreEntryId_fkey" FOREIGN KEY ("targetLoreEntryId") REFERENCES "LoreEntry"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ContributionDraft" ADD CONSTRAINT "ContributionDraft_proposalId_fkey" FOREIGN KEY ("proposalId") REFERENCES "Proposal"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/apps/api/prisma/migrations/20260808120000_add_quest_story_lore_types/migration.sql b/apps/api/prisma/migrations/20260808120000_add_quest_story_lore_types/migration.sql new file mode 100644 index 0000000..65812f7 --- /dev/null +++ b/apps/api/prisma/migrations/20260808120000_add_quest_story_lore_types/migration.sql @@ -0,0 +1,2 @@ +ALTER TYPE "LoreType" ADD VALUE IF NOT EXISTS 'QUEST'; +ALTER TYPE "LoreType" ADD VALUE IF NOT EXISTS 'STORY'; diff --git a/apps/api/prisma/migrations/20260809120000_add_lore_relationship_audit_actions/migration.sql b/apps/api/prisma/migrations/20260809120000_add_lore_relationship_audit_actions/migration.sql new file mode 100644 index 0000000..ec40412 --- /dev/null +++ b/apps/api/prisma/migrations/20260809120000_add_lore_relationship_audit_actions/migration.sql @@ -0,0 +1,5 @@ +ALTER TYPE "WorldAuditAction" ADD VALUE IF NOT EXISTS 'LORE_ENTRY_CREATED'; +ALTER TYPE "WorldAuditAction" ADD VALUE IF NOT EXISTS 'LORE_ENTRY_UPDATED'; +ALTER TYPE "WorldAuditAction" ADD VALUE IF NOT EXISTS 'LORE_ENTRY_DELETED'; +ALTER TYPE "WorldAuditAction" ADD VALUE IF NOT EXISTS 'LORE_RELATIONSHIP_CREATED'; +ALTER TYPE "WorldAuditAction" ADD VALUE IF NOT EXISTS 'LORE_RELATIONSHIP_DELETED'; diff --git a/apps/api/prisma/migrations/20260810120000_add_world_bible_audit_action/migration.sql b/apps/api/prisma/migrations/20260810120000_add_world_bible_audit_action/migration.sql new file mode 100644 index 0000000..6456e3f --- /dev/null +++ b/apps/api/prisma/migrations/20260810120000_add_world_bible_audit_action/migration.sql @@ -0,0 +1 @@ +ALTER TYPE "WorldAuditAction" ADD VALUE 'WORLD_BIBLE_UPDATED'; diff --git a/apps/api/prisma/migrations/20260810133000_publish_initial_world_bibles/migration.sql b/apps/api/prisma/migrations/20260810133000_publish_initial_world_bibles/migration.sql new file mode 100644 index 0000000..7851ea0 --- /dev/null +++ b/apps/api/prisma/migrations/20260810133000_publish_initial_world_bibles/migration.sql @@ -0,0 +1,4 @@ +UPDATE "WorldBibleVersion" +SET "publishedAt" = COALESCE("publishedAt", "createdAt") +WHERE "versionNumber" = 1 + AND "publishedAt" IS NULL; diff --git a/apps/api/prisma/migrations/20260810134000_backfill_quest_story_lore_types/migration.sql b/apps/api/prisma/migrations/20260810134000_backfill_quest_story_lore_types/migration.sql new file mode 100644 index 0000000..efe0ebb --- /dev/null +++ b/apps/api/prisma/migrations/20260810134000_backfill_quest_story_lore_types/migration.sql @@ -0,0 +1,11 @@ +UPDATE "LoreEntry" +SET "loreType" = 'QUEST' +WHERE "loreType" = 'OTHER' + AND "status" <> 'PUBLISHED_CANON' + AND "content"->>'entityType' = 'QUEST'; + +UPDATE "LoreEntry" +SET "loreType" = 'STORY' +WHERE "loreType" = 'OTHER' + AND "status" <> 'PUBLISHED_CANON' + AND "content"->>'entityType' = 'STORY_CONTRIBUTION'; diff --git a/apps/api/prisma/migrations/20260810143000_add_canon_voting/migration.sql b/apps/api/prisma/migrations/20260810143000_add_canon_voting/migration.sql new file mode 100644 index 0000000..403fc11 --- /dev/null +++ b/apps/api/prisma/migrations/20260810143000_add_canon_voting/migration.sql @@ -0,0 +1,86 @@ +-- CreateEnum +CREATE TYPE "ProposalDecisionOutcome" AS ENUM ('APPROVED_FOR_PUBLICATION', 'REJECTED', 'NEEDS_REVISION', 'ALTERNATE_TIMELINE', 'STALE_BASE_CONFLICT'); + +-- AlterEnum +ALTER TYPE "ProposalStatus" ADD VALUE IF NOT EXISTS 'NEEDS_REVISION'; +ALTER TYPE "ProposalStatus" ADD VALUE IF NOT EXISTS 'ALTERNATE_TIMELINE'; + +-- AlterEnum +ALTER TYPE "VoteChoice" ADD VALUE IF NOT EXISTS 'NEEDS_REVISION'; +ALTER TYPE "VoteChoice" ADD VALUE IF NOT EXISTS 'ALTERNATE_TIMELINE'; + +-- AlterEnum +ALTER TYPE "WorldAuditAction" ADD VALUE IF NOT EXISTS 'CANON_DECISION_FINALIZED'; + +-- AlterTable +ALTER TABLE "Proposal" + ADD COLUMN "votingEndsAt" TIMESTAMP(3), + ADD COLUMN "decidedAt" TIMESTAMP(3), + ADD COLUMN "contentHash" TEXT, + ADD COLUMN "aiWarningAcknowledgedAt" TIMESTAMP(3), + ADD COLUMN "baseCanonVersionId" TEXT, + ADD COLUMN "branchParentProposalId" TEXT, + ADD COLUMN "branchBaseLoreEntryId" TEXT, + ADD COLUMN "branchLabel" TEXT, + ADD COLUMN "conflictMetadata" JSONB, + ADD COLUMN "staleBaseAtDecision" BOOLEAN NOT NULL DEFAULT false; + +-- CreateTable +CREATE TABLE "ProposalDecision" ( + "id" TEXT NOT NULL, + "proposalId" TEXT NOT NULL, + "outcome" "ProposalDecisionOutcome" NOT NULL, + "decidedAt" TIMESTAMP(3) NOT NULL, + "rulesVersion" TEXT NOT NULL, + "payloadSchemaVersion" INTEGER NOT NULL, + "minimumVotes" INTEGER NOT NULL, + "approvalThresholdBps" INTEGER NOT NULL, + "votingWindowHours" INTEGER NOT NULL, + "approveCount" INTEGER NOT NULL, + "rejectCount" INTEGER NOT NULL, + "needsRevisionCount" INTEGER NOT NULL, + "alternateTimelineCount" INTEGER NOT NULL, + "totalVotes" INTEGER NOT NULL, + "approvalNumerator" INTEGER NOT NULL, + "approvalDenominator" INTEGER NOT NULL, + "approvalPercentageBps" INTEGER NOT NULL, + "aiWarningAcknowledged" BOOLEAN NOT NULL DEFAULT false, + "aiWarningSummary" TEXT, + "baseCanonVersionId" TEXT, + "branchParentProposalId" TEXT, + "branchBaseLoreEntryId" TEXT, + "branchLabel" TEXT, + "conflictMetadata" JSONB, + "staleBaseAtDecision" BOOLEAN NOT NULL DEFAULT false, + "contentHash" TEXT NOT NULL, + "decisionPayload" JSONB NOT NULL, + "decisionPayloadHash" TEXT NOT NULL, + "customJsonId" TEXT, + "expectedSigner" TEXT, + "hiveEventId" TEXT, + "transactionId" TEXT, + "blockNumber" BIGINT, + "operationIndex" INTEGER, + "blockchainTimestamp" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + CONSTRAINT "ProposalDecision_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "ProposalDecision_proposalId_key" ON "ProposalDecision"("proposalId"); +CREATE UNIQUE INDEX "ProposalDecision_decisionPayloadHash_key" ON "ProposalDecision"("decisionPayloadHash"); +CREATE UNIQUE INDEX "ProposalDecision_hiveEventId_key" ON "ProposalDecision"("hiveEventId"); +CREATE UNIQUE INDEX "ProposalDecision_transactionId_operationIndex_key" ON "ProposalDecision"("transactionId", "operationIndex"); +CREATE INDEX "ProposalDecision_outcome_idx" ON "ProposalDecision"("outcome"); +CREATE INDEX "ProposalDecision_decidedAt_idx" ON "ProposalDecision"("decidedAt"); +CREATE INDEX "ProposalDecision_customJsonId_idx" ON "ProposalDecision"("customJsonId"); +CREATE INDEX "ProposalDecision_baseCanonVersionId_idx" ON "ProposalDecision"("baseCanonVersionId"); +CREATE INDEX "ProposalDecision_branchBaseLoreEntryId_idx" ON "ProposalDecision"("branchBaseLoreEntryId"); +CREATE INDEX "Proposal_votingEndsAt_idx" ON "Proposal"("votingEndsAt"); +CREATE INDEX "Proposal_baseCanonVersionId_idx" ON "Proposal"("baseCanonVersionId"); +CREATE INDEX "Proposal_branchBaseLoreEntryId_idx" ON "Proposal"("branchBaseLoreEntryId"); + +-- AddForeignKey +ALTER TABLE "ProposalDecision" ADD CONSTRAINT "ProposalDecision_proposalId_fkey" FOREIGN KEY ("proposalId") REFERENCES "Proposal"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "ProposalDecision" ADD CONSTRAINT "ProposalDecision_hiveEventId_fkey" FOREIGN KEY ("hiveEventId") REFERENCES "HiveEvent"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/apps/api/prisma/migrations/20260810162000_add_lore_ordering_indexes/migration.sql b/apps/api/prisma/migrations/20260810162000_add_lore_ordering_indexes/migration.sql new file mode 100644 index 0000000..6b6d476 --- /dev/null +++ b/apps/api/prisma/migrations/20260810162000_add_lore_ordering_indexes/migration.sql @@ -0,0 +1,4 @@ +-- Support deterministic lore list and relation projections. +CREATE INDEX "LoreEntry_worldId_updatedAt_id_idx" ON "LoreEntry"("worldId", "updatedAt", "id"); +CREATE INDEX "LoreRelationship_sourceId_updatedAt_id_idx" ON "LoreRelationship"("sourceId", "updatedAt", "id"); +CREATE INDEX "LoreRelationship_targetId_updatedAt_id_idx" ON "LoreRelationship"("targetId", "updatedAt", "id"); diff --git a/apps/api/prisma/migrations/20260810170000_add_proposal_comments/migration.sql b/apps/api/prisma/migrations/20260810170000_add_proposal_comments/migration.sql new file mode 100644 index 0000000..7046d6a --- /dev/null +++ b/apps/api/prisma/migrations/20260810170000_add_proposal_comments/migration.sql @@ -0,0 +1,23 @@ +-- Proposal discussion is mutable, off-chain application state. It never determines canon. +ALTER TYPE "ModerationTargetType" ADD VALUE 'PROPOSAL_COMMENT'; + +CREATE TABLE "ProposalComment" ( + "id" TEXT NOT NULL, + "proposalId" TEXT NOT NULL, + "authorId" TEXT NOT NULL, + "body" VARCHAR(3000) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deletedAt" TIMESTAMP(3), + "deletedById" TEXT, + + CONSTRAINT "ProposalComment_pkey" PRIMARY KEY ("id") +); + +CREATE INDEX "ProposalComment_proposalId_createdAt_id_idx" ON "ProposalComment"("proposalId", "createdAt", "id"); +CREATE INDEX "ProposalComment_authorId_createdAt_idx" ON "ProposalComment"("authorId", "createdAt"); +CREATE INDEX "ProposalComment_deletedById_idx" ON "ProposalComment"("deletedById"); + +ALTER TABLE "ProposalComment" ADD CONSTRAINT "ProposalComment_proposalId_fkey" FOREIGN KEY ("proposalId") REFERENCES "Proposal"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "ProposalComment" ADD CONSTRAINT "ProposalComment_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +ALTER TABLE "ProposalComment" ADD CONSTRAINT "ProposalComment_deletedById_fkey" FOREIGN KEY ("deletedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; +ALTER TABLE "ProposalComment" ADD CONSTRAINT "ProposalComment_body_not_empty" CHECK (length(btrim("body")) > 0); diff --git a/apps/api/prisma/migrations/20260810190000_repair_published_canon_quest_story_lore_types/migration.sql b/apps/api/prisma/migrations/20260810190000_repair_published_canon_quest_story_lore_types/migration.sql new file mode 100644 index 0000000..ea76c68 --- /dev/null +++ b/apps/api/prisma/migrations/20260810190000_repair_published_canon_quest_story_lore_types/migration.sql @@ -0,0 +1,50 @@ +WITH repaired AS ( + UPDATE "LoreEntry" + SET "loreType" = CASE + WHEN "content"->>'entityType' = 'QUEST' THEN 'QUEST'::"LoreType" + WHEN "content"->>'entityType' = 'STORY_CONTRIBUTION' THEN 'STORY'::"LoreType" + ELSE "loreType" + END + WHERE "status" = 'PUBLISHED_CANON' + AND "loreType" = 'OTHER' + AND "content"->>'entityType' IN ('QUEST', 'STORY_CONTRIBUTION') + RETURNING + "id", + "worldId", + "loreType", + "content"->>'entityType' AS "entityType" +) +INSERT INTO "WorldAuditLog" ( + "id", + "worldId", + "actorId", + "action", + "targetType", + "targetId", + "metadata", + "createdAt" +) +SELECT + gen_random_uuid()::text, + repaired."worldId", + NULL, + 'LORE_ENTRY_UPDATED', + 'LORE_ENTRY', + repaired."id", + jsonb_build_object( + 'reason', 'Corrected a published canon lore type that still used OTHER after the QUEST/STORY type split.', + 'migration', '20260810190000_repair_published_canon_quest_story_lore_types', + 'loreType', repaired."loreType", + 'entityType', repaired."entityType" + ), + CURRENT_TIMESTAMP +FROM repaired +WHERE NOT EXISTS ( + SELECT 1 + FROM "WorldAuditLog" + WHERE "WorldAuditLog"."targetType" = 'LORE_ENTRY' + AND "WorldAuditLog"."targetId" = repaired."id" + AND "WorldAuditLog"."action" = 'LORE_ENTRY_UPDATED' + AND "WorldAuditLog"."metadata"->>'migration' = + '20260810190000_repair_published_canon_quest_story_lore_types' +); diff --git a/apps/api/prisma/migrations/20260811130000_align_indexer_watermark_index/migration.sql b/apps/api/prisma/migrations/20260811130000_align_indexer_watermark_index/migration.sql new file mode 100644 index 0000000..8b7a019 --- /dev/null +++ b/apps/api/prisma/migrations/20260811130000_align_indexer_watermark_index/migration.sql @@ -0,0 +1,6 @@ +-- PostgreSQL truncates identifiers to 63 bytes. The original migration requested +-- the longer Prisma-generated name, which is stored as the shorter mapped name below. +DROP INDEX IF EXISTS "IndexerWatermark_lastProcessedBlock_lastProcessedOperationIndex_idx"; + +CREATE INDEX "IndexerWatermark_lastProcessedBlock_lastProcessedOperationI_idx" +ON "IndexerWatermark"("lastProcessedBlock", "lastProcessedOperationIndex"); diff --git a/apps/api/prisma/migrations/20260812120000_add_canon_confirmation_audit_action/migration.sql b/apps/api/prisma/migrations/20260812120000_add_canon_confirmation_audit_action/migration.sql new file mode 100644 index 0000000..7b81653 --- /dev/null +++ b/apps/api/prisma/migrations/20260812120000_add_canon_confirmation_audit_action/migration.sql @@ -0,0 +1 @@ +ALTER TYPE "WorldAuditAction" ADD VALUE IF NOT EXISTS 'CANON_DECISION_CONFIRMED'; diff --git a/apps/api/prisma/migrations/20260902124000_add_search_vector_index/migration.sql b/apps/api/prisma/migrations/20260902124000_add_search_vector_index/migration.sql new file mode 100644 index 0000000..9c173dd --- /dev/null +++ b/apps/api/prisma/migrations/20260902124000_add_search_vector_index/migration.sql @@ -0,0 +1,27 @@ +ALTER TABLE "SearchIndex" +ADD COLUMN "searchVector" tsvector; + +CREATE FUNCTION update_search_index_vector() +RETURNS trigger +LANGUAGE plpgsql +AS $$ +BEGIN + NEW."searchVector" := + setweight(to_tsvector('english', coalesce(NEW."title", '')), 'A') || + setweight(to_tsvector('english', coalesce(NEW."searchableContent", '')), 'B'); + RETURN NEW; +END; +$$; + +CREATE TRIGGER "SearchIndex_searchVector_update" +BEFORE INSERT OR UPDATE OF "title", "searchableContent" +ON "SearchIndex" +FOR EACH ROW +EXECUTE FUNCTION update_search_index_vector(); + +UPDATE "SearchIndex" +SET "searchVector" = + setweight(to_tsvector('english', coalesce("title", '')), 'A') || + setweight(to_tsvector('english', coalesce("searchableContent", '')), 'B'); + +CREATE INDEX "SearchIndex_searchVector_idx" ON "SearchIndex" USING GIN ("searchVector"); diff --git a/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma index 1962082..7beab31 100644 --- a/apps/api/prisma/schema.prisma +++ b/apps/api/prisma/schema.prisma @@ -12,7 +12,9 @@ enum LoreType { CHARACTER LOCATION FACTION + QUEST EVENT + STORY ARTIFACT HISTORY RULE @@ -29,16 +31,29 @@ enum LoreStatus { enum ProposalType { ADD_LORE + ADD_STORY UPDATE_LORE UPDATE_WORLD_BIBLE } +enum ContributionKind { + LORE + STORY +} + +enum ContributionStatus { + DRAFT + SUBMITTED +} + enum ProposalStatus { DRAFT SUBMITTED VOTING APPROVED_FOR_PUBLICATION REJECTED + NEEDS_REVISION + ALTERNATE_TIMELINE PUBLISHED WITHDRAWN } @@ -46,9 +61,19 @@ enum ProposalStatus { enum VoteChoice { APPROVE REJECT + NEEDS_REVISION + ALTERNATE_TIMELINE ABSTAIN } +enum ProposalDecisionOutcome { + APPROVED_FOR_PUBLICATION + REJECTED + NEEDS_REVISION + ALTERNATE_TIMELINE + STALE_BASE_CONFLICT +} + enum AIReportStatus { PENDING COMPLETED @@ -69,6 +94,7 @@ enum ModerationTargetType { LORE_ENTRY LORE_RELATIONSHIP PROPOSAL + PROPOSAL_COMMENT APP_VOTE AI_REPORT HIVE_REFERENCE @@ -110,50 +136,291 @@ enum SearchEntityType { PROPOSAL } +enum PlatformRole { + USER + ADMIN +} + +enum WorldRole { + READER + CONTRIBUTOR + FOUNDER + CURATOR +} + +enum WorldAuditAction { + ROLE_ASSIGNED + ROLE_CHANGED + ROLE_REMOVED + MODERATION_ACTION + CANON_STATUS_EXECUTED + AI_WARNING_RESOLVED + CONTRIBUTION_CREATED + CONTRIBUTION_UPDATED + CONTRIBUTION_DELETED + CONTRIBUTION_SUBMITTED + PROPOSAL_CREATED + CANON_DECISION_FINALIZED + CANON_DECISION_CONFIRMED + WORLD_BIBLE_UPDATED + LORE_ENTRY_CREATED + LORE_ENTRY_UPDATED + LORE_ENTRY_DELETED + LORE_RELATIONSHIP_CREATED + LORE_RELATIONSHIP_DELETED +} + +enum AuthProvider { + KEYCHAIN + HIVESIGNER +} + +enum ExternalIdentityProvider { + GOOGLE +} + +enum HiveProvisioningStatus { + PENDING + SUCCEEDED + FAILED + NOT_CONFIGURED +} + +enum RcDelegationStatus { + PENDING + SUCCEEDED + FAILED + NOT_CONFIGURED +} + model User { - id String @id @default(cuid()) - hiveUsername String @unique - normalizedHiveUsername String @unique - displayName String? - avatarUrl String? - bio String? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - foundedWorlds World[] @relation("WorldFounder") - bibleVersions WorldBibleVersion[] @relation("WorldBibleVersionCreator") - loreEntries LoreEntry[] @relation("LoreEntryAuthor") - proposals Proposal[] @relation("ProposalAuthor") - votes AppVote[] @relation("AppVoteVoter") - moderationReports ModerationReport[] @relation("ModerationReporter") - moderationReviews ModerationReport[] @relation("ModerationReviewer") - hiveReferences HiveReference[] @relation("HiveReferenceAuthor") - rewardRecords RewardRecord[] - rewardSummaries UserRewardSummary[] - reputationSnapshots UserReputationSnapshot[] + id String @id @default(cuid()) + hiveUsername String @unique + normalizedHiveUsername String @unique + displayName String? + avatarUrl String? + bio String? + platformRole PlatformRole @default(USER) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + foundedWorlds World[] @relation("WorldFounder") + bibleVersions WorldBibleVersion[] @relation("WorldBibleVersionCreator") + loreEntries LoreEntry[] @relation("LoreEntryAuthor") + proposals Proposal[] @relation("ProposalAuthor") + proposalComments ProposalComment[] @relation("ProposalCommentAuthor") + deletedProposalComments ProposalComment[] @relation("ProposalCommentDeleter") + contributionDrafts ContributionDraft[] @relation("ContributionDraftAuthor") + votes AppVote[] @relation("AppVoteVoter") + moderationReports ModerationReport[] @relation("ModerationReporter") + moderationReviews ModerationReport[] @relation("ModerationReviewer") + hiveReferences HiveReference[] @relation("HiveReferenceAuthor") + rewardRecords RewardRecord[] + rewardSummaries UserRewardSummary[] + reputationSnapshots UserReputationSnapshot[] + worldMemberships WorldMembership[] @relation("WorldMembershipUser") + grantedWorldMemberships WorldMembership[] @relation("WorldMembershipGrantor") + worldAuditLogs WorldAuditLog[] @relation("WorldAuditLogActor") + authChallenges AuthChallenge[] + refreshSessions RefreshSession[] + externalIdentityLinks ExternalIdentityLink[] + provisioningRequests HiveProvisioningRequest[] + rcDelegations RcDelegation[] @@index([normalizedHiveUsername]) + @@index([platformRole]) +} + +model AuthChallenge { + id String @id @default(cuid()) + userId String? + user User? @relation(fields: [userId], references: [id], onDelete: SetNull) + normalizedHiveUsername String + provider AuthProvider + intent String @default("authentication") + challengeHash String + nonceHash String + issuedAt DateTime + expiresAt DateTime + consumedAt DateTime? + createdAt DateTime @default(now()) + + @@unique([challengeHash]) + @@index([normalizedHiveUsername, provider]) + @@index([expiresAt]) + @@index([consumedAt]) + @@index([userId]) +} + +model RefreshSession { + id String @id @default(cuid()) + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + sessionFamilyId String + refreshTokenHash String @unique + createdAt DateTime @default(now()) + expiresAt DateTime + rotatedAt DateTime? + revokedAt DateTime? + replacedById String? @unique + replacedBy RefreshSession? @relation("RefreshSessionRotation", fields: [replacedById], references: [id], onDelete: SetNull) + replaces RefreshSession? @relation("RefreshSessionRotation") + lastUsedAt DateTime? + userAgent String? + ipAddress String? + + @@index([userId]) + @@index([sessionFamilyId]) + @@index([expiresAt]) + @@index([revokedAt]) +} + +model AuthRateLimitBucket { + key String @id + count Int @default(0) + expiresAt DateTime + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([expiresAt]) +} + +model ExternalIdentityLink { + id String @id @default(cuid()) + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + provider ExternalIdentityProvider + providerSubject String + verifiedEmail String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + provisioningRequests HiveProvisioningRequest[] + + @@unique([provider, providerSubject]) + @@unique([userId, provider]) + @@index([userId]) +} + +model HiveProvisioningRequest { + id String @id @default(cuid()) + userId String? + user User? @relation(fields: [userId], references: [id], onDelete: SetNull) + externalIdentityLinkId String? + externalIdentityLink ExternalIdentityLink? @relation(fields: [externalIdentityLinkId], references: [id], onDelete: SetNull) + requestedHiveUsername String + status HiveProvisioningStatus @default(NOT_CONFIGURED) + failureReason String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([userId]) + @@index([externalIdentityLinkId]) + @@index([status]) +} + +model RcDelegation { + id String @id @default(cuid()) + userId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + hiveUsername String + delegatorAccount String + amount String + status RcDelegationStatus @default(NOT_CONFIGURED) + transactionId String? + operationIndex Int? + idempotencyKey String @unique + failureReason String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([userId]) + @@index([hiveUsername]) + @@index([status]) } model World { - id String @id @default(cuid()) - slug String @unique - title String - description String - founderId String - founder User @relation("WorldFounder", fields: [founderId], references: [id], onDelete: Restrict) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - bibleVersions WorldBibleVersion[] - loreEntries LoreEntry[] - loreRelationships LoreRelationship[] - proposals Proposal[] - moderationReports ModerationReport[] - searchIndexes SearchIndex[] + id String @id @default(cuid()) + slug String @unique + title String + description String + founderId String + founder User @relation("WorldFounder", fields: [founderId], references: [id], onDelete: Restrict) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + seed WorldSeed? + bibleVersions WorldBibleVersion[] + loreEntries LoreEntry[] + loreRelationships LoreRelationship[] + proposals Proposal[] + contributionDrafts ContributionDraft[] + moderationReports ModerationReport[] + searchIndexes SearchIndex[] + memberships WorldMembership[] + auditLogs WorldAuditLog[] @@index([founderId]) @@index([createdAt]) } +model WorldSeed { + id String @id @default(cuid()) + worldId String @unique + world World @relation(fields: [worldId], references: [id], onDelete: Restrict) + premise String + genre String + tone String + mainConflict String + startingLocation String? + firstCharacters Json? + firstFactions Json? + firstHistoricalEvent String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + /// Mutable off-chain world seed. Hive publication requires a future approved publication flow. + + @@index([genre]) + @@index([tone]) +} + +model WorldMembership { + id String @id @default(cuid()) + worldId String + world World @relation(fields: [worldId], references: [id], onDelete: Restrict) + userId String + user User @relation("WorldMembershipUser", fields: [userId], references: [id], onDelete: Restrict) + role WorldRole + grantedById String? + grantedBy User? @relation("WorldMembershipGrantor", fields: [grantedById], references: [id], onDelete: SetNull) + grantedAt DateTime @default(now()) + revokedAt DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([worldId, userId]) + @@index([worldId, role]) + @@index([userId, role]) + @@index([grantedById]) + @@index([revokedAt]) +} + +model WorldAuditLog { + id String @id @default(cuid()) + worldId String + world World @relation(fields: [worldId], references: [id], onDelete: Restrict) + actorId String? + actor User? @relation("WorldAuditLogActor", fields: [actorId], references: [id], onDelete: SetNull) + action WorldAuditAction + targetType String + targetId String + metadata Json? + createdAt DateTime @default(now()) + /// Append-only audit trail for role changes, moderation actions, and rule-based status execution. + + @@index([worldId, createdAt]) + @@index([actorId, createdAt]) + @@index([worldId, action, createdAt]) + @@index([targetType, targetId]) +} + model WorldBibleVersion { id String @id @default(cuid()) worldId String @@ -177,30 +444,32 @@ model WorldBibleVersion { } model LoreEntry { - id String @id @default(cuid()) - worldId String - world World @relation(fields: [worldId], references: [id], onDelete: Restrict) - authorId String - author User @relation("LoreEntryAuthor", fields: [authorId], references: [id], onDelete: Restrict) - title String - slug String - loreType LoreType - content Json - status LoreStatus @default(DRAFT) - publishedAt DateTime? - hiveReferenceId String? @unique + id String @id @default(cuid()) + worldId String + world World @relation(fields: [worldId], references: [id], onDelete: Restrict) + authorId String + author User @relation("LoreEntryAuthor", fields: [authorId], references: [id], onDelete: Restrict) + title String + slug String + loreType LoreType + content Json + status LoreStatus @default(DRAFT) + publishedAt DateTime? + hiveReferenceId String? @unique /// Published canon must be confirmed through an indexed HiveReference, not only this mutable row. - hiveReference HiveReference? @relation(fields: [hiveReferenceId], references: [id], onDelete: SetNull) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - outgoingRelations LoreRelationship[] @relation("LoreRelationshipSource") - incomingRelations LoreRelationship[] @relation("LoreRelationshipTarget") - targetProposals Proposal[] @relation("ProposalTargetLoreEntry") - resultingProposals Proposal[] @relation("ProposalResultingLoreEntry") + hiveReference HiveReference? @relation(fields: [hiveReferenceId], references: [id], onDelete: SetNull) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + outgoingRelations LoreRelationship[] @relation("LoreRelationshipSource") + incomingRelations LoreRelationship[] @relation("LoreRelationshipTarget") + targetProposals Proposal[] @relation("ProposalTargetLoreEntry") + targetContributionDrafts ContributionDraft[] @relation("ContributionDraftTargetLoreEntry") + resultingProposals Proposal[] @relation("ProposalResultingLoreEntry") @@unique([worldId, slug]) @@index([worldId, status]) @@index([worldId, loreType]) + @@index([worldId, updatedAt, id]) @@index([authorId]) } @@ -222,6 +491,8 @@ model LoreRelationship { @@index([worldId]) @@index([sourceId]) @@index([targetId]) + @@index([sourceId, updatedAt, id]) + @@index([targetId, updatedAt, id]) } model Proposal { @@ -231,6 +502,7 @@ model Proposal { authorId String author User @relation("ProposalAuthor", fields: [authorId], references: [id], onDelete: Restrict) proposalType ProposalType + contributionKind ContributionKind? status ProposalStatus @default(DRAFT) title String summary String @@ -243,17 +515,79 @@ model Proposal { resultingBibleVersion WorldBibleVersion? @relation("ProposalResultingBibleVersion", fields: [resultingBibleVersionId], references: [id], onDelete: SetNull) submittedAt DateTime? votingStartedAt DateTime? + votingEndsAt DateTime? + decidedAt DateTime? approvedAt DateTime? rejectedAt DateTime? publishedAt DateTime? + contentHash String? + aiWarningAcknowledgedAt DateTime? + baseCanonVersionId String? + branchParentProposalId String? + branchBaseLoreEntryId String? + branchLabel String? + conflictMetadata Json? + staleBaseAtDecision Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt + contributionDraft ContributionDraft? votes AppVote[] + decision ProposalDecision? aiReports AIReport[] moderationReports ModerationReport[] + comments ProposalComment[] @@index([worldId, status]) @@index([authorId]) + @@index([worldId, contributionKind]) + @@index([targetLoreEntryId]) + @@index([votingEndsAt]) + @@index([baseCanonVersionId]) + @@index([branchBaseLoreEntryId]) +} + +model ProposalComment { + id String @id @default(cuid()) + proposalId String + proposal Proposal @relation(fields: [proposalId], references: [id], onDelete: Restrict) + authorId String + author User @relation("ProposalCommentAuthor", fields: [authorId], references: [id], onDelete: Restrict) + body String @db.VarChar(3000) + createdAt DateTime @default(now()) + deletedAt DateTime? + deletedById String? + deletedBy User? @relation("ProposalCommentDeleter", fields: [deletedById], references: [id], onDelete: SetNull) + /// Off-chain plain-text discussion. Comments never count as AppVote rows or canon decisions. + + @@index([proposalId, createdAt, id]) + @@index([authorId, createdAt]) + @@index([deletedById]) +} + +model ContributionDraft { + id String @id @default(cuid()) + worldId String + world World @relation(fields: [worldId], references: [id], onDelete: Cascade) + authorId String + author User @relation("ContributionDraftAuthor", fields: [authorId], references: [id], onDelete: Cascade) + targetLoreEntryId String? + targetLoreEntry LoreEntry? @relation("ContributionDraftTargetLoreEntry", fields: [targetLoreEntryId], references: [id], onDelete: SetNull) + kind ContributionKind + title String + summary String? + content Json + status ContributionStatus @default(DRAFT) + proposalId String? @unique + /// Submitted drafts are locked; Proposal.proposedContent stores the immutable reviewer snapshot. + proposal Proposal? @relation(fields: [proposalId], references: [id], onDelete: SetNull) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + submittedAt DateTime? + + @@index([worldId]) + @@index([authorId]) + @@index([worldId, status]) + @@index([worldId, authorId, status]) @@index([targetLoreEntryId]) } @@ -275,6 +609,55 @@ model AppVote { @@index([voterId]) } +model ProposalDecision { + id String @id @default(cuid()) + proposalId String @unique + proposal Proposal @relation(fields: [proposalId], references: [id], onDelete: Restrict) + outcome ProposalDecisionOutcome + decidedAt DateTime + rulesVersion String + payloadSchemaVersion Int + minimumVotes Int + approvalThresholdBps Int + votingWindowHours Int + approveCount Int + rejectCount Int + needsRevisionCount Int + alternateTimelineCount Int + totalVotes Int + approvalNumerator Int + approvalDenominator Int + approvalPercentageBps Int + aiWarningAcknowledged Boolean @default(false) + aiWarningSummary String? + baseCanonVersionId String? + branchParentProposalId String? + branchBaseLoreEntryId String? + branchLabel String? + conflictMetadata Json? + staleBaseAtDecision Boolean @default(false) + contentHash String + decisionPayload Json + decisionPayloadHash String @unique + customJsonId String? + expectedSigner String? + hiveEventId String? @unique + hiveEvent HiveEvent? @relation(fields: [hiveEventId], references: [id], onDelete: SetNull) + transactionId String? + blockNumber BigInt? + operationIndex Int? + blockchainTimestamp DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([transactionId, operationIndex]) + @@index([outcome]) + @@index([decidedAt]) + @@index([customJsonId]) + @@index([baseCanonVersionId]) + @@index([branchBaseLoreEntryId]) +} + model AIReport { id String @id @default(cuid()) proposalId String @@ -351,16 +734,17 @@ model HiveReference { } model HiveEvent { - id String @id @default(cuid()) + id String @id @default(cuid()) blockNumber BigInt transactionId String operationIndex Int eventType HiveEventType blockchainTimestamp DateTime payload Json - processedAt DateTime @default(now()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + processedAt DateTime @default(now()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + proposalDecision ProposalDecision? /// Rebuildable indexed Hive operation; the blockchain remains authoritative. @@unique([transactionId, operationIndex]) @@ -369,6 +753,19 @@ model HiveEvent { @@index([blockchainTimestamp]) } +model IndexerWatermark { + name String @id + lastProcessedBlock BigInt @default(0) + lastProcessedOperationIndex Int @default(-1) + lastRunStartedAt DateTime? + lastRunFinishedAt DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + /// Durable resume point for rebuildable indexer processes. + + @@index([lastProcessedBlock, lastProcessedOperationIndex], map: "IndexerWatermark_lastProcessedBlock_lastProcessedOperationI_idx") +} + model RewardRecord { id String @id @default(cuid()) userId String @@ -425,18 +822,20 @@ model UserReputationSnapshot { } model SearchIndex { - id String @id @default(cuid()) + id String @id @default(cuid()) worldId String? - world World? @relation(fields: [worldId], references: [id], onDelete: Cascade) + world World? @relation(fields: [worldId], references: [id], onDelete: Cascade) entityType SearchEntityType entityId String title String searchableContent String + searchVector Unsupported("tsvector")? metadata Json? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt /// Derived PostgreSQL search projection for the MVP; rebuildable from source records. @@unique([entityType, entityId]) @@index([worldId, entityType]) + @@index([searchVector], type: Gin) } diff --git a/apps/api/prisma/seed.ts b/apps/api/prisma/seed.ts index 764c94d..b01a451 100644 --- a/apps/api/prisma/seed.ts +++ b/apps/api/prisma/seed.ts @@ -3,6 +3,8 @@ import 'dotenv/config'; import { PrismaPg } from '@prisma/adapter-pg'; import { PrismaClient } from '../src/generated/prisma/client.js'; +import { WorldRole } from '../src/generated/prisma/enums.js'; +import { ensureActiveFounderMembership } from '../src/lib/founder-memberships.js'; const databaseUrl = process.env.DATABASE_URL; @@ -67,6 +69,58 @@ async function main() { }, }); + // Development seed data is disposable: reruns intentionally normalize this fixture + // back to one active FOUNDER membership instead of preserving manual local edits. + await ensureActiveFounderMembership(prisma, { + worldId: world.id, + userId: founder.id, + }); + + await prisma.worldMembership.upsert({ + where: { + worldId_userId: { + worldId: world.id, + userId: contributor.id, + }, + }, + update: { + role: WorldRole.CONTRIBUTOR, + grantedById: founder.id, + revokedAt: null, + }, + create: { + worldId: world.id, + userId: contributor.id, + role: WorldRole.CONTRIBUTOR, + grantedById: founder.id, + }, + }); + + await prisma.worldSeed.upsert({ + where: { + worldId: world.id, + }, + update: { + genre: 'Fantasy', + mainConflict: 'Weather, memory, and craft compete to define what the islands remember.', + premise: + 'A fictional chain of floating islands where memory, weather, and craft are tightly intertwined.', + tone: 'Luminous mystery', + }, + create: { + worldId: world.id, + premise: + 'A fictional chain of floating islands where memory, weather, and craft are tightly intertwined.', + genre: 'Fantasy', + tone: 'Luminous mystery', + mainConflict: 'Weather, memory, and craft compete to define what the islands remember.', + startingLocation: 'Mirror Lighthouse', + firstCharacters: ['Ember Quill', 'Mira Vale'], + firstFactions: ['Cartographers Guild'], + firstHistoricalEvent: 'The first reflected storm appears before its clouds arrive.', + }, + }); + await prisma.worldBibleVersion.upsert({ where: { worldId_versionNumber: { @@ -90,6 +144,7 @@ async function main() { }, ], }, + publishedAt: new Date(), }, create: { worldId: world.id, @@ -110,6 +165,7 @@ async function main() { }, ], }, + publishedAt: new Date(), }, }); @@ -237,6 +293,68 @@ async function main() { }, }); + await prisma.contributionDraft.upsert({ + where: { + id: 'dev-contribution-glass-archipelago-001', + }, + update: { + kind: 'LORE', + title: 'Draft: Lighthouse Keeper Oath', + summary: 'Development-only structured contribution draft.', + content: { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Lighthouse Keeper Oath' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Keepers swear to report reflected storms before dawn bells sound.', + }, + ], + }, + ], + }, + status: 'DRAFT', + proposalId: null, + submittedAt: null, + targetLoreEntryId: lighthouse.id, + }, + create: { + id: 'dev-contribution-glass-archipelago-001', + worldId: world.id, + authorId: contributor.id, + kind: 'LORE', + title: 'Draft: Lighthouse Keeper Oath', + summary: 'Development-only structured contribution draft.', + content: { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Lighthouse Keeper Oath' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Keepers swear to report reflected storms before dawn bells sound.', + }, + ], + }, + ], + }, + targetLoreEntryId: lighthouse.id, + }, + }); + await prisma.aIReport.upsert({ where: { id: 'dev-ai-report-glass-archipelago-001' }, update: { diff --git a/apps/api/scripts/check-fresh-prisma-migrations.mjs b/apps/api/scripts/check-fresh-prisma-migrations.mjs new file mode 100644 index 0000000..eb9e548 --- /dev/null +++ b/apps/api/scripts/check-fresh-prisma-migrations.mjs @@ -0,0 +1,225 @@ +import { spawnSync } from 'node:child_process'; +import { randomUUID } from 'node:crypto'; +import process from 'node:process'; + +import pg from 'pg'; + +const { Client } = pg; + +const disposablePrefix = 'hivelore_migrate_check_'; +const adminUrl = process.env.TEST_DATABASE_ADMIN_URL; + +if (!adminUrl) { + throw new Error( + 'TEST_DATABASE_ADMIN_URL is required, for example postgresql://postgres:postgres@127.0.0.1:5432/postgres', + ); +} + +const databaseName = `${disposablePrefix}${Date.now()}_${process.pid}_${randomUUID().replaceAll('-', '').slice(0, 8)}`; + +if (!databaseName.startsWith(disposablePrefix)) { + throw new Error(`Refusing to use non-disposable database name: ${databaseName}`); +} + +const databaseUrl = new URL(adminUrl); +databaseUrl.pathname = `/${databaseName}`; +const directUrl = databaseUrl.toString(); + +function runPrisma(args, options = {}) { + const executable = process.platform === 'win32' ? 'npx.cmd' : 'npx'; + const result = spawnSync(executable, ['prisma', ...args], { + cwd: new URL('..', import.meta.url), + env: { + ...process.env, + DATABASE_URL: directUrl, + DIRECT_URL: directUrl, + NODE_ENV: 'test', + }, + shell: false, + stdio: 'inherit', + ...options, + }); + + if (result.status !== 0) { + throw new Error(`prisma ${args.join(' ')} failed with exit code ${result.status}`); + } +} + +async function withAdminClient(callback) { + const client = new Client({ connectionString: adminUrl }); + await client.connect(); + + try { + return await callback(client); + } finally { + await client.end(); + } +} + +async function createDatabase() { + await withAdminClient((client) => client.query(`CREATE DATABASE "${databaseName}"`)); +} + +async function dropDatabase() { + if (!databaseName.startsWith(disposablePrefix)) { + throw new Error(`Refusing to drop non-disposable database: ${databaseName}`); + } + + await withAdminClient(async (client) => { + await client.query( + ` + SELECT pg_terminate_backend(pid) + FROM pg_stat_activity + WHERE datname = $1 + AND pid <> pg_backend_pid() + `, + [databaseName], + ); + await client.query(`DROP DATABASE IF EXISTS "${databaseName}"`); + }); +} + +async function smokeCheckSchema() { + const client = new Client({ connectionString: directUrl }); + await client.connect(); + + try { + const tables = await client.query( + ` + SELECT tablename + FROM pg_tables + WHERE schemaname = 'public' + AND tablename = ANY($1) + `, + [ + [ + 'User', + 'World', + 'WorldSeed', + 'WorldMembership', + 'LoreEntry', + 'Proposal', + 'ProposalDecision', + 'ProposalComment', + 'IndexerWatermark', + ], + ], + ); + + const enums = await client.query( + ` + SELECT typname + FROM pg_type + WHERE typname = ANY($1) + `, + [ + [ + 'LoreType', + 'WorldAuditAction', + 'ProposalDecisionOutcome', + 'ContributionKind', + 'AuthProvider', + ], + ], + ); + + const constraints = await client.query( + ` + SELECT conname + FROM pg_constraint + WHERE conname = ANY($1) + `, + [ + [ + 'World_founderId_fkey', + 'ProposalDecision_proposalId_fkey', + 'ProposalComment_body_not_empty', + ], + ], + ); + + const indexes = await client.query( + ` + SELECT indexname + FROM pg_indexes + WHERE schemaname = 'public' + AND indexname = ANY($1) + `, + [ + [ + 'LoreEntry_worldId_slug_key', + 'ProposalDecision_decisionPayloadHash_key', + 'ProposalComment_proposalId_createdAt_id_idx', + ], + ], + ); + + const seedCounts = await client.query(` + SELECT + (SELECT COUNT(*)::int FROM "User") AS users, + (SELECT COUNT(*)::int FROM "World") AS worlds, + (SELECT COUNT(*)::int FROM "WorldSeed") AS world_seeds, + (SELECT COUNT(*)::int FROM "ContributionDraft") AS contribution_drafts + `); + + const expectations = [ + ['tables', tables.rowCount, 9], + ['enums', enums.rowCount, 5], + ['constraints', constraints.rowCount, 3], + ['indexes', indexes.rowCount, 3], + ]; + + for (const [label, actual, expected] of expectations) { + if (actual !== expected) { + throw new Error(`Expected ${expected} ${label}, found ${actual}`); + } + } + + const counts = seedCounts.rows[0]; + if ( + counts.users < 2 || + counts.worlds < 1 || + counts.world_seeds < 1 || + counts.contribution_drafts < 1 + ) { + throw new Error(`Seed smoke check failed: ${JSON.stringify(counts)}`); + } + } finally { + await client.end(); + } +} + +try { + console.log(`Creating disposable PostgreSQL database ${databaseName}`); + await createDatabase(); + + console.log('Running prisma migrate deploy from migration zero'); + runPrisma(['migrate', 'deploy']); + + console.log('Re-running prisma migrate deploy to prove idempotency'); + runPrisma(['migrate', 'deploy']); + + console.log('Checking deployed schema for drift against schema.prisma'); + runPrisma([ + 'migrate', + 'diff', + '--from-config-datasource', + '--to-schema', + 'prisma/schema.prisma', + '--exit-code', + ]); + + console.log('Generating Prisma Client'); + runPrisma(['generate']); + + console.log('Running development seed against disposable database'); + runPrisma(['db', 'seed']); + + console.log('Smoke-checking tables, enums, constraints, indexes, and seed data'); + await smokeCheckSchema(); + + console.log('Fresh Prisma migration check passed'); +} finally { + console.log(`Dropping disposable PostgreSQL database ${databaseName}`); + await dropDatabase(); +} diff --git a/apps/api/scripts/check-upgrade-prisma-migrations.mjs b/apps/api/scripts/check-upgrade-prisma-migrations.mjs new file mode 100644 index 0000000..0722f53 --- /dev/null +++ b/apps/api/scripts/check-upgrade-prisma-migrations.mjs @@ -0,0 +1,182 @@ +import { spawnSync } from 'node:child_process'; +import { randomUUID } from 'node:crypto'; +import { writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; + +import pg from 'pg'; + +const { Client } = pg; + +const disposablePrefix = 'hivelore_migrate_upgrade_'; +const adminUrl = process.env.TEST_DATABASE_ADMIN_URL; +const baseSchema = process.env.TEST_DATABASE_BASE_PRISMA_SCHEMA; +const repairedMigration = '20260718154842_init'; +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const apiWorkspaceDir = path.resolve(scriptDir, '..'); +const repoRoot = path.resolve(apiWorkspaceDir, '..', '..'); +const prismaExecutable = path.join( + repoRoot, + 'node_modules', + '.bin', + process.platform === 'win32' ? 'prisma.cmd' : 'prisma', +); + +if (!adminUrl) { + throw new Error( + 'TEST_DATABASE_ADMIN_URL is required, for example postgresql://postgres:postgres@127.0.0.1:5432/postgres', + ); +} + +if (!baseSchema) { + throw new Error('TEST_DATABASE_BASE_PRISMA_SCHEMA must point to the base branch schema.prisma.'); +} + +const databaseName = `${disposablePrefix}${Date.now()}_${process.pid}_${randomUUID().replaceAll('-', '').slice(0, 8)}`; + +if (!databaseName.startsWith(disposablePrefix)) { + throw new Error(`Refusing to use non-disposable database name: ${databaseName}`); +} + +const databaseUrl = new URL(adminUrl); +databaseUrl.pathname = `/${databaseName}`; +const directUrl = databaseUrl.toString(); + +function runPrisma(args, options = {}) { + const result = spawnSync(prismaExecutable, args, { + cwd: options.cwd ?? apiWorkspaceDir, + env: { + ...process.env, + DATABASE_URL: directUrl, + DIRECT_URL: directUrl, + NODE_ENV: 'test', + }, + shell: false, + stdio: 'inherit', + ...options, + }); + + if (!options.allowFailure && result.status !== 0) { + throw new Error(`prisma ${args.join(' ')} failed with exit code ${result.status}`); + } + + return result.status ?? 1; +} + +function getBaseApiWorkspaceDir(schemaPath) { + return path.dirname(path.dirname(path.resolve(schemaPath))); +} + +async function createBasePrismaConfig(apiWorkspaceDir) { + const configPath = path.join(apiWorkspaceDir, 'prisma.config.ts'); + + await writeFile( + configPath, + ` +export default { + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + }, + datasource: { + url: process.env.DIRECT_URL, + }, +}; +`.trimStart(), + ); + + return configPath; +} + +async function withAdminClient(callback) { + const client = new Client({ connectionString: adminUrl }); + await client.connect(); + + try { + return await callback(client); + } finally { + await client.end(); + } +} + +async function createDatabase() { + await withAdminClient((client) => client.query(`CREATE DATABASE "${databaseName}"`)); +} + +async function dropDatabase() { + if (!databaseName.startsWith(disposablePrefix)) { + throw new Error(`Refusing to drop non-disposable database: ${databaseName}`); + } + + await withAdminClient(async (client) => { + await client.query( + ` + SELECT pg_terminate_backend(pid) + FROM pg_stat_activity + WHERE datname = $1 + AND pid <> pg_backend_pid() + `, + [databaseName], + ); + await client.query(`DROP DATABASE IF EXISTS "${databaseName}"`); + }); +} + +try { + console.log(`Creating disposable PostgreSQL database ${databaseName}`); + await createDatabase(); + + console.log('Deploying base branch migration history'); + const baseApiWorkspaceDir = getBaseApiWorkspaceDir(baseSchema); + const baseConfig = await createBasePrismaConfig(baseApiWorkspaceDir); + const baseStatus = runPrisma( + ['migrate', 'deploy', '--schema', baseSchema, '--config', baseConfig], + { + allowFailure: true, + cwd: baseApiWorkspaceDir, + }, + ); + + if (baseStatus !== 0) { + console.log(`Resolving historical failed migration ${repairedMigration} as rolled back`); + runPrisma( + [ + 'migrate', + 'resolve', + '--rolled-back', + repairedMigration, + '--schema', + baseSchema, + '--config', + baseConfig, + ], + { + cwd: baseApiWorkspaceDir, + }, + ); + + console.log('Re-running base branch migration history after resolve'); + runPrisma(['migrate', 'deploy', '--schema', baseSchema, '--config', baseConfig], { + cwd: baseApiWorkspaceDir, + }); + } + + console.log('Deploying repaired migration history from this branch'); + runPrisma(['migrate', 'deploy']); + + console.log('Checking upgraded schema for drift against schema.prisma'); + runPrisma([ + 'migrate', + 'diff', + '--from-config-datasource', + '--to-schema', + 'prisma/schema.prisma', + '--exit-code', + ]); + + console.log('Prisma migration upgrade check passed'); +} finally { + console.log(`Dropping disposable PostgreSQL database ${databaseName}`); + await dropDatabase(); +} diff --git a/apps/api/scripts/run-tests.mjs b/apps/api/scripts/run-tests.mjs new file mode 100644 index 0000000..d15f3f9 --- /dev/null +++ b/apps/api/scripts/run-tests.mjs @@ -0,0 +1,60 @@ +import { spawnSync } from 'node:child_process'; +import { readdirSync, statSync } from 'node:fs'; +import { join } from 'node:path'; +import process from 'node:process'; + +function findTestFiles(directory) { + return readdirSync(directory).flatMap((entry) => { + const path = join(directory, entry); + const stat = statSync(path); + + if (stat.isDirectory()) { + return findTestFiles(path); + } + + return entry.endsWith('.test.ts') ? [path] : []; + }); +} + +const testFiles = findTestFiles('src'); + +if (testFiles.length === 0) { + throw new Error('No API test files were discovered.'); +} + +console.log(`Discovered ${testFiles.length} API test files.`); + +const testArgs = ['tsx', '--test', ...testFiles]; +const command = + process.platform === 'win32' + ? { + args: testArgs, + executable: 'npx.cmd', + shell: true, + } + : { + args: testArgs, + executable: 'npx', + shell: false, + }; +const result = spawnSync(command.executable, command.args, { + env: { + ...process.env, + AUTH_JWT_SECRET: process.env.AUTH_JWT_SECRET ?? 'test-only-jwt-secret-with-enough-entropy', + AUTH_REFRESH_SECRET: + process.env.AUTH_REFRESH_SECRET ?? 'test-only-refresh-secret-with-enough-entropy', + NODE_ENV: 'test', + }, + shell: command.shell, + stdio: 'inherit', +}); + +if (result.error) { + console.error(result.error); +} + +if (result.status !== 0) { + console.error(`API test command exited with status ${result.status ?? 'null'}.`); +} + +process.exit(result.status ?? 1); diff --git a/apps/api/src/app.ts b/apps/api/src/app.ts index b18a61a..8ec1c59 100644 --- a/apps/api/src/app.ts +++ b/apps/api/src/app.ts @@ -1,23 +1,95 @@ import cors from '@fastify/cors'; +import rateLimit from '@fastify/rate-limit'; import Fastify from 'fastify'; +import { randomUUID } from 'node:crypto'; import { env } from './config/env.js'; +import { createPrismaRateLimitStore } from './lib/auth-rate-limit-store.js'; +import { reportUnhandledError } from './lib/error-tracking.js'; +import { createHafClient } from './lib/hive/client.js'; +import { prisma } from './lib/prisma.js'; import { registerAuthRoutes } from './routes/auth.js'; +import { registerContributionRoutes } from './routes/contributions.js'; import { registerHealthRoute } from './routes/health.js'; +import { registerLoreRoutes } from './routes/lore.js'; +import { registerProposalRoutes } from './routes/proposals.js'; +import { registerProfileRoutes } from './routes/profiles.js'; +import { registerSearchRoutes } from './routes/search.js'; +import { registerWorldRoutes } from './routes/worlds.js'; export async function buildApp() { const app = Fastify({ + genReqId: () => randomUUID(), logger: { level: env.NODE_ENV === 'production' ? 'info' : 'debug', + redact: [ + 'req.headers.authorization', + 'req.headers.cookie', + 'request.headers.authorization', + 'request.headers.cookie', + 'body.signature', + 'body.refreshToken', + 'body.nonce', + 'body.code', + 'body.id_token', + 'body.access_token', + 'body.refresh_token', + ], }, + requestIdHeader: 'x-request-id', + trustProxy: env.TRUST_PROXY, + }); + + app.addHook('onRequest', async (request, reply) => { + reply.header('x-request-id', request.id); + }); + + app.addHook('onError', async (request, _reply, error) => { + // Deliberately NOT awaited: Fastify waits for this hook before sending the + // error response, so awaiting webhook delivery would let a slow tracker + // delay - or with no timeout, indefinitely stall - every failing request. + // reportUnhandledError swallows its own errors, so this cannot reject. + void reportUnhandledError( + { + error, + method: request.method, + requestId: request.id, + url: request.url, + }, + { + enabled: env.ERROR_TRACKING_ENABLED, + logger: request.log, + webhookUrl: env.ERROR_TRACKING_WEBHOOK_URL, + }, + ); }); await app.register(cors, { + credentials: true, origin: env.NODE_ENV === 'production' ? env.CORS_ORIGIN : [env.CORS_ORIGIN], }); + await app.register(rateLimit, { + global: false, + skipOnError: false, + // Route scope already isolates /auth/refresh from /auth/challenge inside this shared + // namespace. A separate namespace is only warranted for independent cleanup, retention, + // or monitoring. + store: createPrismaRateLimitStore(prisma), + }); - await registerHealthRoute(app); + await registerHealthRoute(app, { + database: prisma, + getHeadBlock: () => createHafClient().getHeadBlock(), + indexerLagThresholdBlocks: env.INDEXER_MAX_READY_LAG_BLOCKS, + indexerName: env.INDEXER_NAME, + }); await registerAuthRoutes(app); + await registerWorldRoutes(app); + await registerLoreRoutes(app); + await registerContributionRoutes(app); + await registerProposalRoutes(app); + await registerProfileRoutes(app); + await registerSearchRoutes(app); return app; } diff --git a/apps/api/src/config/env.test.ts b/apps/api/src/config/env.test.ts new file mode 100644 index 0000000..ac9d618 --- /dev/null +++ b/apps/api/src/config/env.test.ts @@ -0,0 +1,133 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +process.env.NODE_ENV = 'test'; + +const { parseEnv } = await import('./env.js'); + +describe('API environment validation', () => { + test('parses false feature flags as false', () => { + const env = parseEnv({ + AUTH_COOKIE_SECURE: 'false', + AUTH_JWT_SECRET: 'test-jwt-secret-that-is-long-enough', + AUTH_REFRESH_SECRET: 'test-refresh-secret-that-is-long-enough', + GOOGLE_AUTH_ENABLED: 'false', + GOOGLE_HIVE_PROVISIONING_ENABLED: 'false', + HIVE_RC_DELEGATION_ENABLED: 'false', + NODE_ENV: 'development', + }); + + assert.equal(env.AUTH_COOKIE_SECURE, false); + assert.equal(env.GOOGLE_AUTH_ENABLED, false); + assert.equal(env.GOOGLE_HIVE_PROVISIONING_ENABLED, false); + assert.equal(env.HIVE_RC_DELEGATION_ENABLED, false); + }); + + test('rejects missing Google credentials only when Google auth is enabled', () => { + assert.throws( + () => + parseEnv({ + GOOGLE_AUTH_ENABLED: 'true', + NODE_ENV: 'development', + AUTH_JWT_SECRET: 'test-jwt-secret-that-is-long-enough', + AUTH_REFRESH_SECRET: 'test-refresh-secret-that-is-long-enough', + }), + /Google auth is enabled/, + ); + + assert.equal( + parseEnv({ + AUTH_JWT_SECRET: 'test-jwt-secret-that-is-long-enough', + AUTH_REFRESH_SECRET: 'test-refresh-secret-that-is-long-enough', + GOOGLE_AUTH_ENABLED: 'false', + NODE_ENV: 'development', + }).GOOGLE_AUTH_ENABLED, + false, + ); + }); + + test('rejects missing auth secrets in every non-test environment', () => { + assert.throws( + () => + parseEnv({ + NODE_ENV: 'development', + }), + /AUTH_JWT_SECRET/, + ); + }); + + test('allows missing auth secrets only in test', () => { + const env = parseEnv({ + NODE_ENV: 'test', + }); + + assert.match(env.AUTH_JWT_SECRET, /test-only/); + assert.match(env.AUTH_REFRESH_SECRET, /test-only/); + }); + + test('parses mainnet Hive config and bounded broadcast defaults', () => { + const env = parseEnv({ + NODE_ENV: 'test', + }); + + assert.equal( + env.HIVE_MAINNET_CHAIN_ID, + 'beeab0de00000000000000000000000000000000000000000000000000000000', + ); + assert.equal(env.HIVE_BROADCAST_MAX_ATTEMPTS, 4); + assert.equal(env.HIVE_BROADCAST_TOTAL_DEADLINE_MS, 90_000); + assert.equal(env.HIVE_CONFIRMATION_TIMEOUT_MS, 60_000); + }); + + test('parses bounded proposal comment write rate-limit defaults', () => { + const env = parseEnv({ + NODE_ENV: 'test', + }); + + assert.equal(env.PROPOSAL_COMMENT_WRITE_RATE_LIMIT_CACHE, 10_000); + assert.equal(env.PROPOSAL_COMMENT_WRITE_RATE_LIMIT_MAX, 5); + assert.equal(env.PROPOSAL_COMMENT_WRITE_RATE_LIMIT_WINDOW_SECONDS, 60); + assert.equal(env.ERROR_TRACKING_ENABLED, false); + assert.equal(env.INDEXER_MAX_READY_LAG_BLOCKS, 1_200); + }); + + test('requires an error tracking webhook only when alerting is enabled', () => { + assert.throws( + () => + parseEnv({ + ERROR_TRACKING_ENABLED: 'true', + NODE_ENV: 'test', + }), + /ERROR_TRACKING_WEBHOOK_URL/, + ); + + assert.equal( + parseEnv({ + ERROR_TRACKING_ENABLED: 'true', + ERROR_TRACKING_WEBHOOK_URL: 'https://example.com/hivelore-errors', + NODE_ENV: 'test', + }).ERROR_TRACKING_ENABLED, + true, + ); + }); + + test('rejects invalid Hive network configuration', () => { + assert.throws( + () => + parseEnv({ + HIVE_MAINNET_CHAIN_ID: 'not-a-chain-id', + NODE_ENV: 'test', + }), + /HIVE_MAINNET_CHAIN_ID/, + ); + + assert.throws( + () => + parseEnv({ + NODE_ENV: 'test', + PROPOSAL_COMMENT_WRITE_RATE_LIMIT_MAX: '0', + }), + /PROPOSAL_COMMENT_WRITE_RATE_LIMIT_MAX/, + ); + }); +}); diff --git a/apps/api/src/config/env.ts b/apps/api/src/config/env.ts index 021ef7b..a0b9f67 100644 --- a/apps/api/src/config/env.ts +++ b/apps/api/src/config/env.ts @@ -1,23 +1,194 @@ import { config as loadDotenv } from 'dotenv'; import { z } from 'zod'; +import { DEFAULT_HIVE_RETRY_CONFIG } from '../lib/hive/network-config.js'; + loadDotenv(); +const booleanEnv = (defaultValue: boolean) => + z + .enum(['true', 'false']) + .optional() + .transform((value) => (value === undefined ? defaultValue : value === 'true')); +const optionalBooleanEnv = z + .enum(['true', 'false']) + .optional() + .transform((value) => (value === undefined ? undefined : value === 'true')); + const envSchema = z.object({ NODE_ENV: z.enum(['development', 'test', 'production']).default('development'), HOST: z.string().min(1).default('0.0.0.0'), PORT: z.coerce.number().int().positive().max(65535).default(3001), CORS_ORIGIN: z.string().url().default('http://localhost:3000'), + TRUST_PROXY: booleanEnv(false), + AUTH_JWT_SECRET: z.string().min(32).optional(), + AUTH_REFRESH_SECRET: z.string().min(32).optional(), + AUTH_JWT_ISSUER: z.string().min(1).default('hivelore'), + AUTH_JWT_AUDIENCE: z.string().min(1).default('hivelore-web'), + AUTH_ACCESS_TOKEN_TTL_SECONDS: z.coerce.number().int().positive().default(900), + AUTH_REFRESH_TOKEN_TTL_SECONDS: z.coerce + .number() + .int() + .positive() + .default(60 * 60 * 24 * 14), + AUTH_CHALLENGE_TTL_SECONDS: z.coerce.number().int().positive().default(300), + AUTH_COOKIE_DOMAIN: z.string().optional(), + AUTH_COOKIE_SECURE: optionalBooleanEnv, + PROPOSAL_COMMENT_WRITE_RATE_LIMIT_CACHE: z.coerce.number().int().positive().default(10_000), + PROPOSAL_COMMENT_WRITE_RATE_LIMIT_MAX: z.coerce.number().int().positive().default(5), + PROPOSAL_COMMENT_WRITE_RATE_LIMIT_WINDOW_SECONDS: z.coerce.number().int().positive().default(60), + ERROR_TRACKING_ENABLED: booleanEnv(false), + ERROR_TRACKING_WEBHOOK_URL: z.string().url().optional(), + HIVE_RPC_URL: z.string().url().default('https://api.hive.blog'), + HIVE_MAINNET_CHAIN_ID: z + .string() + .regex(/^[a-f0-9]{64}$/i) + .default('beeab0de00000000000000000000000000000000000000000000000000000000'), + HIVE_MAINNET_RPC_NODES: z.string().min(1).default('https://api.hive.blog'), + HIVE_MAINNET_HAF_URL: z.string().url().default('https://api.hive.blog/hafbe-api'), + HIVE_BROADCAST_MAX_ATTEMPTS: z.coerce + .number() + .int() + .positive() + .default(DEFAULT_HIVE_RETRY_CONFIG.maxAttempts), + HIVE_BROADCAST_INITIAL_DELAY_MS: z.coerce + .number() + .int() + .positive() + .default(DEFAULT_HIVE_RETRY_CONFIG.initialDelayMs), + HIVE_BROADCAST_MAX_DELAY_MS: z.coerce + .number() + .int() + .positive() + .default(DEFAULT_HIVE_RETRY_CONFIG.maxDelayMs), + HIVE_BROADCAST_BACKOFF_MULTIPLIER: z.coerce + .number() + .positive() + .default(DEFAULT_HIVE_RETRY_CONFIG.backoffMultiplier), + HIVE_BROADCAST_JITTER_RATIO: z.coerce + .number() + .min(0) + .max(1) + .default(DEFAULT_HIVE_RETRY_CONFIG.jitterRatio), + HIVE_BROADCAST_TIMEOUT_MS: z.coerce + .number() + .int() + .positive() + .default(DEFAULT_HIVE_RETRY_CONFIG.requestTimeoutMs), + HIVE_BROADCAST_TOTAL_DEADLINE_MS: z.coerce + .number() + .int() + .positive() + .default(DEFAULT_HIVE_RETRY_CONFIG.totalDeadlineMs), + HIVE_CONFIRMATION_POLL_INTERVAL_MS: z.coerce + .number() + .int() + .positive() + .default(DEFAULT_HIVE_RETRY_CONFIG.confirmationPollIntervalMs), + HIVE_CONFIRMATION_TIMEOUT_MS: z.coerce + .number() + .int() + .positive() + .default(DEFAULT_HIVE_RETRY_CONFIG.confirmationTimeoutMs), + HIVE_NODE_MAX_CONSECUTIVE_FAILURES: z.coerce + .number() + .int() + .positive() + .default(DEFAULT_HIVE_RETRY_CONFIG.maxConsecutiveNodeFailures), + HIVE_NODE_COOLDOWN_MS: z.coerce + .number() + .int() + .positive() + .default(DEFAULT_HIVE_RETRY_CONFIG.nodeCooldownMs), + HIVE_AUTH_AUDIENCE: z.string().min(1).default('hivelore-local-api'), + HAF_API_URL: z.string().url().default('https://api.hive.blog/hafbe-api'), + HIVELORE_APP_ID: z.string().min(1).default('hivelore/0.1.0'), + INDEXER_NAME: z.string().min(1).default('hivelore-haf'), + INDEXER_START_BLOCK: z.coerce.number().int().positive().default(1), + INDEXER_BATCH_SIZE: z.coerce.number().int().positive().max(1_000).default(100), + INDEXER_MAX_BLOCKS_PER_RUN: z.coerce.number().int().positive().default(1_000), + INDEXER_MAX_READY_LAG_BLOCKS: z.coerce.number().int().nonnegative().default(1_200), + GOOGLE_AUTH_ENABLED: booleanEnv(false), + GOOGLE_CLIENT_ID: z.string().optional(), + GOOGLE_CLIENT_SECRET: z.string().optional(), + GOOGLE_REDIRECT_URI: z.string().url().optional(), + GOOGLE_HIVE_PROVISIONING_ENABLED: booleanEnv(false), + HIVE_RC_DELEGATION_ENABLED: booleanEnv(false), + HIVE_RC_DELEGATOR_ACCOUNT: z.string().optional(), + HIVE_RC_DELEGATION_AMOUNT: z.string().optional(), }); -const parsed = envSchema.safeParse(process.env); +export function parseEnv(environment: NodeJS.ProcessEnv) { + const parsed = envSchema.safeParse(environment); + + if (!parsed.success) { + const errors = parsed.error.issues + .map((issue) => `${issue.path.join('.')}: ${issue.message}`) + .join('; '); + + throw new Error(`Invalid API environment configuration: ${errors}`); + } + + const parsedEnv = + parsed.data.NODE_ENV === 'test' + ? { + ...parsed.data, + AUTH_JWT_SECRET: + parsed.data.AUTH_JWT_SECRET ?? 'test-only-jwt-secret-with-enough-entropy', + AUTH_REFRESH_SECRET: + parsed.data.AUTH_REFRESH_SECRET ?? 'test-only-refresh-secret-with-enough-entropy', + } + : parsed.data; + + if (parsedEnv.NODE_ENV !== 'test') { + if (!parsedEnv.AUTH_JWT_SECRET) { + throw new Error('AUTH_JWT_SECRET must be set.'); + } + + if (!parsedEnv.AUTH_REFRESH_SECRET) { + throw new Error('AUTH_REFRESH_SECRET must be set.'); + } + + if ( + parsedEnv.AUTH_JWT_SECRET.includes('development-only') || + parsedEnv.AUTH_REFRESH_SECRET.includes('development-only') + ) { + throw new Error('Authentication secrets must not use development-only defaults.'); + } + } + + if (parsedEnv.NODE_ENV === 'production' && parsedEnv.AUTH_COOKIE_SECURE === false) { + throw new Error('AUTH_COOKIE_SECURE must be true in production.'); + } + + if ( + parsedEnv.GOOGLE_AUTH_ENABLED && + (!parsedEnv.GOOGLE_CLIENT_ID || + !parsedEnv.GOOGLE_CLIENT_SECRET || + !parsedEnv.GOOGLE_REDIRECT_URI) + ) { + throw new Error('Google auth is enabled but Google OAuth environment variables are missing.'); + } + + if ( + parsedEnv.HIVE_RC_DELEGATION_ENABLED && + (!parsedEnv.HIVE_RC_DELEGATOR_ACCOUNT || !parsedEnv.HIVE_RC_DELEGATION_AMOUNT) + ) { + throw new Error('Hive RC delegation is enabled but delegation configuration is missing.'); + } + + if (parsedEnv.ERROR_TRACKING_ENABLED && !parsedEnv.ERROR_TRACKING_WEBHOOK_URL) { + throw new Error('Error tracking is enabled but ERROR_TRACKING_WEBHOOK_URL is missing.'); + } -if (!parsed.success) { - const errors = parsed.error.issues - .map((issue) => `${issue.path.join('.')}: ${issue.message}`) - .join('; '); + if (!parsedEnv.AUTH_JWT_SECRET || !parsedEnv.AUTH_REFRESH_SECRET) { + throw new Error('Authentication secrets must be set.'); + } - throw new Error(`Invalid API environment configuration: ${errors}`); + return parsedEnv as typeof parsedEnv & { + AUTH_JWT_SECRET: string; + AUTH_REFRESH_SECRET: string; + }; } -export const env = parsed.data; +export const env = parseEnv(process.env); diff --git a/apps/api/src/generated/prisma/browser.ts b/apps/api/src/generated/prisma/browser.ts deleted file mode 100644 index 2f0ca25..0000000 --- a/apps/api/src/generated/prisma/browser.ts +++ /dev/null @@ -1,94 +0,0 @@ - -/* !!! 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 World - * - */ -export type World = Prisma.WorldModel -/** - * Model WorldBibleVersion - * - */ -export type WorldBibleVersion = Prisma.WorldBibleVersionModel -/** - * Model LoreEntry - * - */ -export type LoreEntry = Prisma.LoreEntryModel -/** - * Model LoreRelationship - * - */ -export type LoreRelationship = Prisma.LoreRelationshipModel -/** - * Model Proposal - * - */ -export type Proposal = Prisma.ProposalModel -/** - * Model AppVote - * - */ -export type AppVote = Prisma.AppVoteModel -/** - * Model AIReport - * - */ -export type AIReport = Prisma.AIReportModel -/** - * Model ModerationReport - * - */ -export type ModerationReport = Prisma.ModerationReportModel -/** - * Model HiveReference - * - */ -export type HiveReference = Prisma.HiveReferenceModel -/** - * Model HiveEvent - * - */ -export type HiveEvent = Prisma.HiveEventModel -/** - * Model RewardRecord - * - */ -export type RewardRecord = Prisma.RewardRecordModel -/** - * Model UserRewardSummary - * - */ -export type UserRewardSummary = Prisma.UserRewardSummaryModel -/** - * Model UserReputationSnapshot - * - */ -export type UserReputationSnapshot = Prisma.UserReputationSnapshotModel -/** - * Model SearchIndex - * - */ -export type SearchIndex = Prisma.SearchIndexModel diff --git a/apps/api/src/generated/prisma/client.ts b/apps/api/src/generated/prisma/client.ts deleted file mode 100644 index 6e00543..0000000 --- a/apps/api/src/generated/prisma/client.ts +++ /dev/null @@ -1,118 +0,0 @@ - -/* !!! 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 World - * - */ -export type World = Prisma.WorldModel -/** - * Model WorldBibleVersion - * - */ -export type WorldBibleVersion = Prisma.WorldBibleVersionModel -/** - * Model LoreEntry - * - */ -export type LoreEntry = Prisma.LoreEntryModel -/** - * Model LoreRelationship - * - */ -export type LoreRelationship = Prisma.LoreRelationshipModel -/** - * Model Proposal - * - */ -export type Proposal = Prisma.ProposalModel -/** - * Model AppVote - * - */ -export type AppVote = Prisma.AppVoteModel -/** - * Model AIReport - * - */ -export type AIReport = Prisma.AIReportModel -/** - * Model ModerationReport - * - */ -export type ModerationReport = Prisma.ModerationReportModel -/** - * Model HiveReference - * - */ -export type HiveReference = Prisma.HiveReferenceModel -/** - * Model HiveEvent - * - */ -export type HiveEvent = Prisma.HiveEventModel -/** - * Model RewardRecord - * - */ -export type RewardRecord = Prisma.RewardRecordModel -/** - * Model UserRewardSummary - * - */ -export type UserRewardSummary = Prisma.UserRewardSummaryModel -/** - * Model UserReputationSnapshot - * - */ -export type UserReputationSnapshot = Prisma.UserReputationSnapshotModel -/** - * Model SearchIndex - * - */ -export type SearchIndex = Prisma.SearchIndexModel diff --git a/apps/api/src/generated/prisma/commonInputTypes.ts b/apps/api/src/generated/prisma/commonInputTypes.ts deleted file mode 100644 index f3645d8..0000000 --- a/apps/api/src/generated/prisma/commonInputTypes.ts +++ /dev/null @@ -1,1154 +0,0 @@ - -/* !!! 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 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 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 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 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 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 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 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 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 EnumLoreTypeFilter<$PrismaModel = never> = { - equals?: $Enums.LoreType | Prisma.EnumLoreTypeFieldRefInput<$PrismaModel> - in?: $Enums.LoreType[] | Prisma.ListEnumLoreTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.LoreType[] | Prisma.ListEnumLoreTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumLoreTypeFilter<$PrismaModel> | $Enums.LoreType -} - -export type EnumLoreStatusFilter<$PrismaModel = never> = { - equals?: $Enums.LoreStatus | Prisma.EnumLoreStatusFieldRefInput<$PrismaModel> - in?: $Enums.LoreStatus[] | Prisma.ListEnumLoreStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.LoreStatus[] | Prisma.ListEnumLoreStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumLoreStatusFilter<$PrismaModel> | $Enums.LoreStatus -} - -export type EnumLoreTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.LoreType | Prisma.EnumLoreTypeFieldRefInput<$PrismaModel> - in?: $Enums.LoreType[] | Prisma.ListEnumLoreTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.LoreType[] | Prisma.ListEnumLoreTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumLoreTypeWithAggregatesFilter<$PrismaModel> | $Enums.LoreType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumLoreTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumLoreTypeFilter<$PrismaModel> -} - -export type EnumLoreStatusWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.LoreStatus | Prisma.EnumLoreStatusFieldRefInput<$PrismaModel> - in?: $Enums.LoreStatus[] | Prisma.ListEnumLoreStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.LoreStatus[] | Prisma.ListEnumLoreStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumLoreStatusWithAggregatesFilter<$PrismaModel> | $Enums.LoreStatus - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumLoreStatusFilter<$PrismaModel> - _max?: Prisma.NestedEnumLoreStatusFilter<$PrismaModel> -} - -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 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 EnumProposalTypeFilter<$PrismaModel = never> = { - equals?: $Enums.ProposalType | Prisma.EnumProposalTypeFieldRefInput<$PrismaModel> - in?: $Enums.ProposalType[] | Prisma.ListEnumProposalTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.ProposalType[] | Prisma.ListEnumProposalTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumProposalTypeFilter<$PrismaModel> | $Enums.ProposalType -} - -export type EnumProposalStatusFilter<$PrismaModel = never> = { - equals?: $Enums.ProposalStatus | Prisma.EnumProposalStatusFieldRefInput<$PrismaModel> - in?: $Enums.ProposalStatus[] | Prisma.ListEnumProposalStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.ProposalStatus[] | Prisma.ListEnumProposalStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumProposalStatusFilter<$PrismaModel> | $Enums.ProposalStatus -} - -export type EnumProposalTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.ProposalType | Prisma.EnumProposalTypeFieldRefInput<$PrismaModel> - in?: $Enums.ProposalType[] | Prisma.ListEnumProposalTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.ProposalType[] | Prisma.ListEnumProposalTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumProposalTypeWithAggregatesFilter<$PrismaModel> | $Enums.ProposalType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumProposalTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumProposalTypeFilter<$PrismaModel> -} - -export type EnumProposalStatusWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.ProposalStatus | Prisma.EnumProposalStatusFieldRefInput<$PrismaModel> - in?: $Enums.ProposalStatus[] | Prisma.ListEnumProposalStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.ProposalStatus[] | Prisma.ListEnumProposalStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumProposalStatusWithAggregatesFilter<$PrismaModel> | $Enums.ProposalStatus - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumProposalStatusFilter<$PrismaModel> - _max?: Prisma.NestedEnumProposalStatusFilter<$PrismaModel> -} - -export type EnumVoteChoiceFilter<$PrismaModel = never> = { - equals?: $Enums.VoteChoice | Prisma.EnumVoteChoiceFieldRefInput<$PrismaModel> - in?: $Enums.VoteChoice[] | Prisma.ListEnumVoteChoiceFieldRefInput<$PrismaModel> - notIn?: $Enums.VoteChoice[] | Prisma.ListEnumVoteChoiceFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumVoteChoiceFilter<$PrismaModel> | $Enums.VoteChoice -} - -export type DecimalNullableFilter<$PrismaModel = never> = { - equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null - in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null - notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null - lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - not?: Prisma.NestedDecimalNullableFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null -} - -export type EnumVoteChoiceWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.VoteChoice | Prisma.EnumVoteChoiceFieldRefInput<$PrismaModel> - in?: $Enums.VoteChoice[] | Prisma.ListEnumVoteChoiceFieldRefInput<$PrismaModel> - notIn?: $Enums.VoteChoice[] | Prisma.ListEnumVoteChoiceFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumVoteChoiceWithAggregatesFilter<$PrismaModel> | $Enums.VoteChoice - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumVoteChoiceFilter<$PrismaModel> - _max?: Prisma.NestedEnumVoteChoiceFilter<$PrismaModel> -} - -export type DecimalNullableWithAggregatesFilter<$PrismaModel = never> = { - equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null - in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null - notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null - lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - not?: Prisma.NestedDecimalNullableWithAggregatesFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null - _count?: Prisma.NestedIntNullableFilter<$PrismaModel> - _avg?: Prisma.NestedDecimalNullableFilter<$PrismaModel> - _sum?: Prisma.NestedDecimalNullableFilter<$PrismaModel> - _min?: Prisma.NestedDecimalNullableFilter<$PrismaModel> - _max?: Prisma.NestedDecimalNullableFilter<$PrismaModel> -} - -export type EnumAIReportStatusFilter<$PrismaModel = never> = { - equals?: $Enums.AIReportStatus | Prisma.EnumAIReportStatusFieldRefInput<$PrismaModel> - in?: $Enums.AIReportStatus[] | Prisma.ListEnumAIReportStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.AIReportStatus[] | Prisma.ListEnumAIReportStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumAIReportStatusFilter<$PrismaModel> | $Enums.AIReportStatus -} - -export type EnumAIReportStatusWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.AIReportStatus | Prisma.EnumAIReportStatusFieldRefInput<$PrismaModel> - in?: $Enums.AIReportStatus[] | Prisma.ListEnumAIReportStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.AIReportStatus[] | Prisma.ListEnumAIReportStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumAIReportStatusWithAggregatesFilter<$PrismaModel> | $Enums.AIReportStatus - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumAIReportStatusFilter<$PrismaModel> - _max?: Prisma.NestedEnumAIReportStatusFilter<$PrismaModel> -} - -export type EnumModerationTargetTypeFilter<$PrismaModel = never> = { - equals?: $Enums.ModerationTargetType | Prisma.EnumModerationTargetTypeFieldRefInput<$PrismaModel> - in?: $Enums.ModerationTargetType[] | Prisma.ListEnumModerationTargetTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.ModerationTargetType[] | Prisma.ListEnumModerationTargetTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumModerationTargetTypeFilter<$PrismaModel> | $Enums.ModerationTargetType -} - -export type EnumModerationStatusFilter<$PrismaModel = never> = { - equals?: $Enums.ModerationStatus | Prisma.EnumModerationStatusFieldRefInput<$PrismaModel> - in?: $Enums.ModerationStatus[] | Prisma.ListEnumModerationStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.ModerationStatus[] | Prisma.ListEnumModerationStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumModerationStatusFilter<$PrismaModel> | $Enums.ModerationStatus -} - -export type EnumModerationTargetTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.ModerationTargetType | Prisma.EnumModerationTargetTypeFieldRefInput<$PrismaModel> - in?: $Enums.ModerationTargetType[] | Prisma.ListEnumModerationTargetTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.ModerationTargetType[] | Prisma.ListEnumModerationTargetTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumModerationTargetTypeWithAggregatesFilter<$PrismaModel> | $Enums.ModerationTargetType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumModerationTargetTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumModerationTargetTypeFilter<$PrismaModel> -} - -export type EnumModerationStatusWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.ModerationStatus | Prisma.EnumModerationStatusFieldRefInput<$PrismaModel> - in?: $Enums.ModerationStatus[] | Prisma.ListEnumModerationStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.ModerationStatus[] | Prisma.ListEnumModerationStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumModerationStatusWithAggregatesFilter<$PrismaModel> | $Enums.ModerationStatus - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumModerationStatusFilter<$PrismaModel> - _max?: Prisma.NestedEnumModerationStatusFilter<$PrismaModel> -} - -export type EnumHiveEntityTypeFilter<$PrismaModel = never> = { - equals?: $Enums.HiveEntityType | Prisma.EnumHiveEntityTypeFieldRefInput<$PrismaModel> - in?: $Enums.HiveEntityType[] | Prisma.ListEnumHiveEntityTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.HiveEntityType[] | Prisma.ListEnumHiveEntityTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumHiveEntityTypeFilter<$PrismaModel> | $Enums.HiveEntityType -} - -export type BigIntNullableFilter<$PrismaModel = never> = { - equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> | null - in?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> | null - notIn?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> | null - lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - not?: Prisma.NestedBigIntNullableFilter<$PrismaModel> | bigint | number | null -} - -export type IntNullableFilter<$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 EnumHiveEntityTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.HiveEntityType | Prisma.EnumHiveEntityTypeFieldRefInput<$PrismaModel> - in?: $Enums.HiveEntityType[] | Prisma.ListEnumHiveEntityTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.HiveEntityType[] | Prisma.ListEnumHiveEntityTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumHiveEntityTypeWithAggregatesFilter<$PrismaModel> | $Enums.HiveEntityType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumHiveEntityTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumHiveEntityTypeFilter<$PrismaModel> -} - -export type BigIntNullableWithAggregatesFilter<$PrismaModel = never> = { - equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> | null - in?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> | null - notIn?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> | null - lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - not?: Prisma.NestedBigIntNullableWithAggregatesFilter<$PrismaModel> | bigint | number | null - _count?: Prisma.NestedIntNullableFilter<$PrismaModel> - _avg?: Prisma.NestedFloatNullableFilter<$PrismaModel> - _sum?: Prisma.NestedBigIntNullableFilter<$PrismaModel> - _min?: Prisma.NestedBigIntNullableFilter<$PrismaModel> - _max?: Prisma.NestedBigIntNullableFilter<$PrismaModel> -} - -export type IntNullableWithAggregatesFilter<$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.NestedIntNullableWithAggregatesFilter<$PrismaModel> | number | null - _count?: Prisma.NestedIntNullableFilter<$PrismaModel> - _avg?: Prisma.NestedFloatNullableFilter<$PrismaModel> - _sum?: Prisma.NestedIntNullableFilter<$PrismaModel> - _min?: Prisma.NestedIntNullableFilter<$PrismaModel> - _max?: Prisma.NestedIntNullableFilter<$PrismaModel> -} - -export type BigIntFilter<$PrismaModel = never> = { - equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - in?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> - notIn?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> - lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - not?: Prisma.NestedBigIntFilter<$PrismaModel> | bigint | number -} - -export type EnumHiveEventTypeFilter<$PrismaModel = never> = { - equals?: $Enums.HiveEventType | Prisma.EnumHiveEventTypeFieldRefInput<$PrismaModel> - in?: $Enums.HiveEventType[] | Prisma.ListEnumHiveEventTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.HiveEventType[] | Prisma.ListEnumHiveEventTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumHiveEventTypeFilter<$PrismaModel> | $Enums.HiveEventType -} - -export type BigIntWithAggregatesFilter<$PrismaModel = never> = { - equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - in?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> - notIn?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> - lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - not?: Prisma.NestedBigIntWithAggregatesFilter<$PrismaModel> | bigint | number - _count?: Prisma.NestedIntFilter<$PrismaModel> - _avg?: Prisma.NestedFloatFilter<$PrismaModel> - _sum?: Prisma.NestedBigIntFilter<$PrismaModel> - _min?: Prisma.NestedBigIntFilter<$PrismaModel> - _max?: Prisma.NestedBigIntFilter<$PrismaModel> -} - -export type EnumHiveEventTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.HiveEventType | Prisma.EnumHiveEventTypeFieldRefInput<$PrismaModel> - in?: $Enums.HiveEventType[] | Prisma.ListEnumHiveEventTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.HiveEventType[] | Prisma.ListEnumHiveEventTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumHiveEventTypeWithAggregatesFilter<$PrismaModel> | $Enums.HiveEventType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumHiveEventTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumHiveEventTypeFilter<$PrismaModel> -} - -export type EnumRewardTypeFilter<$PrismaModel = never> = { - equals?: $Enums.RewardType | Prisma.EnumRewardTypeFieldRefInput<$PrismaModel> - in?: $Enums.RewardType[] | Prisma.ListEnumRewardTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.RewardType[] | Prisma.ListEnumRewardTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumRewardTypeFilter<$PrismaModel> | $Enums.RewardType -} - -export type DecimalFilter<$PrismaModel = never> = { - equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> - notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> - lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - not?: Prisma.NestedDecimalFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string -} - -export type EnumRewardTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.RewardType | Prisma.EnumRewardTypeFieldRefInput<$PrismaModel> - in?: $Enums.RewardType[] | Prisma.ListEnumRewardTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.RewardType[] | Prisma.ListEnumRewardTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumRewardTypeWithAggregatesFilter<$PrismaModel> | $Enums.RewardType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumRewardTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumRewardTypeFilter<$PrismaModel> -} - -export type DecimalWithAggregatesFilter<$PrismaModel = never> = { - equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> - notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> - lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - not?: Prisma.NestedDecimalWithAggregatesFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string - _count?: Prisma.NestedIntFilter<$PrismaModel> - _avg?: Prisma.NestedDecimalFilter<$PrismaModel> - _sum?: Prisma.NestedDecimalFilter<$PrismaModel> - _min?: Prisma.NestedDecimalFilter<$PrismaModel> - _max?: Prisma.NestedDecimalFilter<$PrismaModel> -} - -export type EnumSearchEntityTypeFilter<$PrismaModel = never> = { - equals?: $Enums.SearchEntityType | Prisma.EnumSearchEntityTypeFieldRefInput<$PrismaModel> - in?: $Enums.SearchEntityType[] | Prisma.ListEnumSearchEntityTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.SearchEntityType[] | Prisma.ListEnumSearchEntityTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumSearchEntityTypeFilter<$PrismaModel> | $Enums.SearchEntityType -} - -export type EnumSearchEntityTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.SearchEntityType | Prisma.EnumSearchEntityTypeFieldRefInput<$PrismaModel> - in?: $Enums.SearchEntityType[] | Prisma.ListEnumSearchEntityTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.SearchEntityType[] | Prisma.ListEnumSearchEntityTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumSearchEntityTypeWithAggregatesFilter<$PrismaModel> | $Enums.SearchEntityType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumSearchEntityTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumSearchEntityTypeFilter<$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 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 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 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 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 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 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 NestedEnumLoreTypeFilter<$PrismaModel = never> = { - equals?: $Enums.LoreType | Prisma.EnumLoreTypeFieldRefInput<$PrismaModel> - in?: $Enums.LoreType[] | Prisma.ListEnumLoreTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.LoreType[] | Prisma.ListEnumLoreTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumLoreTypeFilter<$PrismaModel> | $Enums.LoreType -} - -export type NestedEnumLoreStatusFilter<$PrismaModel = never> = { - equals?: $Enums.LoreStatus | Prisma.EnumLoreStatusFieldRefInput<$PrismaModel> - in?: $Enums.LoreStatus[] | Prisma.ListEnumLoreStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.LoreStatus[] | Prisma.ListEnumLoreStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumLoreStatusFilter<$PrismaModel> | $Enums.LoreStatus -} - -export type NestedEnumLoreTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.LoreType | Prisma.EnumLoreTypeFieldRefInput<$PrismaModel> - in?: $Enums.LoreType[] | Prisma.ListEnumLoreTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.LoreType[] | Prisma.ListEnumLoreTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumLoreTypeWithAggregatesFilter<$PrismaModel> | $Enums.LoreType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumLoreTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumLoreTypeFilter<$PrismaModel> -} - -export type NestedEnumLoreStatusWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.LoreStatus | Prisma.EnumLoreStatusFieldRefInput<$PrismaModel> - in?: $Enums.LoreStatus[] | Prisma.ListEnumLoreStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.LoreStatus[] | Prisma.ListEnumLoreStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumLoreStatusWithAggregatesFilter<$PrismaModel> | $Enums.LoreStatus - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumLoreStatusFilter<$PrismaModel> - _max?: Prisma.NestedEnumLoreStatusFilter<$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 NestedEnumProposalTypeFilter<$PrismaModel = never> = { - equals?: $Enums.ProposalType | Prisma.EnumProposalTypeFieldRefInput<$PrismaModel> - in?: $Enums.ProposalType[] | Prisma.ListEnumProposalTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.ProposalType[] | Prisma.ListEnumProposalTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumProposalTypeFilter<$PrismaModel> | $Enums.ProposalType -} - -export type NestedEnumProposalStatusFilter<$PrismaModel = never> = { - equals?: $Enums.ProposalStatus | Prisma.EnumProposalStatusFieldRefInput<$PrismaModel> - in?: $Enums.ProposalStatus[] | Prisma.ListEnumProposalStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.ProposalStatus[] | Prisma.ListEnumProposalStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumProposalStatusFilter<$PrismaModel> | $Enums.ProposalStatus -} - -export type NestedEnumProposalTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.ProposalType | Prisma.EnumProposalTypeFieldRefInput<$PrismaModel> - in?: $Enums.ProposalType[] | Prisma.ListEnumProposalTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.ProposalType[] | Prisma.ListEnumProposalTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumProposalTypeWithAggregatesFilter<$PrismaModel> | $Enums.ProposalType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumProposalTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumProposalTypeFilter<$PrismaModel> -} - -export type NestedEnumProposalStatusWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.ProposalStatus | Prisma.EnumProposalStatusFieldRefInput<$PrismaModel> - in?: $Enums.ProposalStatus[] | Prisma.ListEnumProposalStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.ProposalStatus[] | Prisma.ListEnumProposalStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumProposalStatusWithAggregatesFilter<$PrismaModel> | $Enums.ProposalStatus - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumProposalStatusFilter<$PrismaModel> - _max?: Prisma.NestedEnumProposalStatusFilter<$PrismaModel> -} - -export type NestedEnumVoteChoiceFilter<$PrismaModel = never> = { - equals?: $Enums.VoteChoice | Prisma.EnumVoteChoiceFieldRefInput<$PrismaModel> - in?: $Enums.VoteChoice[] | Prisma.ListEnumVoteChoiceFieldRefInput<$PrismaModel> - notIn?: $Enums.VoteChoice[] | Prisma.ListEnumVoteChoiceFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumVoteChoiceFilter<$PrismaModel> | $Enums.VoteChoice -} - -export type NestedDecimalNullableFilter<$PrismaModel = never> = { - equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null - in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null - notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null - lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - not?: Prisma.NestedDecimalNullableFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null -} - -export type NestedEnumVoteChoiceWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.VoteChoice | Prisma.EnumVoteChoiceFieldRefInput<$PrismaModel> - in?: $Enums.VoteChoice[] | Prisma.ListEnumVoteChoiceFieldRefInput<$PrismaModel> - notIn?: $Enums.VoteChoice[] | Prisma.ListEnumVoteChoiceFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumVoteChoiceWithAggregatesFilter<$PrismaModel> | $Enums.VoteChoice - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumVoteChoiceFilter<$PrismaModel> - _max?: Prisma.NestedEnumVoteChoiceFilter<$PrismaModel> -} - -export type NestedDecimalNullableWithAggregatesFilter<$PrismaModel = never> = { - equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> | null - in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null - notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> | null - lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - not?: Prisma.NestedDecimalNullableWithAggregatesFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string | null - _count?: Prisma.NestedIntNullableFilter<$PrismaModel> - _avg?: Prisma.NestedDecimalNullableFilter<$PrismaModel> - _sum?: Prisma.NestedDecimalNullableFilter<$PrismaModel> - _min?: Prisma.NestedDecimalNullableFilter<$PrismaModel> - _max?: Prisma.NestedDecimalNullableFilter<$PrismaModel> -} - -export type NestedEnumAIReportStatusFilter<$PrismaModel = never> = { - equals?: $Enums.AIReportStatus | Prisma.EnumAIReportStatusFieldRefInput<$PrismaModel> - in?: $Enums.AIReportStatus[] | Prisma.ListEnumAIReportStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.AIReportStatus[] | Prisma.ListEnumAIReportStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumAIReportStatusFilter<$PrismaModel> | $Enums.AIReportStatus -} - -export type NestedEnumAIReportStatusWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.AIReportStatus | Prisma.EnumAIReportStatusFieldRefInput<$PrismaModel> - in?: $Enums.AIReportStatus[] | Prisma.ListEnumAIReportStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.AIReportStatus[] | Prisma.ListEnumAIReportStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumAIReportStatusWithAggregatesFilter<$PrismaModel> | $Enums.AIReportStatus - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumAIReportStatusFilter<$PrismaModel> - _max?: Prisma.NestedEnumAIReportStatusFilter<$PrismaModel> -} - -export type NestedEnumModerationTargetTypeFilter<$PrismaModel = never> = { - equals?: $Enums.ModerationTargetType | Prisma.EnumModerationTargetTypeFieldRefInput<$PrismaModel> - in?: $Enums.ModerationTargetType[] | Prisma.ListEnumModerationTargetTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.ModerationTargetType[] | Prisma.ListEnumModerationTargetTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumModerationTargetTypeFilter<$PrismaModel> | $Enums.ModerationTargetType -} - -export type NestedEnumModerationStatusFilter<$PrismaModel = never> = { - equals?: $Enums.ModerationStatus | Prisma.EnumModerationStatusFieldRefInput<$PrismaModel> - in?: $Enums.ModerationStatus[] | Prisma.ListEnumModerationStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.ModerationStatus[] | Prisma.ListEnumModerationStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumModerationStatusFilter<$PrismaModel> | $Enums.ModerationStatus -} - -export type NestedEnumModerationTargetTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.ModerationTargetType | Prisma.EnumModerationTargetTypeFieldRefInput<$PrismaModel> - in?: $Enums.ModerationTargetType[] | Prisma.ListEnumModerationTargetTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.ModerationTargetType[] | Prisma.ListEnumModerationTargetTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumModerationTargetTypeWithAggregatesFilter<$PrismaModel> | $Enums.ModerationTargetType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumModerationTargetTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumModerationTargetTypeFilter<$PrismaModel> -} - -export type NestedEnumModerationStatusWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.ModerationStatus | Prisma.EnumModerationStatusFieldRefInput<$PrismaModel> - in?: $Enums.ModerationStatus[] | Prisma.ListEnumModerationStatusFieldRefInput<$PrismaModel> - notIn?: $Enums.ModerationStatus[] | Prisma.ListEnumModerationStatusFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumModerationStatusWithAggregatesFilter<$PrismaModel> | $Enums.ModerationStatus - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumModerationStatusFilter<$PrismaModel> - _max?: Prisma.NestedEnumModerationStatusFilter<$PrismaModel> -} - -export type NestedEnumHiveEntityTypeFilter<$PrismaModel = never> = { - equals?: $Enums.HiveEntityType | Prisma.EnumHiveEntityTypeFieldRefInput<$PrismaModel> - in?: $Enums.HiveEntityType[] | Prisma.ListEnumHiveEntityTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.HiveEntityType[] | Prisma.ListEnumHiveEntityTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumHiveEntityTypeFilter<$PrismaModel> | $Enums.HiveEntityType -} - -export type NestedBigIntNullableFilter<$PrismaModel = never> = { - equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> | null - in?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> | null - notIn?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> | null - lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - not?: Prisma.NestedBigIntNullableFilter<$PrismaModel> | bigint | number | null -} - -export type NestedEnumHiveEntityTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.HiveEntityType | Prisma.EnumHiveEntityTypeFieldRefInput<$PrismaModel> - in?: $Enums.HiveEntityType[] | Prisma.ListEnumHiveEntityTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.HiveEntityType[] | Prisma.ListEnumHiveEntityTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumHiveEntityTypeWithAggregatesFilter<$PrismaModel> | $Enums.HiveEntityType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumHiveEntityTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumHiveEntityTypeFilter<$PrismaModel> -} - -export type NestedBigIntNullableWithAggregatesFilter<$PrismaModel = never> = { - equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> | null - in?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> | null - notIn?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> | null - lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - not?: Prisma.NestedBigIntNullableWithAggregatesFilter<$PrismaModel> | bigint | number | null - _count?: Prisma.NestedIntNullableFilter<$PrismaModel> - _avg?: Prisma.NestedFloatNullableFilter<$PrismaModel> - _sum?: Prisma.NestedBigIntNullableFilter<$PrismaModel> - _min?: Prisma.NestedBigIntNullableFilter<$PrismaModel> - _max?: Prisma.NestedBigIntNullableFilter<$PrismaModel> -} - -export type NestedFloatNullableFilter<$PrismaModel = never> = { - equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> | null - in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> | null - notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> | null - lt?: number | Prisma.FloatFieldRefInput<$PrismaModel> - lte?: number | Prisma.FloatFieldRefInput<$PrismaModel> - gt?: number | Prisma.FloatFieldRefInput<$PrismaModel> - gte?: number | Prisma.FloatFieldRefInput<$PrismaModel> - not?: Prisma.NestedFloatNullableFilter<$PrismaModel> | number | null -} - -export type NestedIntNullableWithAggregatesFilter<$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.NestedIntNullableWithAggregatesFilter<$PrismaModel> | number | null - _count?: Prisma.NestedIntNullableFilter<$PrismaModel> - _avg?: Prisma.NestedFloatNullableFilter<$PrismaModel> - _sum?: Prisma.NestedIntNullableFilter<$PrismaModel> - _min?: Prisma.NestedIntNullableFilter<$PrismaModel> - _max?: Prisma.NestedIntNullableFilter<$PrismaModel> -} - -export type NestedBigIntFilter<$PrismaModel = never> = { - equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - in?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> - notIn?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> - lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - not?: Prisma.NestedBigIntFilter<$PrismaModel> | bigint | number -} - -export type NestedEnumHiveEventTypeFilter<$PrismaModel = never> = { - equals?: $Enums.HiveEventType | Prisma.EnumHiveEventTypeFieldRefInput<$PrismaModel> - in?: $Enums.HiveEventType[] | Prisma.ListEnumHiveEventTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.HiveEventType[] | Prisma.ListEnumHiveEventTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumHiveEventTypeFilter<$PrismaModel> | $Enums.HiveEventType -} - -export type NestedBigIntWithAggregatesFilter<$PrismaModel = never> = { - equals?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - in?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> - notIn?: bigint[] | number[] | Prisma.ListBigIntFieldRefInput<$PrismaModel> - lt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - lte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gt?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - gte?: bigint | number | Prisma.BigIntFieldRefInput<$PrismaModel> - not?: Prisma.NestedBigIntWithAggregatesFilter<$PrismaModel> | bigint | number - _count?: Prisma.NestedIntFilter<$PrismaModel> - _avg?: Prisma.NestedFloatFilter<$PrismaModel> - _sum?: Prisma.NestedBigIntFilter<$PrismaModel> - _min?: Prisma.NestedBigIntFilter<$PrismaModel> - _max?: Prisma.NestedBigIntFilter<$PrismaModel> -} - -export type NestedEnumHiveEventTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.HiveEventType | Prisma.EnumHiveEventTypeFieldRefInput<$PrismaModel> - in?: $Enums.HiveEventType[] | Prisma.ListEnumHiveEventTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.HiveEventType[] | Prisma.ListEnumHiveEventTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumHiveEventTypeWithAggregatesFilter<$PrismaModel> | $Enums.HiveEventType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumHiveEventTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumHiveEventTypeFilter<$PrismaModel> -} - -export type NestedEnumRewardTypeFilter<$PrismaModel = never> = { - equals?: $Enums.RewardType | Prisma.EnumRewardTypeFieldRefInput<$PrismaModel> - in?: $Enums.RewardType[] | Prisma.ListEnumRewardTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.RewardType[] | Prisma.ListEnumRewardTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumRewardTypeFilter<$PrismaModel> | $Enums.RewardType -} - -export type NestedDecimalFilter<$PrismaModel = never> = { - equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> - notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> - lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - not?: Prisma.NestedDecimalFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string -} - -export type NestedEnumRewardTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.RewardType | Prisma.EnumRewardTypeFieldRefInput<$PrismaModel> - in?: $Enums.RewardType[] | Prisma.ListEnumRewardTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.RewardType[] | Prisma.ListEnumRewardTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumRewardTypeWithAggregatesFilter<$PrismaModel> | $Enums.RewardType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumRewardTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumRewardTypeFilter<$PrismaModel> -} - -export type NestedDecimalWithAggregatesFilter<$PrismaModel = never> = { - equals?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - in?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> - notIn?: runtime.Decimal[] | runtime.DecimalJsLike[] | number[] | string[] | Prisma.ListDecimalFieldRefInput<$PrismaModel> - lt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - lte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gt?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - gte?: runtime.Decimal | runtime.DecimalJsLike | number | string | Prisma.DecimalFieldRefInput<$PrismaModel> - not?: Prisma.NestedDecimalWithAggregatesFilter<$PrismaModel> | runtime.Decimal | runtime.DecimalJsLike | number | string - _count?: Prisma.NestedIntFilter<$PrismaModel> - _avg?: Prisma.NestedDecimalFilter<$PrismaModel> - _sum?: Prisma.NestedDecimalFilter<$PrismaModel> - _min?: Prisma.NestedDecimalFilter<$PrismaModel> - _max?: Prisma.NestedDecimalFilter<$PrismaModel> -} - -export type NestedEnumSearchEntityTypeFilter<$PrismaModel = never> = { - equals?: $Enums.SearchEntityType | Prisma.EnumSearchEntityTypeFieldRefInput<$PrismaModel> - in?: $Enums.SearchEntityType[] | Prisma.ListEnumSearchEntityTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.SearchEntityType[] | Prisma.ListEnumSearchEntityTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumSearchEntityTypeFilter<$PrismaModel> | $Enums.SearchEntityType -} - -export type NestedEnumSearchEntityTypeWithAggregatesFilter<$PrismaModel = never> = { - equals?: $Enums.SearchEntityType | Prisma.EnumSearchEntityTypeFieldRefInput<$PrismaModel> - in?: $Enums.SearchEntityType[] | Prisma.ListEnumSearchEntityTypeFieldRefInput<$PrismaModel> - notIn?: $Enums.SearchEntityType[] | Prisma.ListEnumSearchEntityTypeFieldRefInput<$PrismaModel> - not?: Prisma.NestedEnumSearchEntityTypeWithAggregatesFilter<$PrismaModel> | $Enums.SearchEntityType - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedEnumSearchEntityTypeFilter<$PrismaModel> - _max?: Prisma.NestedEnumSearchEntityTypeFilter<$PrismaModel> -} - - diff --git a/apps/api/src/generated/prisma/enums.ts b/apps/api/src/generated/prisma/enums.ts deleted file mode 100644 index e4d7972..0000000 --- a/apps/api/src/generated/prisma/enums.ts +++ /dev/null @@ -1,147 +0,0 @@ - -/* !!! 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 LoreType = { - CHARACTER: 'CHARACTER', - LOCATION: 'LOCATION', - FACTION: 'FACTION', - EVENT: 'EVENT', - ARTIFACT: 'ARTIFACT', - HISTORY: 'HISTORY', - RULE: 'RULE', - OTHER: 'OTHER' -} as const - -export type LoreType = (typeof LoreType)[keyof typeof LoreType] - - -export const LoreStatus = { - DRAFT: 'DRAFT', - SUBMITTED: 'SUBMITTED', - APPROVED_FOR_PUBLICATION: 'APPROVED_FOR_PUBLICATION', - PUBLISHED_CANON: 'PUBLISHED_CANON', - ARCHIVED: 'ARCHIVED' -} as const - -export type LoreStatus = (typeof LoreStatus)[keyof typeof LoreStatus] - - -export const ProposalType = { - ADD_LORE: 'ADD_LORE', - UPDATE_LORE: 'UPDATE_LORE', - UPDATE_WORLD_BIBLE: 'UPDATE_WORLD_BIBLE' -} as const - -export type ProposalType = (typeof ProposalType)[keyof typeof ProposalType] - - -export const ProposalStatus = { - DRAFT: 'DRAFT', - SUBMITTED: 'SUBMITTED', - VOTING: 'VOTING', - APPROVED_FOR_PUBLICATION: 'APPROVED_FOR_PUBLICATION', - REJECTED: 'REJECTED', - PUBLISHED: 'PUBLISHED', - WITHDRAWN: 'WITHDRAWN' -} as const - -export type ProposalStatus = (typeof ProposalStatus)[keyof typeof ProposalStatus] - - -export const VoteChoice = { - APPROVE: 'APPROVE', - REJECT: 'REJECT', - ABSTAIN: 'ABSTAIN' -} as const - -export type VoteChoice = (typeof VoteChoice)[keyof typeof VoteChoice] - - -export const AIReportStatus = { - PENDING: 'PENDING', - COMPLETED: 'COMPLETED', - FAILED: 'FAILED' -} as const - -export type AIReportStatus = (typeof AIReportStatus)[keyof typeof AIReportStatus] - - -export const ModerationStatus = { - OPEN: 'OPEN', - IN_REVIEW: 'IN_REVIEW', - RESOLVED: 'RESOLVED', - DISMISSED: 'DISMISSED' -} as const - -export type ModerationStatus = (typeof ModerationStatus)[keyof typeof ModerationStatus] - - -export const ModerationTargetType = { - USER: 'USER', - WORLD: 'WORLD', - WORLD_BIBLE_VERSION: 'WORLD_BIBLE_VERSION', - LORE_ENTRY: 'LORE_ENTRY', - LORE_RELATIONSHIP: 'LORE_RELATIONSHIP', - PROPOSAL: 'PROPOSAL', - APP_VOTE: 'APP_VOTE', - AI_REPORT: 'AI_REPORT', - HIVE_REFERENCE: 'HIVE_REFERENCE', - HIVE_EVENT: 'HIVE_EVENT', - REWARD_RECORD: 'REWARD_RECORD' -} as const - -export type ModerationTargetType = (typeof ModerationTargetType)[keyof typeof ModerationTargetType] - - -export const HiveEntityType = { - WORLD_SEED: 'WORLD_SEED', - WORLD_BIBLE_VERSION: 'WORLD_BIBLE_VERSION', - LORE_ENTRY: 'LORE_ENTRY', - STORY_CHAPTER: 'STORY_CHAPTER', - CANON_DECISION: 'CANON_DECISION', - LORE_RELATIONSHIP: 'LORE_RELATIONSHIP', - METADATA: 'METADATA' -} as const - -export type HiveEntityType = (typeof HiveEntityType)[keyof typeof HiveEntityType] - - -export const HiveEventType = { - POST: 'POST', - COMMENT: 'COMMENT', - CUSTOM_JSON: 'CUSTOM_JSON', - VOTE: 'VOTE', - REWARD: 'REWARD', - BENEFICIARY: 'BENEFICIARY', - OTHER: 'OTHER' -} as const - -export type HiveEventType = (typeof HiveEventType)[keyof typeof HiveEventType] - - -export const RewardType = { - AUTHOR: 'AUTHOR', - CURATION: 'CURATION', - BENEFICIARY: 'BENEFICIARY', - OTHER: 'OTHER' -} as const - -export type RewardType = (typeof RewardType)[keyof typeof RewardType] - - -export const SearchEntityType = { - WORLD: 'WORLD', - WORLD_BIBLE_VERSION: 'WORLD_BIBLE_VERSION', - LORE_ENTRY: 'LORE_ENTRY', - PROPOSAL: 'PROPOSAL' -} as const - -export type SearchEntityType = (typeof SearchEntityType)[keyof typeof SearchEntityType] diff --git a/apps/api/src/generated/prisma/internal/class.ts b/apps/api/src/generated/prisma/internal/class.ts deleted file mode 100644 index 2c71c44..0000000 --- a/apps/api/src/generated/prisma/internal/class.ts +++ /dev/null @@ -1,344 +0,0 @@ - -/* !!! 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 moduleFormat = \"esm\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nenum LoreType {\n CHARACTER\n LOCATION\n FACTION\n EVENT\n ARTIFACT\n HISTORY\n RULE\n OTHER\n}\n\nenum LoreStatus {\n DRAFT\n SUBMITTED\n APPROVED_FOR_PUBLICATION\n PUBLISHED_CANON\n ARCHIVED\n}\n\nenum ProposalType {\n ADD_LORE\n UPDATE_LORE\n UPDATE_WORLD_BIBLE\n}\n\nenum ProposalStatus {\n DRAFT\n SUBMITTED\n VOTING\n APPROVED_FOR_PUBLICATION\n REJECTED\n PUBLISHED\n WITHDRAWN\n}\n\nenum VoteChoice {\n APPROVE\n REJECT\n ABSTAIN\n}\n\nenum AIReportStatus {\n PENDING\n COMPLETED\n FAILED\n}\n\nenum ModerationStatus {\n OPEN\n IN_REVIEW\n RESOLVED\n DISMISSED\n}\n\nenum ModerationTargetType {\n USER\n WORLD\n WORLD_BIBLE_VERSION\n LORE_ENTRY\n LORE_RELATIONSHIP\n PROPOSAL\n APP_VOTE\n AI_REPORT\n HIVE_REFERENCE\n HIVE_EVENT\n REWARD_RECORD\n}\n\nenum HiveEntityType {\n WORLD_SEED\n WORLD_BIBLE_VERSION\n LORE_ENTRY\n STORY_CHAPTER\n CANON_DECISION\n LORE_RELATIONSHIP\n METADATA\n}\n\nenum HiveEventType {\n POST\n COMMENT\n CUSTOM_JSON\n VOTE\n REWARD\n BENEFICIARY\n OTHER\n}\n\nenum RewardType {\n AUTHOR\n CURATION\n BENEFICIARY\n OTHER\n}\n\nenum SearchEntityType {\n WORLD\n WORLD_BIBLE_VERSION\n LORE_ENTRY\n PROPOSAL\n}\n\nmodel User {\n id String @id @default(cuid())\n hiveUsername String @unique\n normalizedHiveUsername String @unique\n displayName String?\n avatarUrl String?\n bio String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n foundedWorlds World[] @relation(\"WorldFounder\")\n bibleVersions WorldBibleVersion[] @relation(\"WorldBibleVersionCreator\")\n loreEntries LoreEntry[] @relation(\"LoreEntryAuthor\")\n proposals Proposal[] @relation(\"ProposalAuthor\")\n votes AppVote[] @relation(\"AppVoteVoter\")\n moderationReports ModerationReport[] @relation(\"ModerationReporter\")\n moderationReviews ModerationReport[] @relation(\"ModerationReviewer\")\n hiveReferences HiveReference[] @relation(\"HiveReferenceAuthor\")\n rewardRecords RewardRecord[]\n rewardSummaries UserRewardSummary[]\n reputationSnapshots UserReputationSnapshot[]\n\n @@index([normalizedHiveUsername])\n}\n\nmodel World {\n id String @id @default(cuid())\n slug String @unique\n title String\n description String\n founderId String\n founder User @relation(\"WorldFounder\", fields: [founderId], references: [id], onDelete: Restrict)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n bibleVersions WorldBibleVersion[]\n loreEntries LoreEntry[]\n loreRelationships LoreRelationship[]\n proposals Proposal[]\n moderationReports ModerationReport[]\n searchIndexes SearchIndex[]\n\n @@index([founderId])\n @@index([createdAt])\n}\n\nmodel WorldBibleVersion {\n id String @id @default(cuid())\n worldId String\n world World @relation(fields: [worldId], references: [id], onDelete: Restrict)\n versionNumber Int\n creatorId String\n creator User @relation(\"WorldBibleVersionCreator\", fields: [creatorId], references: [id], onDelete: Restrict)\n content Json\n changeSummary String?\n publishedAt DateTime?\n hiveReferenceId String? @unique\n /// A local publishedAt value is not proof of canon; verified canon requires an indexed HiveReference.\n hiveReference HiveReference? @relation(fields: [hiveReferenceId], references: [id], onDelete: SetNull)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n proposals Proposal[] @relation(\"ProposalResultingBibleVersion\")\n\n @@unique([worldId, versionNumber])\n @@index([worldId, versionNumber])\n @@index([creatorId])\n}\n\nmodel LoreEntry {\n id String @id @default(cuid())\n worldId String\n world World @relation(fields: [worldId], references: [id], onDelete: Restrict)\n authorId String\n author User @relation(\"LoreEntryAuthor\", fields: [authorId], references: [id], onDelete: Restrict)\n title String\n slug String\n loreType LoreType\n content Json\n status LoreStatus @default(DRAFT)\n publishedAt DateTime?\n hiveReferenceId String? @unique\n /// Published canon must be confirmed through an indexed HiveReference, not only this mutable row.\n hiveReference HiveReference? @relation(fields: [hiveReferenceId], references: [id], onDelete: SetNull)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n outgoingRelations LoreRelationship[] @relation(\"LoreRelationshipSource\")\n incomingRelations LoreRelationship[] @relation(\"LoreRelationshipTarget\")\n targetProposals Proposal[] @relation(\"ProposalTargetLoreEntry\")\n resultingProposals Proposal[] @relation(\"ProposalResultingLoreEntry\")\n\n @@unique([worldId, slug])\n @@index([worldId, status])\n @@index([worldId, loreType])\n @@index([authorId])\n}\n\nmodel LoreRelationship {\n id String @id @default(cuid())\n worldId String\n world World @relation(fields: [worldId], references: [id], onDelete: Restrict)\n sourceId String\n source LoreEntry @relation(\"LoreRelationshipSource\", fields: [sourceId], references: [id], onDelete: Restrict)\n targetId String\n target LoreEntry @relation(\"LoreRelationshipTarget\", fields: [targetId], references: [id], onDelete: Restrict)\n relationType String\n metadata Json?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n /// The API must enforce sourceId != targetId and ensure both entries belong to worldId.\n\n @@unique([worldId, sourceId, targetId, relationType])\n @@index([worldId])\n @@index([sourceId])\n @@index([targetId])\n}\n\nmodel Proposal {\n id String @id @default(cuid())\n worldId String\n world World @relation(fields: [worldId], references: [id], onDelete: Restrict)\n authorId String\n author User @relation(\"ProposalAuthor\", fields: [authorId], references: [id], onDelete: Restrict)\n proposalType ProposalType\n status ProposalStatus @default(DRAFT)\n title String\n summary String\n proposedContent Json\n targetLoreEntryId String?\n targetLoreEntry LoreEntry? @relation(\"ProposalTargetLoreEntry\", fields: [targetLoreEntryId], references: [id], onDelete: SetNull)\n resultingLoreEntryId String?\n resultingLoreEntry LoreEntry? @relation(\"ProposalResultingLoreEntry\", fields: [resultingLoreEntryId], references: [id], onDelete: SetNull)\n resultingBibleVersionId String? @unique\n resultingBibleVersion WorldBibleVersion? @relation(\"ProposalResultingBibleVersion\", fields: [resultingBibleVersionId], references: [id], onDelete: SetNull)\n submittedAt DateTime?\n votingStartedAt DateTime?\n approvedAt DateTime?\n rejectedAt DateTime?\n publishedAt DateTime?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n votes AppVote[]\n aiReports AIReport[]\n moderationReports ModerationReport[]\n\n @@index([worldId, status])\n @@index([authorId])\n @@index([targetLoreEntryId])\n}\n\nmodel AppVote {\n id String @id @default(cuid())\n proposalId String\n proposal Proposal @relation(fields: [proposalId], references: [id], onDelete: Restrict)\n voterId String\n voter User @relation(\"AppVoteVoter\", fields: [voterId], references: [id], onDelete: Restrict)\n choice VoteChoice\n reputationScoreAtVote Decimal? @db.Decimal(20, 4)\n reputationSnapshotId String?\n reputationSnapshot UserReputationSnapshot? @relation(fields: [reputationSnapshotId], references: [id], onDelete: SetNull)\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n @@unique([proposalId, voterId])\n @@index([proposalId])\n @@index([voterId])\n}\n\nmodel AIReport {\n id String @id @default(cuid())\n proposalId String\n proposal Proposal @relation(fields: [proposalId], references: [id], onDelete: Restrict)\n provider String\n model String\n status AIReportStatus @default(PENDING)\n summary String?\n findings Json?\n errorCode String?\n errorMessage String?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n /// AI analysis is advisory and does not determine canon.\n\n @@index([proposalId])\n @@index([status])\n}\n\nmodel ModerationReport {\n id String @id @default(cuid())\n reporterId String\n reporter User @relation(\"ModerationReporter\", fields: [reporterId], references: [id], onDelete: Restrict)\n reviewerId String?\n reviewer User? @relation(\"ModerationReviewer\", fields: [reviewerId], references: [id], onDelete: SetNull)\n worldId String?\n world World? @relation(fields: [worldId], references: [id], onDelete: SetNull)\n proposalId String?\n proposal Proposal? @relation(fields: [proposalId], references: [id], onDelete: SetNull)\n targetType ModerationTargetType\n targetId String\n reason String\n details String?\n status ModerationStatus @default(OPEN)\n reviewedAt DateTime?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n /// Polymorphic target integrity must be enforced by API logic.\n\n @@index([reporterId])\n @@index([reviewerId])\n @@index([worldId, status])\n @@index([proposalId])\n @@index([targetType, targetId])\n}\n\nmodel HiveReference {\n id String @id @default(cuid())\n entityType HiveEntityType\n entityId String\n hiveAuthorUsername String\n authorId String?\n author User? @relation(\"HiveReferenceAuthor\", fields: [authorId], references: [id], onDelete: SetNull)\n permlink String\n transactionId String?\n blockNumber BigInt?\n operationIndex Int?\n publicationMetadata Json?\n publishedAt DateTime\n indexedAt DateTime @default(now())\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n bibleVersion WorldBibleVersion?\n loreEntry LoreEntry?\n rewardRecords RewardRecord[]\n /// Hive is the immutable source of truth; this row is a verified indexed projection.\n\n @@unique([entityType, entityId])\n @@unique([hiveAuthorUsername, permlink])\n @@unique([transactionId, operationIndex])\n @@index([authorId])\n @@index([blockNumber])\n @@index([publishedAt])\n}\n\nmodel HiveEvent {\n id String @id @default(cuid())\n blockNumber BigInt\n transactionId String\n operationIndex Int\n eventType HiveEventType\n blockchainTimestamp DateTime\n payload Json\n processedAt DateTime @default(now())\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n /// Rebuildable indexed Hive operation; the blockchain remains authoritative.\n\n @@unique([transactionId, operationIndex])\n @@index([blockNumber, operationIndex])\n @@index([eventType])\n @@index([blockchainTimestamp])\n}\n\nmodel RewardRecord {\n id String @id @default(cuid())\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Restrict)\n hiveReferenceId String?\n hiveReference HiveReference? @relation(fields: [hiveReferenceId], references: [id], onDelete: SetNull)\n rewardType RewardType\n assetSymbol String\n amount Decimal @db.Decimal(38, 18)\n transactionId String\n operationIndex Int\n blockNumber BigInt\n payoutAt DateTime\n idempotencyKey String @unique\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n /// Indexed financial projection from Hive rewards; not the financial source of truth.\n\n @@index([userId, payoutAt])\n @@index([hiveReferenceId])\n @@index([blockNumber])\n @@index([transactionId, operationIndex])\n}\n\nmodel UserRewardSummary {\n id String @id @default(cuid())\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Restrict)\n assetSymbol String\n totalAmount Decimal @db.Decimal(38, 18)\n lastCalculatedAt DateTime @default(now())\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n /// Derived aggregate rebuildable from RewardRecord rows.\n\n @@unique([userId, assetSymbol])\n @@index([assetSymbol])\n}\n\nmodel UserReputationSnapshot {\n id String @id @default(cuid())\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Restrict)\n score Decimal @db.Decimal(20, 4)\n calculationVersion String\n breakdown Json\n calculatedAt DateTime @default(now())\n createdAt DateTime @default(now())\n appVotes AppVote[]\n /// Application reputation is independent of Hive native reputation.\n\n @@index([userId, calculatedAt])\n @@index([calculationVersion])\n}\n\nmodel SearchIndex {\n id String @id @default(cuid())\n worldId String?\n world World? @relation(fields: [worldId], references: [id], onDelete: Cascade)\n entityType SearchEntityType\n entityId String\n title String\n searchableContent String\n metadata Json?\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n /// Derived PostgreSQL search projection for the MVP; rebuildable from source records.\n\n @@unique([entityType, entityId])\n @@index([worldId, entityType])\n}\n", - "runtimeDataModel": { - "models": {}, - "enums": {}, - "types": {} - }, - "parameterizationSchema": { - "strings": [], - "graph": "" - } -} - -config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"hiveUsername\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"normalizedHiveUsername\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"displayName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"avatarUrl\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"bio\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"foundedWorlds\",\"kind\":\"object\",\"type\":\"World\",\"relationName\":\"WorldFounder\"},{\"name\":\"bibleVersions\",\"kind\":\"object\",\"type\":\"WorldBibleVersion\",\"relationName\":\"WorldBibleVersionCreator\"},{\"name\":\"loreEntries\",\"kind\":\"object\",\"type\":\"LoreEntry\",\"relationName\":\"LoreEntryAuthor\"},{\"name\":\"proposals\",\"kind\":\"object\",\"type\":\"Proposal\",\"relationName\":\"ProposalAuthor\"},{\"name\":\"votes\",\"kind\":\"object\",\"type\":\"AppVote\",\"relationName\":\"AppVoteVoter\"},{\"name\":\"moderationReports\",\"kind\":\"object\",\"type\":\"ModerationReport\",\"relationName\":\"ModerationReporter\"},{\"name\":\"moderationReviews\",\"kind\":\"object\",\"type\":\"ModerationReport\",\"relationName\":\"ModerationReviewer\"},{\"name\":\"hiveReferences\",\"kind\":\"object\",\"type\":\"HiveReference\",\"relationName\":\"HiveReferenceAuthor\"},{\"name\":\"rewardRecords\",\"kind\":\"object\",\"type\":\"RewardRecord\",\"relationName\":\"RewardRecordToUser\"},{\"name\":\"rewardSummaries\",\"kind\":\"object\",\"type\":\"UserRewardSummary\",\"relationName\":\"UserToUserRewardSummary\"},{\"name\":\"reputationSnapshots\",\"kind\":\"object\",\"type\":\"UserReputationSnapshot\",\"relationName\":\"UserToUserReputationSnapshot\"}],\"dbName\":null},\"World\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"slug\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"founderId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"founder\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"WorldFounder\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"bibleVersions\",\"kind\":\"object\",\"type\":\"WorldBibleVersion\",\"relationName\":\"WorldToWorldBibleVersion\"},{\"name\":\"loreEntries\",\"kind\":\"object\",\"type\":\"LoreEntry\",\"relationName\":\"LoreEntryToWorld\"},{\"name\":\"loreRelationships\",\"kind\":\"object\",\"type\":\"LoreRelationship\",\"relationName\":\"LoreRelationshipToWorld\"},{\"name\":\"proposals\",\"kind\":\"object\",\"type\":\"Proposal\",\"relationName\":\"ProposalToWorld\"},{\"name\":\"moderationReports\",\"kind\":\"object\",\"type\":\"ModerationReport\",\"relationName\":\"ModerationReportToWorld\"},{\"name\":\"searchIndexes\",\"kind\":\"object\",\"type\":\"SearchIndex\",\"relationName\":\"SearchIndexToWorld\"}],\"dbName\":null},\"WorldBibleVersion\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"worldId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"world\",\"kind\":\"object\",\"type\":\"World\",\"relationName\":\"WorldToWorldBibleVersion\"},{\"name\":\"versionNumber\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"creatorId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"creator\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"WorldBibleVersionCreator\"},{\"name\":\"content\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"changeSummary\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"publishedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"hiveReferenceId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"hiveReference\",\"kind\":\"object\",\"type\":\"HiveReference\",\"relationName\":\"HiveReferenceToWorldBibleVersion\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"proposals\",\"kind\":\"object\",\"type\":\"Proposal\",\"relationName\":\"ProposalResultingBibleVersion\"}],\"dbName\":null},\"LoreEntry\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"worldId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"world\",\"kind\":\"object\",\"type\":\"World\",\"relationName\":\"LoreEntryToWorld\"},{\"name\":\"authorId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"author\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"LoreEntryAuthor\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"slug\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"loreType\",\"kind\":\"enum\",\"type\":\"LoreType\"},{\"name\":\"content\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"LoreStatus\"},{\"name\":\"publishedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"hiveReferenceId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"hiveReference\",\"kind\":\"object\",\"type\":\"HiveReference\",\"relationName\":\"HiveReferenceToLoreEntry\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"outgoingRelations\",\"kind\":\"object\",\"type\":\"LoreRelationship\",\"relationName\":\"LoreRelationshipSource\"},{\"name\":\"incomingRelations\",\"kind\":\"object\",\"type\":\"LoreRelationship\",\"relationName\":\"LoreRelationshipTarget\"},{\"name\":\"targetProposals\",\"kind\":\"object\",\"type\":\"Proposal\",\"relationName\":\"ProposalTargetLoreEntry\"},{\"name\":\"resultingProposals\",\"kind\":\"object\",\"type\":\"Proposal\",\"relationName\":\"ProposalResultingLoreEntry\"}],\"dbName\":null},\"LoreRelationship\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"worldId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"world\",\"kind\":\"object\",\"type\":\"World\",\"relationName\":\"LoreRelationshipToWorld\"},{\"name\":\"sourceId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"source\",\"kind\":\"object\",\"type\":\"LoreEntry\",\"relationName\":\"LoreRelationshipSource\"},{\"name\":\"targetId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"target\",\"kind\":\"object\",\"type\":\"LoreEntry\",\"relationName\":\"LoreRelationshipTarget\"},{\"name\":\"relationType\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"metadata\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Proposal\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"worldId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"world\",\"kind\":\"object\",\"type\":\"World\",\"relationName\":\"ProposalToWorld\"},{\"name\":\"authorId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"author\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"ProposalAuthor\"},{\"name\":\"proposalType\",\"kind\":\"enum\",\"type\":\"ProposalType\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"ProposalStatus\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"summary\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"proposedContent\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"targetLoreEntryId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"targetLoreEntry\",\"kind\":\"object\",\"type\":\"LoreEntry\",\"relationName\":\"ProposalTargetLoreEntry\"},{\"name\":\"resultingLoreEntryId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"resultingLoreEntry\",\"kind\":\"object\",\"type\":\"LoreEntry\",\"relationName\":\"ProposalResultingLoreEntry\"},{\"name\":\"resultingBibleVersionId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"resultingBibleVersion\",\"kind\":\"object\",\"type\":\"WorldBibleVersion\",\"relationName\":\"ProposalResultingBibleVersion\"},{\"name\":\"submittedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"votingStartedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"approvedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"rejectedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"publishedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"votes\",\"kind\":\"object\",\"type\":\"AppVote\",\"relationName\":\"AppVoteToProposal\"},{\"name\":\"aiReports\",\"kind\":\"object\",\"type\":\"AIReport\",\"relationName\":\"AIReportToProposal\"},{\"name\":\"moderationReports\",\"kind\":\"object\",\"type\":\"ModerationReport\",\"relationName\":\"ModerationReportToProposal\"}],\"dbName\":null},\"AppVote\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"proposalId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"proposal\",\"kind\":\"object\",\"type\":\"Proposal\",\"relationName\":\"AppVoteToProposal\"},{\"name\":\"voterId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"voter\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"AppVoteVoter\"},{\"name\":\"choice\",\"kind\":\"enum\",\"type\":\"VoteChoice\"},{\"name\":\"reputationScoreAtVote\",\"kind\":\"scalar\",\"type\":\"Decimal\"},{\"name\":\"reputationSnapshotId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"reputationSnapshot\",\"kind\":\"object\",\"type\":\"UserReputationSnapshot\",\"relationName\":\"AppVoteToUserReputationSnapshot\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"AIReport\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"proposalId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"proposal\",\"kind\":\"object\",\"type\":\"Proposal\",\"relationName\":\"AIReportToProposal\"},{\"name\":\"provider\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"model\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"AIReportStatus\"},{\"name\":\"summary\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"findings\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"errorCode\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"errorMessage\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"ModerationReport\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"reporterId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"reporter\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"ModerationReporter\"},{\"name\":\"reviewerId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"reviewer\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"ModerationReviewer\"},{\"name\":\"worldId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"world\",\"kind\":\"object\",\"type\":\"World\",\"relationName\":\"ModerationReportToWorld\"},{\"name\":\"proposalId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"proposal\",\"kind\":\"object\",\"type\":\"Proposal\",\"relationName\":\"ModerationReportToProposal\"},{\"name\":\"targetType\",\"kind\":\"enum\",\"type\":\"ModerationTargetType\"},{\"name\":\"targetId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"reason\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"details\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"ModerationStatus\"},{\"name\":\"reviewedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"HiveReference\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"entityType\",\"kind\":\"enum\",\"type\":\"HiveEntityType\"},{\"name\":\"entityId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"hiveAuthorUsername\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"authorId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"author\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"HiveReferenceAuthor\"},{\"name\":\"permlink\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"transactionId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"blockNumber\",\"kind\":\"scalar\",\"type\":\"BigInt\"},{\"name\":\"operationIndex\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"publicationMetadata\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"publishedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"indexedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"bibleVersion\",\"kind\":\"object\",\"type\":\"WorldBibleVersion\",\"relationName\":\"HiveReferenceToWorldBibleVersion\"},{\"name\":\"loreEntry\",\"kind\":\"object\",\"type\":\"LoreEntry\",\"relationName\":\"HiveReferenceToLoreEntry\"},{\"name\":\"rewardRecords\",\"kind\":\"object\",\"type\":\"RewardRecord\",\"relationName\":\"HiveReferenceToRewardRecord\"}],\"dbName\":null},\"HiveEvent\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"blockNumber\",\"kind\":\"scalar\",\"type\":\"BigInt\"},{\"name\":\"transactionId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"operationIndex\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"eventType\",\"kind\":\"enum\",\"type\":\"HiveEventType\"},{\"name\":\"blockchainTimestamp\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"payload\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"processedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"RewardRecord\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"RewardRecordToUser\"},{\"name\":\"hiveReferenceId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"hiveReference\",\"kind\":\"object\",\"type\":\"HiveReference\",\"relationName\":\"HiveReferenceToRewardRecord\"},{\"name\":\"rewardType\",\"kind\":\"enum\",\"type\":\"RewardType\"},{\"name\":\"assetSymbol\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"amount\",\"kind\":\"scalar\",\"type\":\"Decimal\"},{\"name\":\"transactionId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"operationIndex\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"blockNumber\",\"kind\":\"scalar\",\"type\":\"BigInt\"},{\"name\":\"payoutAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"idempotencyKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"UserRewardSummary\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToUserRewardSummary\"},{\"name\":\"assetSymbol\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"totalAmount\",\"kind\":\"scalar\",\"type\":\"Decimal\"},{\"name\":\"lastCalculatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"UserReputationSnapshot\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToUserReputationSnapshot\"},{\"name\":\"score\",\"kind\":\"scalar\",\"type\":\"Decimal\"},{\"name\":\"calculationVersion\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"breakdown\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"calculatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"appVotes\",\"kind\":\"object\",\"type\":\"AppVote\",\"relationName\":\"AppVoteToUserReputationSnapshot\"}],\"dbName\":null},\"SearchIndex\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"worldId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"world\",\"kind\":\"object\",\"type\":\"World\",\"relationName\":\"SearchIndexToWorld\"},{\"name\":\"entityType\",\"kind\":\"enum\",\"type\":\"SearchEntityType\"},{\"name\":\"entityId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"searchableContent\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"metadata\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") -config.parameterizationSchema = { - strings: JSON.parse("[\"where\",\"orderBy\",\"cursor\",\"founder\",\"world\",\"creator\",\"author\",\"bibleVersion\",\"hiveReference\",\"source\",\"target\",\"outgoingRelations\",\"incomingRelations\",\"targetLoreEntry\",\"resultingLoreEntry\",\"resultingBibleVersion\",\"proposal\",\"voter\",\"user\",\"appVotes\",\"_count\",\"reputationSnapshot\",\"votes\",\"aiReports\",\"reporter\",\"reviewer\",\"moderationReports\",\"targetProposals\",\"resultingProposals\",\"loreEntry\",\"rewardRecords\",\"proposals\",\"bibleVersions\",\"loreEntries\",\"loreRelationships\",\"searchIndexes\",\"foundedWorlds\",\"moderationReviews\",\"hiveReferences\",\"rewardSummaries\",\"reputationSnapshots\",\"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\",\"World.findUnique\",\"World.findUniqueOrThrow\",\"World.findFirst\",\"World.findFirstOrThrow\",\"World.findMany\",\"World.createOne\",\"World.createMany\",\"World.createManyAndReturn\",\"World.updateOne\",\"World.updateMany\",\"World.updateManyAndReturn\",\"World.upsertOne\",\"World.deleteOne\",\"World.deleteMany\",\"World.groupBy\",\"World.aggregate\",\"WorldBibleVersion.findUnique\",\"WorldBibleVersion.findUniqueOrThrow\",\"WorldBibleVersion.findFirst\",\"WorldBibleVersion.findFirstOrThrow\",\"WorldBibleVersion.findMany\",\"WorldBibleVersion.createOne\",\"WorldBibleVersion.createMany\",\"WorldBibleVersion.createManyAndReturn\",\"WorldBibleVersion.updateOne\",\"WorldBibleVersion.updateMany\",\"WorldBibleVersion.updateManyAndReturn\",\"WorldBibleVersion.upsertOne\",\"WorldBibleVersion.deleteOne\",\"WorldBibleVersion.deleteMany\",\"_avg\",\"_sum\",\"WorldBibleVersion.groupBy\",\"WorldBibleVersion.aggregate\",\"LoreEntry.findUnique\",\"LoreEntry.findUniqueOrThrow\",\"LoreEntry.findFirst\",\"LoreEntry.findFirstOrThrow\",\"LoreEntry.findMany\",\"LoreEntry.createOne\",\"LoreEntry.createMany\",\"LoreEntry.createManyAndReturn\",\"LoreEntry.updateOne\",\"LoreEntry.updateMany\",\"LoreEntry.updateManyAndReturn\",\"LoreEntry.upsertOne\",\"LoreEntry.deleteOne\",\"LoreEntry.deleteMany\",\"LoreEntry.groupBy\",\"LoreEntry.aggregate\",\"LoreRelationship.findUnique\",\"LoreRelationship.findUniqueOrThrow\",\"LoreRelationship.findFirst\",\"LoreRelationship.findFirstOrThrow\",\"LoreRelationship.findMany\",\"LoreRelationship.createOne\",\"LoreRelationship.createMany\",\"LoreRelationship.createManyAndReturn\",\"LoreRelationship.updateOne\",\"LoreRelationship.updateMany\",\"LoreRelationship.updateManyAndReturn\",\"LoreRelationship.upsertOne\",\"LoreRelationship.deleteOne\",\"LoreRelationship.deleteMany\",\"LoreRelationship.groupBy\",\"LoreRelationship.aggregate\",\"Proposal.findUnique\",\"Proposal.findUniqueOrThrow\",\"Proposal.findFirst\",\"Proposal.findFirstOrThrow\",\"Proposal.findMany\",\"Proposal.createOne\",\"Proposal.createMany\",\"Proposal.createManyAndReturn\",\"Proposal.updateOne\",\"Proposal.updateMany\",\"Proposal.updateManyAndReturn\",\"Proposal.upsertOne\",\"Proposal.deleteOne\",\"Proposal.deleteMany\",\"Proposal.groupBy\",\"Proposal.aggregate\",\"AppVote.findUnique\",\"AppVote.findUniqueOrThrow\",\"AppVote.findFirst\",\"AppVote.findFirstOrThrow\",\"AppVote.findMany\",\"AppVote.createOne\",\"AppVote.createMany\",\"AppVote.createManyAndReturn\",\"AppVote.updateOne\",\"AppVote.updateMany\",\"AppVote.updateManyAndReturn\",\"AppVote.upsertOne\",\"AppVote.deleteOne\",\"AppVote.deleteMany\",\"AppVote.groupBy\",\"AppVote.aggregate\",\"AIReport.findUnique\",\"AIReport.findUniqueOrThrow\",\"AIReport.findFirst\",\"AIReport.findFirstOrThrow\",\"AIReport.findMany\",\"AIReport.createOne\",\"AIReport.createMany\",\"AIReport.createManyAndReturn\",\"AIReport.updateOne\",\"AIReport.updateMany\",\"AIReport.updateManyAndReturn\",\"AIReport.upsertOne\",\"AIReport.deleteOne\",\"AIReport.deleteMany\",\"AIReport.groupBy\",\"AIReport.aggregate\",\"ModerationReport.findUnique\",\"ModerationReport.findUniqueOrThrow\",\"ModerationReport.findFirst\",\"ModerationReport.findFirstOrThrow\",\"ModerationReport.findMany\",\"ModerationReport.createOne\",\"ModerationReport.createMany\",\"ModerationReport.createManyAndReturn\",\"ModerationReport.updateOne\",\"ModerationReport.updateMany\",\"ModerationReport.updateManyAndReturn\",\"ModerationReport.upsertOne\",\"ModerationReport.deleteOne\",\"ModerationReport.deleteMany\",\"ModerationReport.groupBy\",\"ModerationReport.aggregate\",\"HiveReference.findUnique\",\"HiveReference.findUniqueOrThrow\",\"HiveReference.findFirst\",\"HiveReference.findFirstOrThrow\",\"HiveReference.findMany\",\"HiveReference.createOne\",\"HiveReference.createMany\",\"HiveReference.createManyAndReturn\",\"HiveReference.updateOne\",\"HiveReference.updateMany\",\"HiveReference.updateManyAndReturn\",\"HiveReference.upsertOne\",\"HiveReference.deleteOne\",\"HiveReference.deleteMany\",\"HiveReference.groupBy\",\"HiveReference.aggregate\",\"HiveEvent.findUnique\",\"HiveEvent.findUniqueOrThrow\",\"HiveEvent.findFirst\",\"HiveEvent.findFirstOrThrow\",\"HiveEvent.findMany\",\"HiveEvent.createOne\",\"HiveEvent.createMany\",\"HiveEvent.createManyAndReturn\",\"HiveEvent.updateOne\",\"HiveEvent.updateMany\",\"HiveEvent.updateManyAndReturn\",\"HiveEvent.upsertOne\",\"HiveEvent.deleteOne\",\"HiveEvent.deleteMany\",\"HiveEvent.groupBy\",\"HiveEvent.aggregate\",\"RewardRecord.findUnique\",\"RewardRecord.findUniqueOrThrow\",\"RewardRecord.findFirst\",\"RewardRecord.findFirstOrThrow\",\"RewardRecord.findMany\",\"RewardRecord.createOne\",\"RewardRecord.createMany\",\"RewardRecord.createManyAndReturn\",\"RewardRecord.updateOne\",\"RewardRecord.updateMany\",\"RewardRecord.updateManyAndReturn\",\"RewardRecord.upsertOne\",\"RewardRecord.deleteOne\",\"RewardRecord.deleteMany\",\"RewardRecord.groupBy\",\"RewardRecord.aggregate\",\"UserRewardSummary.findUnique\",\"UserRewardSummary.findUniqueOrThrow\",\"UserRewardSummary.findFirst\",\"UserRewardSummary.findFirstOrThrow\",\"UserRewardSummary.findMany\",\"UserRewardSummary.createOne\",\"UserRewardSummary.createMany\",\"UserRewardSummary.createManyAndReturn\",\"UserRewardSummary.updateOne\",\"UserRewardSummary.updateMany\",\"UserRewardSummary.updateManyAndReturn\",\"UserRewardSummary.upsertOne\",\"UserRewardSummary.deleteOne\",\"UserRewardSummary.deleteMany\",\"UserRewardSummary.groupBy\",\"UserRewardSummary.aggregate\",\"UserReputationSnapshot.findUnique\",\"UserReputationSnapshot.findUniqueOrThrow\",\"UserReputationSnapshot.findFirst\",\"UserReputationSnapshot.findFirstOrThrow\",\"UserReputationSnapshot.findMany\",\"UserReputationSnapshot.createOne\",\"UserReputationSnapshot.createMany\",\"UserReputationSnapshot.createManyAndReturn\",\"UserReputationSnapshot.updateOne\",\"UserReputationSnapshot.updateMany\",\"UserReputationSnapshot.updateManyAndReturn\",\"UserReputationSnapshot.upsertOne\",\"UserReputationSnapshot.deleteOne\",\"UserReputationSnapshot.deleteMany\",\"UserReputationSnapshot.groupBy\",\"UserReputationSnapshot.aggregate\",\"SearchIndex.findUnique\",\"SearchIndex.findUniqueOrThrow\",\"SearchIndex.findFirst\",\"SearchIndex.findFirstOrThrow\",\"SearchIndex.findMany\",\"SearchIndex.createOne\",\"SearchIndex.createMany\",\"SearchIndex.createManyAndReturn\",\"SearchIndex.updateOne\",\"SearchIndex.updateMany\",\"SearchIndex.updateManyAndReturn\",\"SearchIndex.upsertOne\",\"SearchIndex.deleteOne\",\"SearchIndex.deleteMany\",\"SearchIndex.groupBy\",\"SearchIndex.aggregate\",\"AND\",\"OR\",\"NOT\",\"id\",\"worldId\",\"SearchEntityType\",\"entityType\",\"entityId\",\"title\",\"searchableContent\",\"metadata\",\"createdAt\",\"updatedAt\",\"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\",\"userId\",\"score\",\"calculationVersion\",\"breakdown\",\"calculatedAt\",\"assetSymbol\",\"totalAmount\",\"lastCalculatedAt\",\"hiveReferenceId\",\"RewardType\",\"rewardType\",\"amount\",\"transactionId\",\"operationIndex\",\"blockNumber\",\"payoutAt\",\"idempotencyKey\",\"HiveEventType\",\"eventType\",\"blockchainTimestamp\",\"payload\",\"processedAt\",\"transactionId_operationIndex\",\"HiveEntityType\",\"hiveAuthorUsername\",\"authorId\",\"permlink\",\"publicationMetadata\",\"publishedAt\",\"indexedAt\",\"reporterId\",\"reviewerId\",\"proposalId\",\"ModerationTargetType\",\"targetType\",\"targetId\",\"reason\",\"details\",\"ModerationStatus\",\"status\",\"reviewedAt\",\"provider\",\"model\",\"AIReportStatus\",\"summary\",\"findings\",\"errorCode\",\"errorMessage\",\"voterId\",\"VoteChoice\",\"choice\",\"reputationScoreAtVote\",\"reputationSnapshotId\",\"ProposalType\",\"proposalType\",\"ProposalStatus\",\"proposedContent\",\"targetLoreEntryId\",\"resultingLoreEntryId\",\"resultingBibleVersionId\",\"submittedAt\",\"votingStartedAt\",\"approvedAt\",\"rejectedAt\",\"sourceId\",\"relationType\",\"slug\",\"LoreType\",\"loreType\",\"content\",\"LoreStatus\",\"versionNumber\",\"creatorId\",\"changeSummary\",\"description\",\"founderId\",\"hiveUsername\",\"normalizedHiveUsername\",\"displayName\",\"avatarUrl\",\"bio\",\"every\",\"some\",\"none\",\"userId_assetSymbol\",\"entityType_entityId\",\"hiveAuthorUsername_permlink\",\"worldId_slug\",\"proposalId_voterId\",\"worldId_sourceId_targetId_relationType\",\"worldId_versionNumber\",\"is\",\"isNot\",\"connectOrCreate\",\"upsert\",\"createMany\",\"set\",\"disconnect\",\"delete\",\"connect\",\"updateMany\",\"deleteMany\",\"increment\",\"decrement\",\"multiply\",\"divide\"]"), - graph: "nQqOAfABFhYAALYEACAaAADlBAAgHgAAxQQAIB8AANIEACAgAADrBAAgIQAA7AQAICQAAOoEACAlAADlBAAgJgAA7QQAICcAAO4EACAoAADvBAAgoQIAAOkEADCiAgAADQAQowIAAOkEADCkAgEAAAABrAJAAP8DACGtAkAA_wMAIYsDAQAAAAGMAwEAAAABjQMBAL4EACGOAwEAvgQAIY8DAQC-BAAhAQAAAAEAIBEDAAC1BAAgGgAA5QQAIB8AANIEACAgAADrBAAgIQAA7AQAICIAANEEACAjAADzBAAgoQIAAPIEADCiAgAAAwAQowIAAPIEADCkAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIYEDAQD7AwAhiQMBAPsDACGKAwEA-wMAIQcDAADoCAAgGgAA4wgAIB8AAOEIACAgAADfCAAgIQAA4AgAICIAAO0IACAjAADxCAAgEQMAALUEACAaAADlBAAgHwAA0gQAICAAAOsEACAhAADsBAAgIgAA0QQAICMAAPMEACChAgAA8gQAMKICAAADABCjAgAA8gQAMKQCAQAAAAGpAgEA-wMAIawCQAD_AwAhrQJAAP8DACGBAwEAAAABiQMBAPsDACGKAwEA-wMAIQMAAAADACABAAAEADACAAAFACARBAAAzwQAIAUAALUEACAIAADQBAAgHwAA0gQAIKECAADxBAAwogIAAAcAEKMCAADxBAAwpAIBAPsDACGlAgEA-wMAIawCQAD_AwAhrQJAAP8DACHHAgEAvgQAIdsCQADOBAAhhAMAAIAEACCGAwIA_QMAIYcDAQD7AwAhiAMBAL4EACEHBAAA6wgAIAUAAOgIACAIAADsCAAgHwAA4QgAIMcCAAD0BAAg2wIAAPQEACCIAwAA9AQAIBIEAADPBAAgBQAAtQQAIAgAANAEACAfAADSBAAgoQIAAPEEADCiAgAABwAQowIAAPEEADCkAgEAAAABpQIBAPsDACGsAkAA_wMAIa0CQAD_AwAhxwIBAAAAAdsCQADOBAAhhAMAAIAEACCGAwIA_QMAIYcDAQD7AwAhiAMBAL4EACGZAwAA8AQAIAMAAAAHACABAAAIADACAAAJACAVBgAAwgQAIAcAAMMEACAdAADEBAAgHgAAxQQAIKECAAC8BAAwogIAAAsAEKMCAAC8BAAwpAIBAPsDACGnAgAAvQTXAiKoAgEA-wMAIawCQAD_AwAhrQJAAP8DACHLAgEAvgQAIcwCAgDABAAhzQIEAL8EACHXAgEA-wMAIdgCAQC-BAAh2QIBAPsDACHaAgAAwQQAINsCQAD_AwAh3AJAAP8DACEBAAAACwAgFhYAALYEACAaAADlBAAgHgAAxQQAIB8AANIEACAgAADrBAAgIQAA7AQAICQAAOoEACAlAADlBAAgJgAA7QQAICcAAO4EACAoAADvBAAgoQIAAOkEADCiAgAADQAQowIAAOkEADCkAgEA-wMAIawCQAD_AwAhrQJAAP8DACGLAwEA-wMAIYwDAQD7AwAhjQMBAL4EACGOAwEAvgQAIY8DAQC-BAAhAQAAAA0AIAEAAAAHACAWBAAAzwQAIAYAALUEACAIAADQBAAgCwAA0QQAIAwAANEEACAbAADSBAAgHAAA0gQAIKECAADLBAAwogIAABAAEKMCAADLBAAwpAIBAPsDACGlAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIccCAQC-BAAh2AIBAPsDACHbAkAAzgQAIeYCAADNBIYDIoEDAQD7AwAhgwMAAMwEgwMihAMAAIAEACABAAAAEAAgAQAAAAsAIA4EAADPBAAgCQAA6AQAIAoAAOgEACChAgAA5wQAMKICAAATABCjAgAA5wQAMKQCAQD7AwAhpQIBAPsDACGrAgAAwQQAIKwCQAD_AwAhrQJAAP8DACHiAgEA-wMAIf8CAQD7AwAhgAMBAPsDACEEBAAA6wgAIAkAAOoIACAKAADqCAAgqwIAAPQEACAPBAAAzwQAIAkAAOgEACAKAADoBAAgoQIAAOcEADCiAgAAEwAQowIAAOcEADCkAgEAAAABpQIBAPsDACGrAgAAwQQAIKwCQAD_AwAhrQJAAP8DACHiAgEA-wMAIf8CAQD7AwAhgAMBAPsDACGYAwAA5gQAIAMAAAATACABAAAUADACAAAVACADAAAAEwAgAQAAFAAwAgAAFQAgHQQAAM8EACAGAAC1BAAgDQAAxAQAIA4AAMQEACAPAADDBAAgFgAAtgQAIBcAAOQEACAaAADlBAAgoQIAAOEEADCiAgAAGAAQowIAAOEEADCkAgEA-wMAIaUCAQD7AwAhqQIBAPsDACGsAkAA_wMAIa0CQAD_AwAh2AIBAPsDACHbAkAAzgQAIeYCAADjBPcCIusCAQD7AwAh9QIAAOIE9QIi9wIAAIAEACD4AgEAvgQAIfkCAQC-BAAh-gIBAL4EACH7AkAAzgQAIfwCQADOBAAh_QJAAM4EACH-AkAAzgQAIRAEAADrCAAgBgAA6AgAIA0AAOoIACAOAADqCAAgDwAA6QgAIBYAAOIIACAXAADwCAAgGgAA4wgAINsCAAD0BAAg-AIAAPQEACD5AgAA9AQAIPoCAAD0BAAg-wIAAPQEACD8AgAA9AQAIP0CAAD0BAAg_gIAAPQEACAdBAAAzwQAIAYAALUEACANAADEBAAgDgAAxAQAIA8AAMMEACAWAAC2BAAgFwAA5AQAIBoAAOUEACChAgAA4QQAMKICAAAYABCjAgAA4QQAMKQCAQAAAAGlAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIdgCAQD7AwAh2wJAAM4EACHmAgAA4wT3AiLrAgEA-wMAIfUCAADiBPUCIvcCAACABAAg-AIBAL4EACH5AgEAvgQAIfoCAQAAAAH7AkAAzgQAIfwCQADOBAAh_QJAAM4EACH-AkAAzgQAIQMAAAAYACABAAAZADACAAAaACABAAAAEAAgAQAAABAAIAEAAAAHACAOEAAA2wQAIBEAALUEACAVAADgBAAgoQIAAN0EADCiAgAAHwAQowIAAN0EADCkAgEA-wMAIawCQAD_AwAhrQJAAP8DACHfAgEA-wMAIe8CAQD7AwAh8QIAAN4E8QIi8gIQAN8EACHzAgEAvgQAIQUQAADuCAAgEQAA6AgAIBUAAO8IACDyAgAA9AQAIPMCAAD0BAAgDxAAANsEACARAAC1BAAgFQAA4AQAIKECAADdBAAwogIAAB8AEKMCAADdBAAwpAIBAAAAAawCQAD_AwAhrQJAAP8DACHfAgEA-wMAIe8CAQD7AwAh8QIAAN4E8QIi8gIQAN8EACHzAgEAvgQAIZcDAADcBAAgAwAAAB8AIAEAACAAMAIAACEAIAwSAAC1BAAgEwAAtgQAIKECAACzBAAwogIAACMAEKMCAACzBAAwpAIBAPsDACGsAkAA_wMAIb8CAQD7AwAhwAIQALQEACHBAgEA-wMAIcICAACABAAgwwJAAP8DACEBAAAAIwAgAwAAAB8AIAEAACAAMAIAACEAIAEAAAAfACAPEAAA2wQAIKECAADZBAAwogIAACcAEKMCAADZBAAwpAIBAPsDACGsAkAA_wMAIa0CQAD_AwAh3wIBAPsDACHmAgAA2gTrAiLoAgEA-wMAIekCAQD7AwAh6wIBAL4EACHsAgAAwQQAIO0CAQC-BAAh7gIBAL4EACEFEAAA7ggAIOsCAAD0BAAg7AIAAPQEACDtAgAA9AQAIO4CAAD0BAAgDxAAANsEACChAgAA2QQAMKICAAAnABCjAgAA2QQAMKQCAQAAAAGsAkAA_wMAIa0CQAD_AwAh3wIBAPsDACHmAgAA2gTrAiLoAgEA-wMAIekCAQD7AwAh6wIBAL4EACHsAgAAwQQAIO0CAQC-BAAh7gIBAL4EACEDAAAAJwAgAQAAKAAwAgAAKQAgFAQAAMkEACAQAADYBAAgGAAAtQQAIBkAAMIEACChAgAA1QQAMKICAAArABCjAgAA1QQAMKQCAQD7AwAhpQIBAL4EACGsAkAA_wMAIa0CQAD_AwAh3QIBAPsDACHeAgEAvgQAId8CAQC-BAAh4QIAANYE4QIi4gIBAPsDACHjAgEA-wMAIeQCAQC-BAAh5gIAANcE5gIi5wJAAM4EACEJBAAA6wgAIBAAAO4IACAYAADoCAAgGQAA6AgAIKUCAAD0BAAg3gIAAPQEACDfAgAA9AQAIOQCAAD0BAAg5wIAAPQEACAUBAAAyQQAIBAAANgEACAYAAC1BAAgGQAAwgQAIKECAADVBAAwogIAACsAEKMCAADVBAAwpAIBAAAAAaUCAQC-BAAhrAJAAP8DACGtAkAA_wMAId0CAQD7AwAh3gIBAL4EACHfAgEAvgQAIeECAADWBOECIuICAQD7AwAh4wIBAPsDACHkAgEAvgQAIeYCAADXBOYCIucCQADOBAAhAwAAACsAIAEAACwAMAIAAC0AIAEAAAANACABAAAAAwAgAQAAABgAIAEAAAAfACABAAAAJwAgAQAAACsAIAMAAAAYACABAAAZADACAAAaACABAAAAEwAgAQAAABMAIAEAAAAYACABAAAAGAAgEggAANAEACASAAC1BAAgoQIAANMEADCiAgAAOgAQowIAANMEADCkAgEA-wMAIawCQAD_AwAhrQJAAP8DACG_AgEA-wMAIcQCAQD7AwAhxwIBAL4EACHJAgAA1ATJAiLKAhAAtAQAIcsCAQD7AwAhzAICAP0DACHNAgQA_AMAIc4CQAD_AwAhzwIBAPsDACEDCAAA7AgAIBIAAOgIACDHAgAA9AQAIBIIAADQBAAgEgAAtQQAIKECAADTBAAwogIAADoAEKMCAADTBAAwpAIBAAAAAawCQAD_AwAhrQJAAP8DACG_AgEA-wMAIcQCAQD7AwAhxwIBAL4EACHJAgAA1ATJAiLKAhAAtAQAIcsCAQD7AwAhzAICAP0DACHNAgQA_AMAIc4CQAD_AwAhzwIBAAAAAQMAAAA6ACABAAA7ADACAAA8ACABAAAACwAgAQAAADoAIAMAAAAYACABAAAZADACAAAaACABAAAAGAAgCQQAAOsIACAGAADoCAAgCAAA7AgAIAsAAO0IACAMAADtCAAgGwAA4QgAIBwAAOEIACDHAgAA9AQAINsCAAD0BAAgFwQAAM8EACAGAAC1BAAgCAAA0AQAIAsAANEEACAMAADRBAAgGwAA0gQAIBwAANIEACChAgAAywQAMKICAAAQABCjAgAAywQAMKQCAQAAAAGlAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIccCAQAAAAHYAgEA-wMAIdsCQADOBAAh5gIAAM0EhgMigQMBAPsDACGDAwAAzASDAyKEAwAAgAQAIJYDAADKBAAgAwAAABAAIAEAAEIAMAIAAEMAIAMAAAATACABAAAUADACAAAVACADAAAAGAAgAQAAGQAwAgAAGgAgAwAAACsAIAEAACwAMAIAAC0AIA0EAADJBAAgoQIAAMcEADCiAgAASAAQowIAAMcEADCkAgEA-wMAIaUCAQC-BAAhpwIAAMgEpwIiqAIBAPsDACGpAgEA-wMAIaoCAQD7AwAhqwIAAMEEACCsAkAA_wMAIa0CQAD_AwAhAwQAAOsIACClAgAA9AQAIKsCAAD0BAAgDgQAAMkEACChAgAAxwQAMKICAABIABCjAgAAxwQAMKQCAQAAAAGlAgEAvgQAIacCAADIBKcCIqgCAQD7AwAhqQIBAPsDACGqAgEA-wMAIasCAADBBAAgrAJAAP8DACGtAkAA_wMAIZQDAADGBAAgAwAAAEgAIAEAAEkAMAIAAEoAIAEAAAADACABAAAABwAgAQAAABAAIAEAAAATACABAAAAGAAgAQAAACsAIAEAAABIACADAAAABwAgAQAACAAwAgAACQAgAwAAABAAIAEAAEIAMAIAAEMAIAMAAAAYACABAAAZADACAAAaACADAAAAHwAgAQAAIAAwAgAAIQAgAwAAACsAIAEAACwAMAIAAC0AIAMAAAArACABAAAsADACAAAtACAJBgAA6AgAIAcAAOkIACAdAADqCAAgHgAA5QgAIMsCAAD0BAAgzAIAAPQEACDNAgAA9AQAINgCAAD0BAAg2gIAAPQEACAYBgAAwgQAIAcAAMMEACAdAADEBAAgHgAAxQQAIKECAAC8BAAwogIAAAsAEKMCAAC8BAAwpAIBAAAAAacCAAC9BNcCIqgCAQD7AwAhrAJAAP8DACGtAkAA_wMAIcsCAQC-BAAhzAICAMAEACHNAgQAvwQAIdUCAAC7BAAg1wIBAPsDACHYAgEAvgQAIdkCAQD7AwAh2gIAAMEEACDbAkAA_wMAIdwCQAD_AwAhlAMAALkEACCVAwAAugQAIAMAAAALACABAABZADACAABaACADAAAAOgAgAQAAOwAwAgAAPAAgCxIAALUEACChAgAAuAQAMKICAABdABCjAgAAuAQAMKQCAQD7AwAhrAJAAP8DACGtAkAA_wMAIb8CAQD7AwAhxAIBAPsDACHFAhAAtAQAIcYCQAD_AwAhARIAAOgIACAMEgAAtQQAIKECAAC4BAAwogIAAF0AEKMCAAC4BAAwpAIBAAAAAawCQAD_AwAhrQJAAP8DACG_AgEA-wMAIcQCAQD7AwAhxQIQALQEACHGAkAA_wMAIZMDAAC3BAAgAwAAAF0AIAEAAF4AMAIAAF8AIAISAADoCAAgEwAA4ggAIAwSAAC1BAAgEwAAtgQAIKECAACzBAAwogIAACMAEKMCAACzBAAwpAIBAAAAAawCQAD_AwAhvwIBAPsDACHAAhAAtAQAIcECAQD7AwAhwgIAAIAEACDDAkAA_wMAIQMAAAAjACABAABhADACAABiACABAAAAAwAgAQAAAAcAIAEAAAAQACABAAAAGAAgAQAAAB8AIAEAAAArACABAAAAKwAgAQAAAAsAIAEAAAA6ACABAAAAXQAgAQAAACMAIAEAAAABACAOFgAA4ggAIBoAAOMIACAeAADlCAAgHwAA4QgAICAAAN8IACAhAADgCAAgJAAA3ggAICUAAOMIACAmAADkCAAgJwAA5ggAICgAAOcIACCNAwAA9AQAII4DAAD0BAAgjwMAAPQEACADAAAADQAgAQAAcAAwAgAAAQAgAwAAAA0AIAEAAHAAMAIAAAEAIAMAAAANACABAABwADACAAABACATFgAA1wgAIBoAANgIACAeAADbCAAgHwAA1ggAICAAANQIACAhAADVCAAgJAAA0wgAICUAANkIACAmAADaCAAgJwAA3AgAICgAAN0IACCkAgEAAAABrAJAAAAAAa0CQAAAAAGLAwEAAAABjAMBAAAAAY0DAQAAAAGOAwEAAAABjwMBAAAAAQEuAAB0ACAIpAIBAAAAAawCQAAAAAGtAkAAAAABiwMBAAAAAYwDAQAAAAGNAwEAAAABjgMBAAAAAY8DAQAAAAEBLgAAdgAwAS4AAHYAMBMWAADdBwAgGgAA3gcAIB4AAOEHACAfAADcBwAgIAAA2gcAICEAANsHACAkAADZBwAgJQAA3wcAICYAAOAHACAnAADiBwAgKAAA4wcAIKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIYsDAQD4BAAhjAMBAPgEACGNAwEA-wQAIY4DAQD7BAAhjwMBAPsEACECAAAAAQAgLgAAeQAgCKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIYsDAQD4BAAhjAMBAPgEACGNAwEA-wQAIY4DAQD7BAAhjwMBAPsEACECAAAADQAgLgAAewAgAgAAAA0AIC4AAHsAIAMAAAABACA1AAB0ACA2AAB5ACABAAAAAQAgAQAAAA0AIAYUAADWBwAgOwAA2AcAIDwAANcHACCNAwAA9AQAII4DAAD0BAAgjwMAAPQEACALoQIAALIEADCiAgAAggEAEKMCAACyBAAwpAIBANUDACGsAkAA2QMAIa0CQADZAwAhiwMBANUDACGMAwEA1QMAIY0DAQDWAwAhjgMBANYDACGPAwEA1gMAIQMAAAANACABAACBAQAwOgAAggEAIAMAAAANACABAABwADACAAABACABAAAABQAgAQAAAAUAIAMAAAADACABAAAEADACAAAFACADAAAAAwAgAQAABAAwAgAABQAgAwAAAAMAIAEAAAQAMAIAAAUAIA4DAADPBwAgGgAA1AcAIB8AANMHACAgAADQBwAgIQAA0QcAICIAANIHACAjAADVBwAgpAIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAYEDAQAAAAGJAwEAAAABigMBAAAAAQEuAACKAQAgB6QCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAGBAwEAAAABiQMBAAAAAYoDAQAAAAEBLgAAjAEAMAEuAACMAQAwDgMAAIkHACAaAACOBwAgHwAAjQcAICAAAIoHACAhAACLBwAgIgAAjAcAICMAAI8HACCkAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIYEDAQD4BAAhiQMBAPgEACGKAwEA-AQAIQIAAAAFACAuAACPAQAgB6QCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhgQMBAPgEACGJAwEA-AQAIYoDAQD4BAAhAgAAAAMAIC4AAJEBACACAAAAAwAgLgAAkQEAIAMAAAAFACA1AACKAQAgNgAAjwEAIAEAAAAFACABAAAAAwAgAxQAAIYHACA7AACIBwAgPAAAhwcAIAqhAgAAsQQAMKICAACYAQAQowIAALEEADCkAgEA1QMAIakCAQDVAwAhrAJAANkDACGtAkAA2QMAIYEDAQDVAwAhiQMBANUDACGKAwEA1QMAIQMAAAADACABAACXAQAwOgAAmAEAIAMAAAADACABAAAEADACAAAFACABAAAACQAgAQAAAAkAIAMAAAAHACABAAAIADACAAAJACADAAAABwAgAQAACAAwAgAACQAgAwAAAAcAIAEAAAgAMAIAAAkAIA4EAADeBgAgBQAA3wYAIAgAAIUHACAfAADgBgAgpAIBAAAAAaUCAQAAAAGsAkAAAAABrQJAAAAAAccCAQAAAAHbAkAAAAABhAOAAAAAAYYDAgAAAAGHAwEAAAABiAMBAAAAAQEuAACgAQAgCqQCAQAAAAGlAgEAAAABrAJAAAAAAa0CQAAAAAHHAgEAAAAB2wJAAAAAAYQDgAAAAAGGAwIAAAABhwMBAAAAAYgDAQAAAAEBLgAAogEAMAEuAACiAQAwAQAAAAsAIA4EAADSBgAgBQAA0wYAIAgAAIQHACAfAADUBgAgpAIBAPgEACGlAgEA-AQAIawCQAD6BAAhrQJAAPoEACHHAgEA-wQAIdsCQADSBQAhhAOAAAAAAYYDAgCnBQAhhwMBAPgEACGIAwEA-wQAIQIAAAAJACAuAACmAQAgCqQCAQD4BAAhpQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhxwIBAPsEACHbAkAA0gUAIYQDgAAAAAGGAwIApwUAIYcDAQD4BAAhiAMBAPsEACECAAAABwAgLgAAqAEAIAIAAAAHACAuAACoAQAgAQAAAAsAIAMAAAAJACA1AACgAQAgNgAApgEAIAEAAAAJACABAAAABwAgCBQAAP8GACA7AACCBwAgPAAAgQcAIF0AAIAHACBeAACDBwAgxwIAAPQEACDbAgAA9AQAIIgDAAD0BAAgDaECAACwBAAwogIAALABABCjAgAAsAQAMKQCAQDVAwAhpQIBANUDACGsAkAA2QMAIa0CQADZAwAhxwIBANYDACHbAkAAjwQAIYQDAADnAwAghgMCAO4DACGHAwEA1QMAIYgDAQDWAwAhAwAAAAcAIAEAAK8BADA6AACwAQAgAwAAAAcAIAEAAAgAMAIAAAkAIAEAAABDACABAAAAQwAgAwAAABAAIAEAAEIAMAIAAEMAIAMAAAAQACABAABCADACAABDACADAAAAEAAgAQAAQgAwAgAAQwAgEwQAAMcGACAGAADIBgAgCAAA_gYAIAsAAMkGACAMAADKBgAgGwAAywYAIBwAAMwGACCkAgEAAAABpQIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAccCAQAAAAHYAgEAAAAB2wJAAAAAAeYCAAAAhgMCgQMBAAAAAYMDAAAAgwMChAOAAAAAAQEuAAC4AQAgDKQCAQAAAAGlAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAABxwIBAAAAAdgCAQAAAAHbAkAAAAAB5gIAAACGAwKBAwEAAAABgwMAAACDAwKEA4AAAAABAS4AALoBADABLgAAugEAMAEAAAALACATBAAA0wUAIAYAANQFACAIAAD9BgAgCwAA1QUAIAwAANYFACAbAADXBQAgHAAA2AUAIKQCAQD4BAAhpQIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHHAgEA-wQAIdgCAQD4BAAh2wJAANIFACHmAgAA0QWGAyKBAwEA-AQAIYMDAADQBYMDIoQDgAAAAAECAAAAQwAgLgAAvgEAIAykAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhxwIBAPsEACHYAgEA-AQAIdsCQADSBQAh5gIAANEFhgMigQMBAPgEACGDAwAA0AWDAyKEA4AAAAABAgAAABAAIC4AAMABACACAAAAEAAgLgAAwAEAIAEAAAALACADAAAAQwAgNQAAuAEAIDYAAL4BACABAAAAQwAgAQAAABAAIAUUAAD6BgAgOwAA_AYAIDwAAPsGACDHAgAA9AQAINsCAAD0BAAgD6ECAACpBAAwogIAAMgBABCjAgAAqQQAMKQCAQDVAwAhpQIBANUDACGpAgEA1QMAIawCQADZAwAhrQJAANkDACHHAgEA1gMAIdgCAQDVAwAh2wJAAI8EACHmAgAAqwSGAyKBAwEA1QMAIYMDAACqBIMDIoQDAADnAwAgAwAAABAAIAEAAMcBADA6AADIAQAgAwAAABAAIAEAAEIAMAIAAEMAIAEAAAAVACABAAAAFQAgAwAAABMAIAEAABQAMAIAABUAIAMAAAATACABAAAUADACAAAVACADAAAAEwAgAQAAFAAwAgAAFQAgCwQAALoGACAJAAC7BgAgCgAAxgYAIKQCAQAAAAGlAgEAAAABqwKAAAAAAawCQAAAAAGtAkAAAAAB4gIBAAAAAf8CAQAAAAGAAwEAAAABAS4AANABACAIpAIBAAAAAaUCAQAAAAGrAoAAAAABrAJAAAAAAa0CQAAAAAHiAgEAAAAB_wIBAAAAAYADAQAAAAEBLgAA0gEAMAEuAADSAQAwCwQAALcGACAJAAC4BgAgCgAAxAYAIKQCAQD4BAAhpQIBAPgEACGrAoAAAAABrAJAAPoEACGtAkAA-gQAIeICAQD4BAAh_wIBAPgEACGAAwEA-AQAIQIAAAAVACAuAADVAQAgCKQCAQD4BAAhpQIBAPgEACGrAoAAAAABrAJAAPoEACGtAkAA-gQAIeICAQD4BAAh_wIBAPgEACGAAwEA-AQAIQIAAAATACAuAADXAQAgAgAAABMAIC4AANcBACADAAAAFQAgNQAA0AEAIDYAANUBACABAAAAFQAgAQAAABMAIAQUAAD3BgAgOwAA-QYAIDwAAPgGACCrAgAA9AQAIAuhAgAAqAQAMKICAADeAQAQowIAAKgEADCkAgEA1QMAIaUCAQDVAwAhqwIAANgDACCsAkAA2QMAIa0CQADZAwAh4gIBANUDACH_AgEA1QMAIYADAQDVAwAhAwAAABMAIAEAAN0BADA6AADeAQAgAwAAABMAIAEAABQAMAIAABUAIAEAAAAaACABAAAAGgAgAwAAABgAIAEAABkAMAIAABoAIAMAAAAYACABAAAZADACAAAaACADAAAAGAAgAQAAGQAwAgAAGgAgGgQAAJoGACAGAACbBgAgDQAAnAYAIA4AAKsGACAPAACdBgAgFgAAngYAIBcAAJ8GACAaAACgBgAgpAIBAAAAAaUCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAHYAgEAAAAB2wJAAAAAAeYCAAAA9wIC6wIBAAAAAfUCAAAA9QIC9wKAAAAAAfgCAQAAAAH5AgEAAAAB-gIBAAAAAfsCQAAAAAH8AkAAAAAB_QJAAAAAAf4CQAAAAAEBLgAA5gEAIBKkAgEAAAABpQIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAdgCAQAAAAHbAkAAAAAB5gIAAAD3AgLrAgEAAAAB9QIAAAD1AgL3AoAAAAAB-AIBAAAAAfkCAQAAAAH6AgEAAAAB-wJAAAAAAfwCQAAAAAH9AkAAAAAB_gJAAAAAAQEuAADoAQAwAS4AAOgBADABAAAAEAAgAQAAABAAIAEAAAAHACAaBAAA5gUAIAYAAOcFACANAADoBQAgDgAAqQYAIA8AAOkFACAWAADqBQAgFwAA6wUAIBoAAOwFACCkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAh2AIBAPgEACHbAkAA0gUAIeYCAADkBfcCIusCAQD4BAAh9QIAAOMF9QIi9wKAAAAAAfgCAQD7BAAh-QIBAPsEACH6AgEA-wQAIfsCQADSBQAh_AJAANIFACH9AkAA0gUAIf4CQADSBQAhAgAAABoAIC4AAO4BACASpAIBAPgEACGlAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIdgCAQD4BAAh2wJAANIFACHmAgAA5AX3AiLrAgEA-AQAIfUCAADjBfUCIvcCgAAAAAH4AgEA-wQAIfkCAQD7BAAh-gIBAPsEACH7AkAA0gUAIfwCQADSBQAh_QJAANIFACH-AkAA0gUAIQIAAAAYACAuAADwAQAgAgAAABgAIC4AAPABACABAAAAEAAgAQAAABAAIAEAAAAHACADAAAAGgAgNQAA5gEAIDYAAO4BACABAAAAGgAgAQAAABgAIAsUAAD0BgAgOwAA9gYAIDwAAPUGACDbAgAA9AQAIPgCAAD0BAAg-QIAAPQEACD6AgAA9AQAIPsCAAD0BAAg_AIAAPQEACD9AgAA9AQAIP4CAAD0BAAgFaECAAChBAAwogIAAPoBABCjAgAAoQQAMKQCAQDVAwAhpQIBANUDACGpAgEA1QMAIawCQADZAwAhrQJAANkDACHYAgEA1QMAIdsCQACPBAAh5gIAAKME9wIi6wIBANUDACH1AgAAogT1AiL3AgAA5wMAIPgCAQDWAwAh-QIBANYDACH6AgEA1gMAIfsCQACPBAAh_AJAAI8EACH9AkAAjwQAIf4CQACPBAAhAwAAABgAIAEAAPkBADA6AAD6AQAgAwAAABgAIAEAABkAMAIAABoAIAEAAAAhACABAAAAIQAgAwAAAB8AIAEAACAAMAIAACEAIAMAAAAfACABAAAgADACAAAhACADAAAAHwAgAQAAIAAwAgAAIQAgCxAAAJYFACARAACXBQAgFQAAmAYAIKQCAQAAAAGsAkAAAAABrQJAAAAAAd8CAQAAAAHvAgEAAAAB8QIAAADxAgLyAhAAAAAB8wIBAAAAAQEuAACCAgAgCKQCAQAAAAGsAkAAAAABrQJAAAAAAd8CAQAAAAHvAgEAAAAB8QIAAADxAgLyAhAAAAAB8wIBAAAAAQEuAACEAgAwAS4AAIQCADABAAAAIwAgCxAAAJMFACARAACUBQAgFQAAlgYAIKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAId8CAQD4BAAh7wIBAPgEACHxAgAAkAXxAiLyAhAAkQUAIfMCAQD7BAAhAgAAACEAIC4AAIgCACAIpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAh3wIBAPgEACHvAgEA-AQAIfECAACQBfECIvICEACRBQAh8wIBAPsEACECAAAAHwAgLgAAigIAIAIAAAAfACAuAACKAgAgAQAAACMAIAMAAAAhACA1AACCAgAgNgAAiAIAIAEAAAAhACABAAAAHwAgBxQAAO8GACA7AADyBgAgPAAA8QYAIF0AAPAGACBeAADzBgAg8gIAAPQEACDzAgAA9AQAIAuhAgAAmgQAMKICAACSAgAQowIAAJoEADCkAgEA1QMAIawCQADZAwAhrQJAANkDACHfAgEA1QMAIe8CAQDVAwAh8QIAAJsE8QIi8gIQAJwEACHzAgEA1gMAIQMAAAAfACABAACRAgAwOgAAkgIAIAMAAAAfACABAAAgADACAAAhACABAAAAKQAgAQAAACkAIAMAAAAnACABAAAoADACAAApACADAAAAJwAgAQAAKAAwAgAAKQAgAwAAACcAIAEAACgAMAIAACkAIAwQAADuBgAgpAIBAAAAAawCQAAAAAGtAkAAAAAB3wIBAAAAAeYCAAAA6wIC6AIBAAAAAekCAQAAAAHrAgEAAAAB7AKAAAAAAe0CAQAAAAHuAgEAAAABAS4AAJoCACALpAIBAAAAAawCQAAAAAGtAkAAAAAB3wIBAAAAAeYCAAAA6wIC6AIBAAAAAekCAQAAAAHrAgEAAAAB7AKAAAAAAe0CAQAAAAHuAgEAAAABAS4AAJwCADABLgAAnAIAMAwQAADtBgAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAh3wIBAPgEACHmAgAAiwbrAiLoAgEA-AQAIekCAQD4BAAh6wIBAPsEACHsAoAAAAAB7QIBAPsEACHuAgEA-wQAIQIAAAApACAuAACfAgAgC6QCAQD4BAAhrAJAAPoEACGtAkAA-gQAId8CAQD4BAAh5gIAAIsG6wIi6AIBAPgEACHpAgEA-AQAIesCAQD7BAAh7AKAAAAAAe0CAQD7BAAh7gIBAPsEACECAAAAJwAgLgAAoQIAIAIAAAAnACAuAAChAgAgAwAAACkAIDUAAJoCACA2AACfAgAgAQAAACkAIAEAAAAnACAHFAAA6gYAIDsAAOwGACA8AADrBgAg6wIAAPQEACDsAgAA9AQAIO0CAAD0BAAg7gIAAPQEACAOoQIAAJYEADCiAgAAqAIAEKMCAACWBAAwpAIBANUDACGsAkAA2QMAIa0CQADZAwAh3wIBANUDACHmAgAAlwTrAiLoAgEA1QMAIekCAQDVAwAh6wIBANYDACHsAgAA2AMAIO0CAQDWAwAh7gIBANYDACEDAAAAJwAgAQAApwIAMDoAAKgCACADAAAAJwAgAQAAKAAwAgAAKQAgAQAAAC0AIAEAAAAtACADAAAAKwAgAQAALAAwAgAALQAgAwAAACsAIAEAACwAMAIAAC0AIAMAAAArACABAAAsADACAAAtACARBAAAgAYAIBAAAOkGACAYAAD-BQAgGQAA_wUAIKQCAQAAAAGlAgEAAAABrAJAAAAAAa0CQAAAAAHdAgEAAAAB3gIBAAAAAd8CAQAAAAHhAgAAAOECAuICAQAAAAHjAgEAAAAB5AIBAAAAAeYCAAAA5gIC5wJAAAAAAQEuAACwAgAgDaQCAQAAAAGlAgEAAAABrAJAAAAAAa0CQAAAAAHdAgEAAAAB3gIBAAAAAd8CAQAAAAHhAgAAAOECAuICAQAAAAHjAgEAAAAB5AIBAAAAAeYCAAAA5gIC5wJAAAAAAQEuAACyAgAwAS4AALICADABAAAADQAgAQAAAAMAIAEAAAAYACARBAAA_AUAIBAAAOgGACAYAAD6BQAgGQAA-wUAIKQCAQD4BAAhpQIBAPsEACGsAkAA-gQAIa0CQAD6BAAh3QIBAPgEACHeAgEA-wQAId8CAQD7BAAh4QIAAPcF4QIi4gIBAPgEACHjAgEA-AQAIeQCAQD7BAAh5gIAAPgF5gIi5wJAANIFACECAAAALQAgLgAAuAIAIA2kAgEA-AQAIaUCAQD7BAAhrAJAAPoEACGtAkAA-gQAId0CAQD4BAAh3gIBAPsEACHfAgEA-wQAIeECAAD3BeECIuICAQD4BAAh4wIBAPgEACHkAgEA-wQAIeYCAAD4BeYCIucCQADSBQAhAgAAACsAIC4AALoCACACAAAAKwAgLgAAugIAIAEAAAANACABAAAAAwAgAQAAABgAIAMAAAAtACA1AACwAgAgNgAAuAIAIAEAAAAtACABAAAAKwAgCBQAAOUGACA7AADnBgAgPAAA5gYAIKUCAAD0BAAg3gIAAPQEACDfAgAA9AQAIOQCAAD0BAAg5wIAAPQEACAQoQIAAIwEADCiAgAAxAIAEKMCAACMBAAwpAIBANUDACGlAgEA1gMAIawCQADZAwAhrQJAANkDACHdAgEA1QMAId4CAQDWAwAh3wIBANYDACHhAgAAjQThAiLiAgEA1QMAIeMCAQDVAwAh5AIBANYDACHmAgAAjgTmAiLnAkAAjwQAIQMAAAArACABAADDAgAwOgAAxAIAIAMAAAArACABAAAsADACAAAtACABAAAAWgAgAQAAAFoAIAMAAAALACABAABZADACAABaACADAAAACwAgAQAAWQAwAgAAWgAgAwAAAAsAIAEAAFkAMAIAAFoAIBIGAADhBgAgBwAA4gYAIB0AAOMGACAeAADkBgAgpAIBAAAAAacCAAAA1wICqAIBAAAAAawCQAAAAAGtAkAAAAABywIBAAAAAcwCAgAAAAHNAgQAAAAB1wIBAAAAAdgCAQAAAAHZAgEAAAAB2gKAAAAAAdsCQAAAAAHcAkAAAAABAS4AAMwCACAOpAIBAAAAAacCAAAA1wICqAIBAAAAAawCQAAAAAGtAkAAAAABywIBAAAAAcwCAgAAAAHNAgQAAAAB1wIBAAAAAdgCAQAAAAHZAgEAAAAB2gKAAAAAAdsCQAAAAAHcAkAAAAABAS4AAM4CADABLgAAzgIAMAEAAAANACASBgAAuwUAIAcAALwFACAdAAC9BQAgHgAAvgUAIKQCAQD4BAAhpwIAALgF1wIiqAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhywIBAPsEACHMAgIAugUAIc0CBAC5BQAh1wIBAPgEACHYAgEA-wQAIdkCAQD4BAAh2gKAAAAAAdsCQAD6BAAh3AJAAPoEACECAAAAWgAgLgAA0gIAIA6kAgEA-AQAIacCAAC4BdcCIqgCAQD4BAAhrAJAAPoEACGtAkAA-gQAIcsCAQD7BAAhzAICALoFACHNAgQAuQUAIdcCAQD4BAAh2AIBAPsEACHZAgEA-AQAIdoCgAAAAAHbAkAA-gQAIdwCQAD6BAAhAgAAAAsAIC4AANQCACACAAAACwAgLgAA1AIAIAEAAAANACADAAAAWgAgNQAAzAIAIDYAANICACABAAAAWgAgAQAAAAsAIAoUAACzBQAgOwAAtgUAIDwAALUFACBdAAC0BQAgXgAAtwUAIMsCAAD0BAAgzAIAAPQEACDNAgAA9AQAINgCAAD0BAAg2gIAAPQEACARoQIAAIIEADCiAgAA3AIAEKMCAACCBAAwpAIBANUDACGnAgAAgwTXAiKoAgEA1QMAIawCQADZAwAhrQJAANkDACHLAgEA1gMAIcwCAgCFBAAhzQIEAIQEACHXAgEA1QMAIdgCAQDWAwAh2QIBANUDACHaAgAA2AMAINsCQADZAwAh3AJAANkDACEDAAAACwAgAQAA2wIAMDoAANwCACADAAAACwAgAQAAWQAwAgAAWgAgDqECAAD6AwAwogIAAOICABCjAgAA-gMAMKQCAQAAAAGsAkAA_wMAIa0CQAD_AwAhywIBAPsDACHMAgIA_QMAIc0CBAD8AwAh0QIAAP4D0QIi0gJAAP8DACHTAgAAgAQAINQCQAD_AwAh1QIAAIEEACABAAAA3wIAIAEAAADfAgAgDaECAAD6AwAwogIAAOICABCjAgAA-gMAMKQCAQD7AwAhrAJAAP8DACGtAkAA_wMAIcsCAQD7AwAhzAICAP0DACHNAgQA_AMAIdECAAD-A9ECItICQAD_AwAh0wIAAIAEACDUAkAA_wMAIQADAAAA4gIAIAEAAOMCADACAADfAgAgAwAAAOICACABAADjAgAwAgAA3wIAIAMAAADiAgAgAQAA4wIAMAIAAN8CACAKpAIBAAAAAawCQAAAAAGtAkAAAAABywIBAAAAAcwCAgAAAAHNAgQAAAAB0QIAAADRAgLSAkAAAAAB0wKAAAAAAdQCQAAAAAEBLgAA5wIAIAqkAgEAAAABrAJAAAAAAa0CQAAAAAHLAgEAAAABzAICAAAAAc0CBAAAAAHRAgAAANECAtICQAAAAAHTAoAAAAAB1AJAAAAAAQEuAADpAgAwAS4AAOkCADAKpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhywIBAPgEACHMAgIApwUAIc0CBACoBQAh0QIAALIF0QIi0gJAAPoEACHTAoAAAAAB1AJAAPoEACECAAAA3wIAIC4AAOwCACAKpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhywIBAPgEACHMAgIApwUAIc0CBACoBQAh0QIAALIF0QIi0gJAAPoEACHTAoAAAAAB1AJAAPoEACECAAAA4gIAIC4AAO4CACACAAAA4gIAIC4AAO4CACADAAAA3wIAIDUAAOcCACA2AADsAgAgAQAAAN8CACABAAAA4gIAIAUUAACtBQAgOwAAsAUAIDwAAK8FACBdAACuBQAgXgAAsQUAIA2hAgAA9gMAMKICAAD1AgAQowIAAPYDADCkAgEA1QMAIawCQADZAwAhrQJAANkDACHLAgEA1QMAIcwCAgDuAwAhzQIEAO8DACHRAgAA9wPRAiLSAkAA2QMAIdMCAADnAwAg1AJAANkDACEDAAAA4gIAIAEAAPQCADA6AAD1AgAgAwAAAOICACABAADjAgAwAgAA3wIAIAEAAAA8ACABAAAAPAAgAwAAADoAIAEAADsAMAIAADwAIAMAAAA6ACABAAA7ADACAAA8ACADAAAAOgAgAQAAOwAwAgAAPAAgDwgAAKwFACASAACrBQAgpAIBAAAAAawCQAAAAAGtAkAAAAABvwIBAAAAAcQCAQAAAAHHAgEAAAAByQIAAADJAgLKAhAAAAABywIBAAAAAcwCAgAAAAHNAgQAAAABzgJAAAAAAc8CAQAAAAEBLgAA_QIAIA2kAgEAAAABrAJAAAAAAa0CQAAAAAG_AgEAAAABxAIBAAAAAccCAQAAAAHJAgAAAMkCAsoCEAAAAAHLAgEAAAABzAICAAAAAc0CBAAAAAHOAkAAAAABzwIBAAAAAQEuAAD_AgAwAS4AAP8CADABAAAACwAgDwgAAKoFACASAACpBQAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhvwIBAPgEACHEAgEA-AQAIccCAQD7BAAhyQIAAKYFyQIiygIQAIMFACHLAgEA-AQAIcwCAgCnBQAhzQIEAKgFACHOAkAA-gQAIc8CAQD4BAAhAgAAADwAIC4AAIMDACANpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhvwIBAPgEACHEAgEA-AQAIccCAQD7BAAhyQIAAKYFyQIiygIQAIMFACHLAgEA-AQAIcwCAgCnBQAhzQIEAKgFACHOAkAA-gQAIc8CAQD4BAAhAgAAADoAIC4AAIUDACACAAAAOgAgLgAAhQMAIAEAAAALACADAAAAPAAgNQAA_QIAIDYAAIMDACABAAAAPAAgAQAAADoAIAYUAAChBQAgOwAApAUAIDwAAKMFACBdAACiBQAgXgAApQUAIMcCAAD0BAAgEKECAADsAwAwogIAAI0DABCjAgAA7AMAMKQCAQDVAwAhrAJAANkDACGtAkAA2QMAIb8CAQDVAwAhxAIBANUDACHHAgEA1gMAIckCAADtA8kCIsoCEADmAwAhywIBANUDACHMAgIA7gMAIc0CBADvAwAhzgJAANkDACHPAgEA1QMAIQMAAAA6ACABAACMAwAwOgAAjQMAIAMAAAA6ACABAAA7ADACAAA8ACABAAAAXwAgAQAAAF8AIAMAAABdACABAABeADACAABfACADAAAAXQAgAQAAXgAwAgAAXwAgAwAAAF0AIAEAAF4AMAIAAF8AIAgSAACgBQAgpAIBAAAAAawCQAAAAAGtAkAAAAABvwIBAAAAAcQCAQAAAAHFAhAAAAABxgJAAAAAAQEuAACVAwAgB6QCAQAAAAGsAkAAAAABrQJAAAAAAb8CAQAAAAHEAgEAAAABxQIQAAAAAcYCQAAAAAEBLgAAlwMAMAEuAACXAwAwCBIAAJ8FACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACG_AgEA-AQAIcQCAQD4BAAhxQIQAIMFACHGAkAA-gQAIQIAAABfACAuAACaAwAgB6QCAQD4BAAhrAJAAPoEACGtAkAA-gQAIb8CAQD4BAAhxAIBAPgEACHFAhAAgwUAIcYCQAD6BAAhAgAAAF0AIC4AAJwDACACAAAAXQAgLgAAnAMAIAMAAABfACA1AACVAwAgNgAAmgMAIAEAAABfACABAAAAXQAgBRQAAJoFACA7AACdBQAgPAAAnAUAIF0AAJsFACBeAACeBQAgCqECAADrAwAwogIAAKMDABCjAgAA6wMAMKQCAQDVAwAhrAJAANkDACGtAkAA2QMAIb8CAQDVAwAhxAIBANUDACHFAhAA5gMAIcYCQADZAwAhAwAAAF0AIAEAAKIDADA6AACjAwAgAwAAAF0AIAEAAF4AMAIAAF8AIAEAAABiACABAAAAYgAgAwAAACMAIAEAAGEAMAIAAGIAIAMAAAAjACABAABhADACAABiACADAAAAIwAgAQAAYQAwAgAAYgAgCRIAAJgFACATAACZBQAgpAIBAAAAAawCQAAAAAG_AgEAAAABwAIQAAAAAcECAQAAAAHCAoAAAAABwwJAAAAAAQEuAACrAwAgB6QCAQAAAAGsAkAAAAABvwIBAAAAAcACEAAAAAHBAgEAAAABwgKAAAAAAcMCQAAAAAEBLgAArQMAMAEuAACtAwAwCRIAAIQFACATAACFBQAgpAIBAPgEACGsAkAA-gQAIb8CAQD4BAAhwAIQAIMFACHBAgEA-AQAIcICgAAAAAHDAkAA-gQAIQIAAABiACAuAACwAwAgB6QCAQD4BAAhrAJAAPoEACG_AgEA-AQAIcACEACDBQAhwQIBAPgEACHCAoAAAAABwwJAAPoEACECAAAAIwAgLgAAsgMAIAIAAAAjACAuAACyAwAgAwAAAGIAIDUAAKsDACA2AACwAwAgAQAAAGIAIAEAAAAjACAFFAAA_gQAIDsAAIEFACA8AACABQAgXQAA_wQAIF4AAIIFACAKoQIAAOUDADCiAgAAuQMAEKMCAADlAwAwpAIBANUDACGsAkAA2QMAIb8CAQDVAwAhwAIQAOYDACHBAgEA1QMAIcICAADnAwAgwwJAANkDACEDAAAAIwAgAQAAuAMAMDoAALkDACADAAAAIwAgAQAAYQAwAgAAYgAgAQAAAEoAIAEAAABKACADAAAASAAgAQAASQAwAgAASgAgAwAAAEgAIAEAAEkAMAIAAEoAIAMAAABIACABAABJADACAABKACAKBAAA_QQAIKQCAQAAAAGlAgEAAAABpwIAAACnAgKoAgEAAAABqQIBAAAAAaoCAQAAAAGrAoAAAAABrAJAAAAAAa0CQAAAAAEBLgAAwQMAIAmkAgEAAAABpQIBAAAAAacCAAAApwICqAIBAAAAAakCAQAAAAGqAgEAAAABqwKAAAAAAawCQAAAAAGtAkAAAAABAS4AAMMDADABLgAAwwMAMAEAAAADACAKBAAA_AQAIKQCAQD4BAAhpQIBAPsEACGnAgAA-QSnAiKoAgEA-AQAIakCAQD4BAAhqgIBAPgEACGrAoAAAAABrAJAAPoEACGtAkAA-gQAIQIAAABKACAuAADHAwAgCaQCAQD4BAAhpQIBAPsEACGnAgAA-QSnAiKoAgEA-AQAIakCAQD4BAAhqgIBAPgEACGrAoAAAAABrAJAAPoEACGtAkAA-gQAIQIAAABIACAuAADJAwAgAgAAAEgAIC4AAMkDACABAAAAAwAgAwAAAEoAIDUAAMEDACA2AADHAwAgAQAAAEoAIAEAAABIACAFFAAA9QQAIDsAAPcEACA8AAD2BAAgpQIAAPQEACCrAgAA9AQAIAyhAgAA1AMAMKICAADRAwAQowIAANQDADCkAgEA1QMAIaUCAQDWAwAhpwIAANcDpwIiqAIBANUDACGpAgEA1QMAIaoCAQDVAwAhqwIAANgDACCsAkAA2QMAIa0CQADZAwAhAwAAAEgAIAEAANADADA6AADRAwAgAwAAAEgAIAEAAEkAMAIAAEoAIAyhAgAA1AMAMKICAADRAwAQowIAANQDADCkAgEA1QMAIaUCAQDWAwAhpwIAANcDpwIiqAIBANUDACGpAgEA1QMAIaoCAQDVAwAhqwIAANgDACCsAkAA2QMAIa0CQADZAwAhDhQAANsDACA7AADkAwAgPAAA5AMAIK4CAQAAAAGvAgEAAAAEsAIBAAAABLECAQAAAAGyAgEAAAABswIBAAAAAbQCAQAAAAG1AgEA4wMAIbwCAQAAAAG9AgEAAAABvgIBAAAAAQ4UAADdAwAgOwAA4gMAIDwAAOIDACCuAgEAAAABrwIBAAAABbACAQAAAAWxAgEAAAABsgIBAAAAAbMCAQAAAAG0AgEAAAABtQIBAOEDACG8AgEAAAABvQIBAAAAAb4CAQAAAAEHFAAA2wMAIDsAAOADACA8AADgAwAgrgIAAACnAgKvAgAAAKcCCLACAAAApwIItQIAAN8DpwIiDxQAAN0DACA7AADeAwAgPAAA3gMAIK4CgAAAAAGxAoAAAAABsgKAAAAAAbMCgAAAAAG0AoAAAAABtQKAAAAAAbYCAQAAAAG3AgEAAAABuAIBAAAAAbkCgAAAAAG6AoAAAAABuwKAAAAAAQsUAADbAwAgOwAA3AMAIDwAANwDACCuAkAAAAABrwJAAAAABLACQAAAAASxAkAAAAABsgJAAAAAAbMCQAAAAAG0AkAAAAABtQJAANoDACELFAAA2wMAIDsAANwDACA8AADcAwAgrgJAAAAAAa8CQAAAAASwAkAAAAAEsQJAAAAAAbICQAAAAAGzAkAAAAABtAJAAAAAAbUCQADaAwAhCK4CAgAAAAGvAgIAAAAEsAICAAAABLECAgAAAAGyAgIAAAABswICAAAAAbQCAgAAAAG1AgIA2wMAIQiuAkAAAAABrwJAAAAABLACQAAAAASxAkAAAAABsgJAAAAAAbMCQAAAAAG0AkAAAAABtQJAANwDACEIrgICAAAAAa8CAgAAAAWwAgIAAAAFsQICAAAAAbICAgAAAAGzAgIAAAABtAICAAAAAbUCAgDdAwAhDK4CgAAAAAGxAoAAAAABsgKAAAAAAbMCgAAAAAG0AoAAAAABtQKAAAAAAbYCAQAAAAG3AgEAAAABuAIBAAAAAbkCgAAAAAG6AoAAAAABuwKAAAAAAQcUAADbAwAgOwAA4AMAIDwAAOADACCuAgAAAKcCAq8CAAAApwIIsAIAAACnAgi1AgAA3wOnAiIErgIAAACnAgKvAgAAAKcCCLACAAAApwIItQIAAOADpwIiDhQAAN0DACA7AADiAwAgPAAA4gMAIK4CAQAAAAGvAgEAAAAFsAIBAAAABbECAQAAAAGyAgEAAAABswIBAAAAAbQCAQAAAAG1AgEA4QMAIbwCAQAAAAG9AgEAAAABvgIBAAAAAQuuAgEAAAABrwIBAAAABbACAQAAAAWxAgEAAAABsgIBAAAAAbMCAQAAAAG0AgEAAAABtQIBAOIDACG8AgEAAAABvQIBAAAAAb4CAQAAAAEOFAAA2wMAIDsAAOQDACA8AADkAwAgrgIBAAAAAa8CAQAAAASwAgEAAAAEsQIBAAAAAbICAQAAAAGzAgEAAAABtAIBAAAAAbUCAQDjAwAhvAIBAAAAAb0CAQAAAAG-AgEAAAABC64CAQAAAAGvAgEAAAAEsAIBAAAABLECAQAAAAGyAgEAAAABswIBAAAAAbQCAQAAAAG1AgEA5AMAIbwCAQAAAAG9AgEAAAABvgIBAAAAAQqhAgAA5QMAMKICAAC5AwAQowIAAOUDADCkAgEA1QMAIawCQADZAwAhvwIBANUDACHAAhAA5gMAIcECAQDVAwAhwgIAAOcDACDDAkAA2QMAIQ0UAADbAwAgOwAA6gMAIDwAAOoDACBdAADqAwAgXgAA6gMAIK4CEAAAAAGvAhAAAAAEsAIQAAAABLECEAAAAAGyAhAAAAABswIQAAAAAbQCEAAAAAG1AhAA6QMAIQ8UAADbAwAgOwAA6AMAIDwAAOgDACCuAoAAAAABsQKAAAAAAbICgAAAAAGzAoAAAAABtAKAAAAAAbUCgAAAAAG2AgEAAAABtwIBAAAAAbgCAQAAAAG5AoAAAAABugKAAAAAAbsCgAAAAAEMrgKAAAAAAbECgAAAAAGyAoAAAAABswKAAAAAAbQCgAAAAAG1AoAAAAABtgIBAAAAAbcCAQAAAAG4AgEAAAABuQKAAAAAAboCgAAAAAG7AoAAAAABDRQAANsDACA7AADqAwAgPAAA6gMAIF0AAOoDACBeAADqAwAgrgIQAAAAAa8CEAAAAASwAhAAAAAEsQIQAAAAAbICEAAAAAGzAhAAAAABtAIQAAAAAbUCEADpAwAhCK4CEAAAAAGvAhAAAAAEsAIQAAAABLECEAAAAAGyAhAAAAABswIQAAAAAbQCEAAAAAG1AhAA6gMAIQqhAgAA6wMAMKICAACjAwAQowIAAOsDADCkAgEA1QMAIawCQADZAwAhrQJAANkDACG_AgEA1QMAIcQCAQDVAwAhxQIQAOYDACHGAkAA2QMAIRChAgAA7AMAMKICAACNAwAQowIAAOwDADCkAgEA1QMAIawCQADZAwAhrQJAANkDACG_AgEA1QMAIcQCAQDVAwAhxwIBANYDACHJAgAA7QPJAiLKAhAA5gMAIcsCAQDVAwAhzAICAO4DACHNAgQA7wMAIc4CQADZAwAhzwIBANUDACEHFAAA2wMAIDsAAPUDACA8AAD1AwAgrgIAAADJAgKvAgAAAMkCCLACAAAAyQIItQIAAPQDyQIiDRQAANsDACA7AADbAwAgPAAA2wMAIF0AAPEDACBeAADbAwAgrgICAAAAAa8CAgAAAASwAgIAAAAEsQICAAAAAbICAgAAAAGzAgIAAAABtAICAAAAAbUCAgDzAwAhDRQAANsDACA7AADyAwAgPAAA8gMAIF0AAPEDACBeAADyAwAgrgIEAAAAAa8CBAAAAASwAgQAAAAEsQIEAAAAAbICBAAAAAGzAgQAAAABtAIEAAAAAbUCBADwAwAhDRQAANsDACA7AADyAwAgPAAA8gMAIF0AAPEDACBeAADyAwAgrgIEAAAAAa8CBAAAAASwAgQAAAAEsQIEAAAAAbICBAAAAAGzAgQAAAABtAIEAAAAAbUCBADwAwAhCK4CCAAAAAGvAggAAAAEsAIIAAAABLECCAAAAAGyAggAAAABswIIAAAAAbQCCAAAAAG1AggA8QMAIQiuAgQAAAABrwIEAAAABLACBAAAAASxAgQAAAABsgIEAAAAAbMCBAAAAAG0AgQAAAABtQIEAPIDACENFAAA2wMAIDsAANsDACA8AADbAwAgXQAA8QMAIF4AANsDACCuAgIAAAABrwICAAAABLACAgAAAASxAgIAAAABsgICAAAAAbMCAgAAAAG0AgIAAAABtQICAPMDACEHFAAA2wMAIDsAAPUDACA8AAD1AwAgrgIAAADJAgKvAgAAAMkCCLACAAAAyQIItQIAAPQDyQIiBK4CAAAAyQICrwIAAADJAgiwAgAAAMkCCLUCAAD1A8kCIg2hAgAA9gMAMKICAAD1AgAQowIAAPYDADCkAgEA1QMAIawCQADZAwAhrQJAANkDACHLAgEA1QMAIcwCAgDuAwAhzQIEAO8DACHRAgAA9wPRAiLSAkAA2QMAIdMCAADnAwAg1AJAANkDACEHFAAA2wMAIDsAAPkDACA8AAD5AwAgrgIAAADRAgKvAgAAANECCLACAAAA0QIItQIAAPgD0QIiBxQAANsDACA7AAD5AwAgPAAA-QMAIK4CAAAA0QICrwIAAADRAgiwAgAAANECCLUCAAD4A9ECIgSuAgAAANECAq8CAAAA0QIIsAIAAADRAgi1AgAA-QPRAiINoQIAAPoDADCiAgAA4gIAEKMCAAD6AwAwpAIBAPsDACGsAkAA_wMAIa0CQAD_AwAhywIBAPsDACHMAgIA_QMAIc0CBAD8AwAh0QIAAP4D0QIi0gJAAP8DACHTAgAAgAQAINQCQAD_AwAhC64CAQAAAAGvAgEAAAAEsAIBAAAABLECAQAAAAGyAgEAAAABswIBAAAAAbQCAQAAAAG1AgEA5AMAIbwCAQAAAAG9AgEAAAABvgIBAAAAAQiuAgQAAAABrwIEAAAABLACBAAAAASxAgQAAAABsgIEAAAAAbMCBAAAAAG0AgQAAAABtQIEAPIDACEIrgICAAAAAa8CAgAAAASwAgIAAAAEsQICAAAAAbICAgAAAAGzAgIAAAABtAICAAAAAbUCAgDbAwAhBK4CAAAA0QICrwIAAADRAgiwAgAAANECCLUCAAD5A9ECIgiuAkAAAAABrwJAAAAABLACQAAAAASxAkAAAAABsgJAAAAAAbMCQAAAAAG0AkAAAAABtQJAANwDACEMrgKAAAAAAbECgAAAAAGyAoAAAAABswKAAAAAAbQCgAAAAAG1AoAAAAABtgIBAAAAAbcCAQAAAAG4AgEAAAABuQKAAAAAAboCgAAAAAG7AoAAAAABAssCAQAAAAHMAgIAAAABEaECAACCBAAwogIAANwCABCjAgAAggQAMKQCAQDVAwAhpwIAAIME1wIiqAIBANUDACGsAkAA2QMAIa0CQADZAwAhywIBANYDACHMAgIAhQQAIc0CBACEBAAh1wIBANUDACHYAgEA1gMAIdkCAQDVAwAh2gIAANgDACDbAkAA2QMAIdwCQADZAwAhBxQAANsDACA7AACLBAAgPAAAiwQAIK4CAAAA1wICrwIAAADXAgiwAgAAANcCCLUCAACKBNcCIg0UAADdAwAgOwAAiQQAIDwAAIkEACBdAACHBAAgXgAAiQQAIK4CBAAAAAGvAgQAAAAFsAIEAAAABbECBAAAAAGyAgQAAAABswIEAAAAAbQCBAAAAAG1AgQAiAQAIQ0UAADdAwAgOwAA3QMAIDwAAN0DACBdAACHBAAgXgAA3QMAIK4CAgAAAAGvAgIAAAAFsAICAAAABbECAgAAAAGyAgIAAAABswICAAAAAbQCAgAAAAG1AgIAhgQAIQ0UAADdAwAgOwAA3QMAIDwAAN0DACBdAACHBAAgXgAA3QMAIK4CAgAAAAGvAgIAAAAFsAICAAAABbECAgAAAAGyAgIAAAABswICAAAAAbQCAgAAAAG1AgIAhgQAIQiuAggAAAABrwIIAAAABbACCAAAAAWxAggAAAABsgIIAAAAAbMCCAAAAAG0AggAAAABtQIIAIcEACENFAAA3QMAIDsAAIkEACA8AACJBAAgXQAAhwQAIF4AAIkEACCuAgQAAAABrwIEAAAABbACBAAAAAWxAgQAAAABsgIEAAAAAbMCBAAAAAG0AgQAAAABtQIEAIgEACEIrgIEAAAAAa8CBAAAAAWwAgQAAAAFsQIEAAAAAbICBAAAAAGzAgQAAAABtAIEAAAAAbUCBACJBAAhBxQAANsDACA7AACLBAAgPAAAiwQAIK4CAAAA1wICrwIAAADXAgiwAgAAANcCCLUCAACKBNcCIgSuAgAAANcCAq8CAAAA1wIIsAIAAADXAgi1AgAAiwTXAiIQoQIAAIwEADCiAgAAxAIAEKMCAACMBAAwpAIBANUDACGlAgEA1gMAIawCQADZAwAhrQJAANkDACHdAgEA1QMAId4CAQDWAwAh3wIBANYDACHhAgAAjQThAiLiAgEA1QMAIeMCAQDVAwAh5AIBANYDACHmAgAAjgTmAiLnAkAAjwQAIQcUAADbAwAgOwAAlQQAIDwAAJUEACCuAgAAAOECAq8CAAAA4QIIsAIAAADhAgi1AgAAlAThAiIHFAAA2wMAIDsAAJMEACA8AACTBAAgrgIAAADmAgKvAgAAAOYCCLACAAAA5gIItQIAAJIE5gIiCxQAAN0DACA7AACRBAAgPAAAkQQAIK4CQAAAAAGvAkAAAAAFsAJAAAAABbECQAAAAAGyAkAAAAABswJAAAAAAbQCQAAAAAG1AkAAkAQAIQsUAADdAwAgOwAAkQQAIDwAAJEEACCuAkAAAAABrwJAAAAABbACQAAAAAWxAkAAAAABsgJAAAAAAbMCQAAAAAG0AkAAAAABtQJAAJAEACEIrgJAAAAAAa8CQAAAAAWwAkAAAAAFsQJAAAAAAbICQAAAAAGzAkAAAAABtAJAAAAAAbUCQACRBAAhBxQAANsDACA7AACTBAAgPAAAkwQAIK4CAAAA5gICrwIAAADmAgiwAgAAAOYCCLUCAACSBOYCIgSuAgAAAOYCAq8CAAAA5gIIsAIAAADmAgi1AgAAkwTmAiIHFAAA2wMAIDsAAJUEACA8AACVBAAgrgIAAADhAgKvAgAAAOECCLACAAAA4QIItQIAAJQE4QIiBK4CAAAA4QICrwIAAADhAgiwAgAAAOECCLUCAACVBOECIg6hAgAAlgQAMKICAACoAgAQowIAAJYEADCkAgEA1QMAIawCQADZAwAhrQJAANkDACHfAgEA1QMAIeYCAACXBOsCIugCAQDVAwAh6QIBANUDACHrAgEA1gMAIewCAADYAwAg7QIBANYDACHuAgEA1gMAIQcUAADbAwAgOwAAmQQAIDwAAJkEACCuAgAAAOsCAq8CAAAA6wIIsAIAAADrAgi1AgAAmATrAiIHFAAA2wMAIDsAAJkEACA8AACZBAAgrgIAAADrAgKvAgAAAOsCCLACAAAA6wIItQIAAJgE6wIiBK4CAAAA6wICrwIAAADrAgiwAgAAAOsCCLUCAACZBOsCIguhAgAAmgQAMKICAACSAgAQowIAAJoEADCkAgEA1QMAIawCQADZAwAhrQJAANkDACHfAgEA1QMAIe8CAQDVAwAh8QIAAJsE8QIi8gIQAJwEACHzAgEA1gMAIQcUAADbAwAgOwAAoAQAIDwAAKAEACCuAgAAAPECAq8CAAAA8QIIsAIAAADxAgi1AgAAnwTxAiINFAAA3QMAIDsAAJ4EACA8AACeBAAgXQAAngQAIF4AAJ4EACCuAhAAAAABrwIQAAAABbACEAAAAAWxAhAAAAABsgIQAAAAAbMCEAAAAAG0AhAAAAABtQIQAJ0EACENFAAA3QMAIDsAAJ4EACA8AACeBAAgXQAAngQAIF4AAJ4EACCuAhAAAAABrwIQAAAABbACEAAAAAWxAhAAAAABsgIQAAAAAbMCEAAAAAG0AhAAAAABtQIQAJ0EACEIrgIQAAAAAa8CEAAAAAWwAhAAAAAFsQIQAAAAAbICEAAAAAGzAhAAAAABtAIQAAAAAbUCEACeBAAhBxQAANsDACA7AACgBAAgPAAAoAQAIK4CAAAA8QICrwIAAADxAgiwAgAAAPECCLUCAACfBPECIgSuAgAAAPECAq8CAAAA8QIIsAIAAADxAgi1AgAAoATxAiIVoQIAAKEEADCiAgAA-gEAEKMCAAChBAAwpAIBANUDACGlAgEA1QMAIakCAQDVAwAhrAJAANkDACGtAkAA2QMAIdgCAQDVAwAh2wJAAI8EACHmAgAAowT3AiLrAgEA1QMAIfUCAACiBPUCIvcCAADnAwAg-AIBANYDACH5AgEA1gMAIfoCAQDWAwAh-wJAAI8EACH8AkAAjwQAIf0CQACPBAAh_gJAAI8EACEHFAAA2wMAIDsAAKcEACA8AACnBAAgrgIAAAD1AgKvAgAAAPUCCLACAAAA9QIItQIAAKYE9QIiBxQAANsDACA7AAClBAAgPAAApQQAIK4CAAAA9wICrwIAAAD3AgiwAgAAAPcCCLUCAACkBPcCIgcUAADbAwAgOwAApQQAIDwAAKUEACCuAgAAAPcCAq8CAAAA9wIIsAIAAAD3Agi1AgAApAT3AiIErgIAAAD3AgKvAgAAAPcCCLACAAAA9wIItQIAAKUE9wIiBxQAANsDACA7AACnBAAgPAAApwQAIK4CAAAA9QICrwIAAAD1AgiwAgAAAPUCCLUCAACmBPUCIgSuAgAAAPUCAq8CAAAA9QIIsAIAAAD1Agi1AgAApwT1AiILoQIAAKgEADCiAgAA3gEAEKMCAACoBAAwpAIBANUDACGlAgEA1QMAIasCAADYAwAgrAJAANkDACGtAkAA2QMAIeICAQDVAwAh_wIBANUDACGAAwEA1QMAIQ-hAgAAqQQAMKICAADIAQAQowIAAKkEADCkAgEA1QMAIaUCAQDVAwAhqQIBANUDACGsAkAA2QMAIa0CQADZAwAhxwIBANYDACHYAgEA1QMAIdsCQACPBAAh5gIAAKsEhgMigQMBANUDACGDAwAAqgSDAyKEAwAA5wMAIAcUAADbAwAgOwAArwQAIDwAAK8EACCuAgAAAIMDAq8CAAAAgwMIsAIAAACDAwi1AgAArgSDAyIHFAAA2wMAIDsAAK0EACA8AACtBAAgrgIAAACGAwKvAgAAAIYDCLACAAAAhgMItQIAAKwEhgMiBxQAANsDACA7AACtBAAgPAAArQQAIK4CAAAAhgMCrwIAAACGAwiwAgAAAIYDCLUCAACsBIYDIgSuAgAAAIYDAq8CAAAAhgMIsAIAAACGAwi1AgAArQSGAyIHFAAA2wMAIDsAAK8EACA8AACvBAAgrgIAAACDAwKvAgAAAIMDCLACAAAAgwMItQIAAK4EgwMiBK4CAAAAgwMCrwIAAACDAwiwAgAAAIMDCLUCAACvBIMDIg2hAgAAsAQAMKICAACwAQAQowIAALAEADCkAgEA1QMAIaUCAQDVAwAhrAJAANkDACGtAkAA2QMAIccCAQDWAwAh2wJAAI8EACGEAwAA5wMAIIYDAgDuAwAhhwMBANUDACGIAwEA1gMAIQqhAgAAsQQAMKICAACYAQAQowIAALEEADCkAgEA1QMAIakCAQDVAwAhrAJAANkDACGtAkAA2QMAIYEDAQDVAwAhiQMBANUDACGKAwEA1QMAIQuhAgAAsgQAMKICAACCAQAQowIAALIEADCkAgEA1QMAIawCQADZAwAhrQJAANkDACGLAwEA1QMAIYwDAQDVAwAhjQMBANYDACGOAwEA1gMAIY8DAQDWAwAhDBIAALUEACATAAC2BAAgoQIAALMEADCiAgAAIwAQowIAALMEADCkAgEA-wMAIawCQAD_AwAhvwIBAPsDACHAAhAAtAQAIcECAQD7AwAhwgIAAIAEACDDAkAA_wMAIQiuAhAAAAABrwIQAAAABLACEAAAAASxAhAAAAABsgIQAAAAAbMCEAAAAAG0AhAAAAABtQIQAOoDACEYFgAAtgQAIBoAAOUEACAeAADFBAAgHwAA0gQAICAAAOsEACAhAADsBAAgJAAA6gQAICUAAOUEACAmAADtBAAgJwAA7gQAICgAAO8EACChAgAA6QQAMKICAAANABCjAgAA6QQAMKQCAQD7AwAhrAJAAP8DACGtAkAA_wMAIYsDAQD7AwAhjAMBAPsDACGNAwEAvgQAIY4DAQC-BAAhjwMBAL4EACGaAwAADQAgmwMAAA0AIAOQAwAAHwAgkQMAAB8AIJIDAAAfACACvwIBAAAAAcQCAQAAAAELEgAAtQQAIKECAAC4BAAwogIAAF0AEKMCAAC4BAAwpAIBAPsDACGsAkAA_wMAIa0CQAD_AwAhvwIBAPsDACHEAgEA-wMAIcUCEAC0BAAhxgJAAP8DACECpwIAAADXAgKoAgEAAAABAtcCAQAAAAHZAgEAAAABAssCAQAAAAHMAgIAAAABFQYAAMIEACAHAADDBAAgHQAAxAQAIB4AAMUEACChAgAAvAQAMKICAAALABCjAgAAvAQAMKQCAQD7AwAhpwIAAL0E1wIiqAIBAPsDACGsAkAA_wMAIa0CQAD_AwAhywIBAL4EACHMAgIAwAQAIc0CBAC_BAAh1wIBAPsDACHYAgEAvgQAIdkCAQD7AwAh2gIAAMEEACDbAkAA_wMAIdwCQAD_AwAhBK4CAAAA1wICrwIAAADXAgiwAgAAANcCCLUCAACLBNcCIguuAgEAAAABrwIBAAAABbACAQAAAAWxAgEAAAABsgIBAAAAAbMCAQAAAAG0AgEAAAABtQIBAOIDACG8AgEAAAABvQIBAAAAAb4CAQAAAAEIrgIEAAAAAa8CBAAAAAWwAgQAAAAFsQIEAAAAAbICBAAAAAGzAgQAAAABtAIEAAAAAbUCBACJBAAhCK4CAgAAAAGvAgIAAAAFsAICAAAABbECAgAAAAGyAgIAAAABswICAAAAAbQCAgAAAAG1AgIA3QMAIQyuAoAAAAABsQKAAAAAAbICgAAAAAGzAoAAAAABtAKAAAAAAbUCgAAAAAG2AgEAAAABtwIBAAAAAbgCAQAAAAG5AoAAAAABugKAAAAAAbsCgAAAAAEYFgAAtgQAIBoAAOUEACAeAADFBAAgHwAA0gQAICAAAOsEACAhAADsBAAgJAAA6gQAICUAAOUEACAmAADtBAAgJwAA7gQAICgAAO8EACChAgAA6QQAMKICAAANABCjAgAA6QQAMKQCAQD7AwAhrAJAAP8DACGtAkAA_wMAIYsDAQD7AwAhjAMBAPsDACGNAwEAvgQAIY4DAQC-BAAhjwMBAL4EACGaAwAADQAgmwMAAA0AIBMEAADPBAAgBQAAtQQAIAgAANAEACAfAADSBAAgoQIAAPEEADCiAgAABwAQowIAAPEEADCkAgEA-wMAIaUCAQD7AwAhrAJAAP8DACGtAkAA_wMAIccCAQC-BAAh2wJAAM4EACGEAwAAgAQAIIYDAgD9AwAhhwMBAPsDACGIAwEAvgQAIZoDAAAHACCbAwAABwAgGAQAAM8EACAGAAC1BAAgCAAA0AQAIAsAANEEACAMAADRBAAgGwAA0gQAIBwAANIEACChAgAAywQAMKICAAAQABCjAgAAywQAMKQCAQD7AwAhpQIBAPsDACGpAgEA-wMAIawCQAD_AwAhrQJAAP8DACHHAgEAvgQAIdgCAQD7AwAh2wJAAM4EACHmAgAAzQSGAyKBAwEA-wMAIYMDAADMBIMDIoQDAACABAAgmgMAABAAIJsDAAAQACADkAMAADoAIJEDAAA6ACCSAwAAOgAgAqcCAAAApwICqAIBAAAAAQ0EAADJBAAgoQIAAMcEADCiAgAASAAQowIAAMcEADCkAgEA-wMAIaUCAQC-BAAhpwIAAMgEpwIiqAIBAPsDACGpAgEA-wMAIaoCAQD7AwAhqwIAAMEEACCsAkAA_wMAIa0CQAD_AwAhBK4CAAAApwICrwIAAACnAgiwAgAAAKcCCLUCAADgA6cCIhMDAAC1BAAgGgAA5QQAIB8AANIEACAgAADrBAAgIQAA7AQAICIAANEEACAjAADzBAAgoQIAAPIEADCiAgAAAwAQowIAAPIEADCkAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIYEDAQD7AwAhiQMBAPsDACGKAwEA-wMAIZoDAAADACCbAwAAAwAgAqUCAQAAAAGBAwEAAAABFgQAAM8EACAGAAC1BAAgCAAA0AQAIAsAANEEACAMAADRBAAgGwAA0gQAIBwAANIEACChAgAAywQAMKICAAAQABCjAgAAywQAMKQCAQD7AwAhpQIBAPsDACGpAgEA-wMAIawCQAD_AwAhrQJAAP8DACHHAgEAvgQAIdgCAQD7AwAh2wJAAM4EACHmAgAAzQSGAyKBAwEA-wMAIYMDAADMBIMDIoQDAACABAAgBK4CAAAAgwMCrwIAAACDAwiwAgAAAIMDCLUCAACvBIMDIgSuAgAAAIYDAq8CAAAAhgMIsAIAAACGAwi1AgAArQSGAyIIrgJAAAAAAa8CQAAAAAWwAkAAAAAFsQJAAAAAAbICQAAAAAGzAkAAAAABtAJAAAAAAbUCQACRBAAhEwMAALUEACAaAADlBAAgHwAA0gQAICAAAOsEACAhAADsBAAgIgAA0QQAICMAAPMEACChAgAA8gQAMKICAAADABCjAgAA8gQAMKQCAQD7AwAhqQIBAPsDACGsAkAA_wMAIa0CQAD_AwAhgQMBAPsDACGJAwEA-wMAIYoDAQD7AwAhmgMAAAMAIJsDAAADACAXBgAAwgQAIAcAAMMEACAdAADEBAAgHgAAxQQAIKECAAC8BAAwogIAAAsAEKMCAAC8BAAwpAIBAPsDACGnAgAAvQTXAiKoAgEA-wMAIawCQAD_AwAhrQJAAP8DACHLAgEAvgQAIcwCAgDABAAhzQIEAL8EACHXAgEA-wMAIdgCAQC-BAAh2QIBAPsDACHaAgAAwQQAINsCQAD_AwAh3AJAAP8DACGaAwAACwAgmwMAAAsAIAOQAwAAEwAgkQMAABMAIJIDAAATACADkAMAABgAIJEDAAAYACCSAwAAGAAgEggAANAEACASAAC1BAAgoQIAANMEADCiAgAAOgAQowIAANMEADCkAgEA-wMAIawCQAD_AwAhrQJAAP8DACG_AgEA-wMAIcQCAQD7AwAhxwIBAL4EACHJAgAA1ATJAiLKAhAAtAQAIcsCAQD7AwAhzAICAP0DACHNAgQA_AMAIc4CQAD_AwAhzwIBAPsDACEErgIAAADJAgKvAgAAAMkCCLACAAAAyQIItQIAAPUDyQIiFAQAAMkEACAQAADYBAAgGAAAtQQAIBkAAMIEACChAgAA1QQAMKICAAArABCjAgAA1QQAMKQCAQD7AwAhpQIBAL4EACGsAkAA_wMAIa0CQAD_AwAh3QIBAPsDACHeAgEAvgQAId8CAQC-BAAh4QIAANYE4QIi4gIBAPsDACHjAgEA-wMAIeQCAQC-BAAh5gIAANcE5gIi5wJAAM4EACEErgIAAADhAgKvAgAAAOECCLACAAAA4QIItQIAAJUE4QIiBK4CAAAA5gICrwIAAADmAgiwAgAAAOYCCLUCAACTBOYCIh8EAADPBAAgBgAAtQQAIA0AAMQEACAOAADEBAAgDwAAwwQAIBYAALYEACAXAADkBAAgGgAA5QQAIKECAADhBAAwogIAABgAEKMCAADhBAAwpAIBAPsDACGlAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIdgCAQD7AwAh2wJAAM4EACHmAgAA4wT3AiLrAgEA-wMAIfUCAADiBPUCIvcCAACABAAg-AIBAL4EACH5AgEAvgQAIfoCAQC-BAAh-wJAAM4EACH8AkAAzgQAIf0CQADOBAAh_gJAAM4EACGaAwAAGAAgmwMAABgAIA8QAADbBAAgoQIAANkEADCiAgAAJwAQowIAANkEADCkAgEA-wMAIawCQAD_AwAhrQJAAP8DACHfAgEA-wMAIeYCAADaBOsCIugCAQD7AwAh6QIBAPsDACHrAgEAvgQAIewCAADBBAAg7QIBAL4EACHuAgEAvgQAIQSuAgAAAOsCAq8CAAAA6wIIsAIAAADrAgi1AgAAmQTrAiIfBAAAzwQAIAYAALUEACANAADEBAAgDgAAxAQAIA8AAMMEACAWAAC2BAAgFwAA5AQAIBoAAOUEACChAgAA4QQAMKICAAAYABCjAgAA4QQAMKQCAQD7AwAhpQIBAPsDACGpAgEA-wMAIawCQAD_AwAhrQJAAP8DACHYAgEA-wMAIdsCQADOBAAh5gIAAOME9wIi6wIBAPsDACH1AgAA4gT1AiL3AgAAgAQAIPgCAQC-BAAh-QIBAL4EACH6AgEAvgQAIfsCQADOBAAh_AJAAM4EACH9AkAAzgQAIf4CQADOBAAhmgMAABgAIJsDAAAYACAC3wIBAAAAAe8CAQAAAAEOEAAA2wQAIBEAALUEACAVAADgBAAgoQIAAN0EADCiAgAAHwAQowIAAN0EADCkAgEA-wMAIawCQAD_AwAhrQJAAP8DACHfAgEA-wMAIe8CAQD7AwAh8QIAAN4E8QIi8gIQAN8EACHzAgEAvgQAIQSuAgAAAPECAq8CAAAA8QIIsAIAAADxAgi1AgAAoATxAiIIrgIQAAAAAa8CEAAAAAWwAhAAAAAFsQIQAAAAAbICEAAAAAGzAhAAAAABtAIQAAAAAbUCEACeBAAhDhIAALUEACATAAC2BAAgoQIAALMEADCiAgAAIwAQowIAALMEADCkAgEA-wMAIawCQAD_AwAhvwIBAPsDACHAAhAAtAQAIcECAQD7AwAhwgIAAIAEACDDAkAA_wMAIZoDAAAjACCbAwAAIwAgHQQAAM8EACAGAAC1BAAgDQAAxAQAIA4AAMQEACAPAADDBAAgFgAAtgQAIBcAAOQEACAaAADlBAAgoQIAAOEEADCiAgAAGAAQowIAAOEEADCkAgEA-wMAIaUCAQD7AwAhqQIBAPsDACGsAkAA_wMAIa0CQAD_AwAh2AIBAPsDACHbAkAAzgQAIeYCAADjBPcCIusCAQD7AwAh9QIAAOIE9QIi9wIAAIAEACD4AgEAvgQAIfkCAQC-BAAh-gIBAL4EACH7AkAAzgQAIfwCQADOBAAh_QJAAM4EACH-AkAAzgQAIQSuAgAAAPUCAq8CAAAA9QIIsAIAAAD1Agi1AgAApwT1AiIErgIAAAD3AgKvAgAAAPcCCLACAAAA9wIItQIAAKUE9wIiA5ADAAAnACCRAwAAJwAgkgMAACcAIAOQAwAAKwAgkQMAACsAIJIDAAArACAEpQIBAAAAAeICAQAAAAH_AgEAAAABgAMBAAAAAQ4EAADPBAAgCQAA6AQAIAoAAOgEACChAgAA5wQAMKICAAATABCjAgAA5wQAMKQCAQD7AwAhpQIBAPsDACGrAgAAwQQAIKwCQAD_AwAhrQJAAP8DACHiAgEA-wMAIf8CAQD7AwAhgAMBAPsDACEYBAAAzwQAIAYAALUEACAIAADQBAAgCwAA0QQAIAwAANEEACAbAADSBAAgHAAA0gQAIKECAADLBAAwogIAABAAEKMCAADLBAAwpAIBAPsDACGlAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIccCAQC-BAAh2AIBAPsDACHbAkAAzgQAIeYCAADNBIYDIoEDAQD7AwAhgwMAAMwEgwMihAMAAIAEACCaAwAAEAAgmwMAABAAIBYWAAC2BAAgGgAA5QQAIB4AAMUEACAfAADSBAAgIAAA6wQAICEAAOwEACAkAADqBAAgJQAA5QQAICYAAO0EACAnAADuBAAgKAAA7wQAIKECAADpBAAwogIAAA0AEKMCAADpBAAwpAIBAPsDACGsAkAA_wMAIa0CQAD_AwAhiwMBAPsDACGMAwEA-wMAIY0DAQC-BAAhjgMBAL4EACGPAwEAvgQAIQOQAwAAAwAgkQMAAAMAIJIDAAADACADkAMAAAcAIJEDAAAHACCSAwAABwAgA5ADAAAQACCRAwAAEAAgkgMAABAAIAOQAwAACwAgkQMAAAsAIJIDAAALACADkAMAAF0AIJEDAABdACCSAwAAXQAgA5ADAAAjACCRAwAAIwAgkgMAACMAIAKlAgEAAAABhgMCAAAAAREEAADPBAAgBQAAtQQAIAgAANAEACAfAADSBAAgoQIAAPEEADCiAgAABwAQowIAAPEEADCkAgEA-wMAIaUCAQD7AwAhrAJAAP8DACGtAkAA_wMAIccCAQC-BAAh2wJAAM4EACGEAwAAgAQAIIYDAgD9AwAhhwMBAPsDACGIAwEAvgQAIREDAAC1BAAgGgAA5QQAIB8AANIEACAgAADrBAAgIQAA7AQAICIAANEEACAjAADzBAAgoQIAAPIEADCiAgAAAwAQowIAAPIEADCkAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIYEDAQD7AwAhiQMBAPsDACGKAwEA-wMAIQOQAwAASAAgkQMAAEgAIJIDAABIACAAAAAAAZ8DAQAAAAEBnwMAAACnAgIBnwNAAAAAAQGfAwEAAAABBzUAAJkKACA2AACcCgAgnAMAAJoKACCdAwAAmwoAIKADAAADACChAwAAAwAgogMAAAUAIAM1AACZCgAgnAMAAJoKACCiAwAABQAgAAAAAAAFnwMQAAAAAaUDEAAAAAGmAxAAAAABpwMQAAAAAagDEAAAAAEFNQAAiQoAIDYAAJcKACCcAwAAigoAIJ0DAACWCgAgogMAAAEAIAs1AACGBQAwNgAAiwUAMJwDAACHBQAwnQMAAIgFADCeAwAAiQUAIJ8DAACKBQAwoAMAAIoFADChAwAAigUAMKIDAACKBQAwowMAAIwFADCkAwAAjQUAMAkQAACWBQAgEQAAlwUAIKQCAQAAAAGsAkAAAAABrQJAAAAAAd8CAQAAAAHvAgEAAAAB8QIAAADxAgLyAhAAAAABAgAAACEAIDUAAJUFACADAAAAIQAgNQAAlQUAIDYAAJIFACABLgAAlQoAMA8QAADbBAAgEQAAtQQAIBUAAOAEACChAgAA3QQAMKICAAAfABCjAgAA3QQAMKQCAQAAAAGsAkAA_wMAIa0CQAD_AwAh3wIBAPsDACHvAgEA-wMAIfECAADeBPECIvICEADfBAAh8wIBAL4EACGXAwAA3AQAIAIAAAAhACAuAACSBQAgAgAAAI4FACAuAACPBQAgC6ECAACNBQAwogIAAI4FABCjAgAAjQUAMKQCAQD7AwAhrAJAAP8DACGtAkAA_wMAId8CAQD7AwAh7wIBAPsDACHxAgAA3gTxAiLyAhAA3wQAIfMCAQC-BAAhC6ECAACNBQAwogIAAI4FABCjAgAAjQUAMKQCAQD7AwAhrAJAAP8DACGtAkAA_wMAId8CAQD7AwAh7wIBAPsDACHxAgAA3gTxAiLyAhAA3wQAIfMCAQC-BAAhB6QCAQD4BAAhrAJAAPoEACGtAkAA-gQAId8CAQD4BAAh7wIBAPgEACHxAgAAkAXxAiLyAhAAkQUAIQGfAwAAAPECAgWfAxAAAAABpQMQAAAAAaYDEAAAAAGnAxAAAAABqAMQAAAAAQkQAACTBQAgEQAAlAUAIKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAId8CAQD4BAAh7wIBAPgEACHxAgAAkAXxAiLyAhAAkQUAIQU1AACNCgAgNgAAkwoAIJwDAACOCgAgnQMAAJIKACCiAwAAGgAgBTUAAIsKACA2AACQCgAgnAMAAIwKACCdAwAAjwoAIKIDAAABACAJEAAAlgUAIBEAAJcFACCkAgEAAAABrAJAAAAAAa0CQAAAAAHfAgEAAAAB7wIBAAAAAfECAAAA8QIC8gIQAAAAAQM1AACNCgAgnAMAAI4KACCiAwAAGgAgAzUAAIsKACCcAwAAjAoAIKIDAAABACADNQAAiQoAIJwDAACKCgAgogMAAAEAIAQ1AACGBQAwnAMAAIcFADCeAwAAiQUAIKIDAACKBQAwAAAAAAAFNQAAhAoAIDYAAIcKACCcAwAAhQoAIJ0DAACGCgAgogMAAAEAIAM1AACECgAgnAMAAIUKACCiAwAAAQAgAAAAAAABnwMAAADJAgIFnwMCAAAAAaUDAgAAAAGmAwIAAAABpwMCAAAAAagDAgAAAAEFnwMEAAAAAaUDBAAAAAGmAwQAAAABpwMEAAAAAagDBAAAAAEFNQAA_AkAIDYAAIIKACCcAwAA_QkAIJ0DAACBCgAgogMAAAEAIAc1AAD6CQAgNgAA_wkAIJwDAAD7CQAgnQMAAP4JACCgAwAACwAgoQMAAAsAIKIDAABaACADNQAA_AkAIJwDAAD9CQAgogMAAAEAIAM1AAD6CQAgnAMAAPsJACCiAwAAWgAgAAAAAAABnwMAAADRAgIAAAAAAAGfAwAAANcCAgWfAwQAAAABpQMEAAAAAaYDBAAAAAGnAwQAAAABqAMEAAAAAQWfAwIAAAABpQMCAAAAAaYDAgAAAAGnAwIAAAABqAMCAAAAAQc1AACcCQAgNgAA-AkAIJwDAACdCQAgnQMAAPcJACCgAwAADQAgoQMAAA0AIKIDAAABACAHNQAAzQYAIDYAANAGACCcAwAAzgYAIJ0DAADPBgAgoAMAAAcAIKEDAAAHACCiAwAACQAgBzUAAMsFACA2AADOBQAgnAMAAMwFACCdAwAAzQUAIKADAAAQACChAwAAEAAgogMAAEMAIAs1AAC_BQAwNgAAxAUAMJwDAADABQAwnQMAAMEFADCeAwAAwgUAIJ8DAADDBQAwoAMAAMMFADChAwAAwwUAMKIDAADDBQAwowMAAMUFADCkAwAAxgUAMA0SAACrBQAgpAIBAAAAAawCQAAAAAGtAkAAAAABvwIBAAAAAcQCAQAAAAHJAgAAAMkCAsoCEAAAAAHLAgEAAAABzAICAAAAAc0CBAAAAAHOAkAAAAABzwIBAAAAAQIAAAA8ACA1AADKBQAgAwAAADwAIDUAAMoFACA2AADJBQAgAS4AAPYJADASCAAA0AQAIBIAALUEACChAgAA0wQAMKICAAA6ABCjAgAA0wQAMKQCAQAAAAGsAkAA_wMAIa0CQAD_AwAhvwIBAPsDACHEAgEA-wMAIccCAQC-BAAhyQIAANQEyQIiygIQALQEACHLAgEA-wMAIcwCAgD9AwAhzQIEAPwDACHOAkAA_wMAIc8CAQAAAAECAAAAPAAgLgAAyQUAIAIAAADHBQAgLgAAyAUAIBChAgAAxgUAMKICAADHBQAQowIAAMYFADCkAgEA-wMAIawCQAD_AwAhrQJAAP8DACG_AgEA-wMAIcQCAQD7AwAhxwIBAL4EACHJAgAA1ATJAiLKAhAAtAQAIcsCAQD7AwAhzAICAP0DACHNAgQA_AMAIc4CQAD_AwAhzwIBAPsDACEQoQIAAMYFADCiAgAAxwUAEKMCAADGBQAwpAIBAPsDACGsAkAA_wMAIa0CQAD_AwAhvwIBAPsDACHEAgEA-wMAIccCAQC-BAAhyQIAANQEyQIiygIQALQEACHLAgEA-wMAIcwCAgD9AwAhzQIEAPwDACHOAkAA_wMAIc8CAQD7AwAhDKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIb8CAQD4BAAhxAIBAPgEACHJAgAApgXJAiLKAhAAgwUAIcsCAQD4BAAhzAICAKcFACHNAgQAqAUAIc4CQAD6BAAhzwIBAPgEACENEgAAqQUAIKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIb8CAQD4BAAhxAIBAPgEACHJAgAApgXJAiLKAhAAgwUAIcsCAQD4BAAhzAICAKcFACHNAgQAqAUAIc4CQAD6BAAhzwIBAPgEACENEgAAqwUAIKQCAQAAAAGsAkAAAAABrQJAAAAAAb8CAQAAAAHEAgEAAAAByQIAAADJAgLKAhAAAAABywIBAAAAAcwCAgAAAAHNAgQAAAABzgJAAAAAAc8CAQAAAAERBAAAxwYAIAYAAMgGACALAADJBgAgDAAAygYAIBsAAMsGACAcAADMBgAgpAIBAAAAAaUCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAHYAgEAAAAB2wJAAAAAAeYCAAAAhgMCgQMBAAAAAYMDAAAAgwMChAOAAAAAAQIAAABDACA1AADLBQAgAwAAABAAIDUAAMsFACA2AADPBQAgEwAAABAAIAQAANMFACAGAADUBQAgCwAA1QUAIAwAANYFACAbAADXBQAgHAAA2AUAIC4AAM8FACCkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAh2AIBAPgEACHbAkAA0gUAIeYCAADRBYYDIoEDAQD4BAAhgwMAANAFgwMihAOAAAAAAREEAADTBQAgBgAA1AUAIAsAANUFACAMAADWBQAgGwAA1wUAIBwAANgFACCkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAh2AIBAPgEACHbAkAA0gUAIeYCAADRBYYDIoEDAQD4BAAhgwMAANAFgwMihAOAAAAAAQGfAwAAAIMDAgGfAwAAAIYDAgGfA0AAAAABBTUAAKsJACA2AAD0CQAgnAMAAKwJACCdAwAA8wkAIKIDAAAFACAFNQAAqQkAIDYAAPEJACCcAwAAqgkAIJ0DAADwCQAgogMAAAEAIAs1AAC8BgAwNgAAwAYAMJwDAAC9BgAwnQMAAL4GADCeAwAAvwYAIJ8DAACwBgAwoAMAALAGADChAwAAsAYAMKIDAACwBgAwowMAAMEGADCkAwAAswYAMAs1AACsBgAwNgAAsQYAMJwDAACtBgAwnQMAAK4GADCeAwAArwYAIJ8DAACwBgAwoAMAALAGADChAwAAsAYAMKIDAACwBgAwowMAALIGADCkAwAAswYAMAs1AAChBgAwNgAApQYAMJwDAACiBgAwnQMAAKMGADCeAwAApAYAIJ8DAADdBQAwoAMAAN0FADChAwAA3QUAMKIDAADdBQAwowMAAKYGADCkAwAA4AUAMAs1AADZBQAwNgAA3gUAMJwDAADaBQAwnQMAANsFADCeAwAA3AUAIJ8DAADdBQAwoAMAAN0FADChAwAA3QUAMKIDAADdBQAwowMAAN8FADCkAwAA4AUAMBgEAACaBgAgBgAAmwYAIA0AAJwGACAPAACdBgAgFgAAngYAIBcAAJ8GACAaAACgBgAgpAIBAAAAAaUCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAHYAgEAAAAB2wJAAAAAAeYCAAAA9wIC6wIBAAAAAfUCAAAA9QIC9wKAAAAAAfgCAQAAAAH6AgEAAAAB-wJAAAAAAfwCQAAAAAH9AkAAAAAB_gJAAAAAAQIAAAAaACA1AACZBgAgAwAAABoAIDUAAJkGACA2AADlBQAgAS4AAO8JADAdBAAAzwQAIAYAALUEACANAADEBAAgDgAAxAQAIA8AAMMEACAWAAC2BAAgFwAA5AQAIBoAAOUEACChAgAA4QQAMKICAAAYABCjAgAA4QQAMKQCAQAAAAGlAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIdgCAQD7AwAh2wJAAM4EACHmAgAA4wT3AiLrAgEA-wMAIfUCAADiBPUCIvcCAACABAAg-AIBAL4EACH5AgEAvgQAIfoCAQAAAAH7AkAAzgQAIfwCQADOBAAh_QJAAM4EACH-AkAAzgQAIQIAAAAaACAuAADlBQAgAgAAAOEFACAuAADiBQAgFaECAADgBQAwogIAAOEFABCjAgAA4AUAMKQCAQD7AwAhpQIBAPsDACGpAgEA-wMAIawCQAD_AwAhrQJAAP8DACHYAgEA-wMAIdsCQADOBAAh5gIAAOME9wIi6wIBAPsDACH1AgAA4gT1AiL3AgAAgAQAIPgCAQC-BAAh-QIBAL4EACH6AgEAvgQAIfsCQADOBAAh_AJAAM4EACH9AkAAzgQAIf4CQADOBAAhFaECAADgBQAwogIAAOEFABCjAgAA4AUAMKQCAQD7AwAhpQIBAPsDACGpAgEA-wMAIawCQAD_AwAhrQJAAP8DACHYAgEA-wMAIdsCQADOBAAh5gIAAOME9wIi6wIBAPsDACH1AgAA4gT1AiL3AgAAgAQAIPgCAQC-BAAh-QIBAL4EACH6AgEAvgQAIfsCQADOBAAh_AJAAM4EACH9AkAAzgQAIf4CQADOBAAhEaQCAQD4BAAhpQIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHYAgEA-AQAIdsCQADSBQAh5gIAAOQF9wIi6wIBAPgEACH1AgAA4wX1AiL3AoAAAAAB-AIBAPsEACH6AgEA-wQAIfsCQADSBQAh_AJAANIFACH9AkAA0gUAIf4CQADSBQAhAZ8DAAAA9QICAZ8DAAAA9wICGAQAAOYFACAGAADnBQAgDQAA6AUAIA8AAOkFACAWAADqBQAgFwAA6wUAIBoAAOwFACCkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAh2AIBAPgEACHbAkAA0gUAIeYCAADkBfcCIusCAQD4BAAh9QIAAOMF9QIi9wKAAAAAAfgCAQD7BAAh-gIBAPsEACH7AkAA0gUAIfwCQADSBQAh_QJAANIFACH-AkAA0gUAIQU1AADKCQAgNgAA7QkAIJwDAADLCQAgnQMAAOwJACCiAwAABQAgBTUAAMgJACA2AADqCQAgnAMAAMkJACCdAwAA6QkAIKIDAAABACAHNQAAxgkAIDYAAOcJACCcAwAAxwkAIJ0DAADmCQAgoAMAABAAIKEDAAAQACCiAwAAQwAgBzUAAMQJACA2AADkCQAgnAMAAMUJACCdAwAA4wkAIKADAAAHACChAwAABwAgogMAAAkAIAs1AACOBgAwNgAAkgYAMJwDAACPBgAwnQMAAJAGADCeAwAAkQYAIJ8DAACKBQAwoAMAAIoFADChAwAAigUAMKIDAACKBQAwowMAAJMGADCkAwAAjQUAMAs1AACBBgAwNgAAhgYAMJwDAACCBgAwnQMAAIMGADCeAwAAhAYAIJ8DAACFBgAwoAMAAIUGADChAwAAhQYAMKIDAACFBgAwowMAAIcGADCkAwAAiAYAMAs1AADtBQAwNgAA8gUAMJwDAADuBQAwnQMAAO8FADCeAwAA8AUAIJ8DAADxBQAwoAMAAPEFADChAwAA8QUAMKIDAADxBQAwowMAAPMFADCkAwAA9AUAMA8EAACABgAgGAAA_gUAIBkAAP8FACCkAgEAAAABpQIBAAAAAawCQAAAAAGtAkAAAAAB3QIBAAAAAd4CAQAAAAHhAgAAAOECAuICAQAAAAHjAgEAAAAB5AIBAAAAAeYCAAAA5gIC5wJAAAAAAQIAAAAtACA1AAD9BQAgAwAAAC0AIDUAAP0FACA2AAD5BQAgAS4AAOIJADAUBAAAyQQAIBAAANgEACAYAAC1BAAgGQAAwgQAIKECAADVBAAwogIAACsAEKMCAADVBAAwpAIBAAAAAaUCAQC-BAAhrAJAAP8DACGtAkAA_wMAId0CAQD7AwAh3gIBAL4EACHfAgEAvgQAIeECAADWBOECIuICAQD7AwAh4wIBAPsDACHkAgEAvgQAIeYCAADXBOYCIucCQADOBAAhAgAAAC0AIC4AAPkFACACAAAA9QUAIC4AAPYFACAQoQIAAPQFADCiAgAA9QUAEKMCAAD0BQAwpAIBAPsDACGlAgEAvgQAIawCQAD_AwAhrQJAAP8DACHdAgEA-wMAId4CAQC-BAAh3wIBAL4EACHhAgAA1gThAiLiAgEA-wMAIeMCAQD7AwAh5AIBAL4EACHmAgAA1wTmAiLnAkAAzgQAIRChAgAA9AUAMKICAAD1BQAQowIAAPQFADCkAgEA-wMAIaUCAQC-BAAhrAJAAP8DACGtAkAA_wMAId0CAQD7AwAh3gIBAL4EACHfAgEAvgQAIeECAADWBOECIuICAQD7AwAh4wIBAPsDACHkAgEAvgQAIeYCAADXBOYCIucCQADOBAAhDKQCAQD4BAAhpQIBAPsEACGsAkAA-gQAIa0CQAD6BAAh3QIBAPgEACHeAgEA-wQAIeECAAD3BeECIuICAQD4BAAh4wIBAPgEACHkAgEA-wQAIeYCAAD4BeYCIucCQADSBQAhAZ8DAAAA4QICAZ8DAAAA5gICDwQAAPwFACAYAAD6BQAgGQAA-wUAIKQCAQD4BAAhpQIBAPsEACGsAkAA-gQAIa0CQAD6BAAh3QIBAPgEACHeAgEA-wQAIeECAAD3BeECIuICAQD4BAAh4wIBAPgEACHkAgEA-wQAIeYCAAD4BeYCIucCQADSBQAhBTUAANcJACA2AADgCQAgnAMAANgJACCdAwAA3wkAIKIDAAABACAHNQAA1QkAIDYAAN0JACCcAwAA1gkAIJ0DAADcCQAgoAMAAA0AIKEDAAANACCiAwAAAQAgBzUAANMJACA2AADaCQAgnAMAANQJACCdAwAA2QkAIKADAAADACChAwAAAwAgogMAAAUAIA8EAACABgAgGAAA_gUAIBkAAP8FACCkAgEAAAABpQIBAAAAAawCQAAAAAGtAkAAAAAB3QIBAAAAAd4CAQAAAAHhAgAAAOECAuICAQAAAAHjAgEAAAAB5AIBAAAAAeYCAAAA5gIC5wJAAAAAAQM1AADXCQAgnAMAANgJACCiAwAAAQAgAzUAANUJACCcAwAA1gkAIKIDAAABACADNQAA0wkAIJwDAADUCQAgogMAAAUAIAqkAgEAAAABrAJAAAAAAa0CQAAAAAHmAgAAAOsCAugCAQAAAAHpAgEAAAAB6wIBAAAAAewCgAAAAAHtAgEAAAAB7gIBAAAAAQIAAAApACA1AACNBgAgAwAAACkAIDUAAI0GACA2AACMBgAgAS4AANIJADAPEAAA2wQAIKECAADZBAAwogIAACcAEKMCAADZBAAwpAIBAAAAAawCQAD_AwAhrQJAAP8DACHfAgEA-wMAIeYCAADaBOsCIugCAQD7AwAh6QIBAPsDACHrAgEAvgQAIewCAADBBAAg7QIBAL4EACHuAgEAvgQAIQIAAAApACAuAACMBgAgAgAAAIkGACAuAACKBgAgDqECAACIBgAwogIAAIkGABCjAgAAiAYAMKQCAQD7AwAhrAJAAP8DACGtAkAA_wMAId8CAQD7AwAh5gIAANoE6wIi6AIBAPsDACHpAgEA-wMAIesCAQC-BAAh7AIAAMEEACDtAgEAvgQAIe4CAQC-BAAhDqECAACIBgAwogIAAIkGABCjAgAAiAYAMKQCAQD7AwAhrAJAAP8DACGtAkAA_wMAId8CAQD7AwAh5gIAANoE6wIi6AIBAPsDACHpAgEA-wMAIesCAQC-BAAh7AIAAMEEACDtAgEAvgQAIe4CAQC-BAAhCqQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIeYCAACLBusCIugCAQD4BAAh6QIBAPgEACHrAgEA-wQAIewCgAAAAAHtAgEA-wQAIe4CAQD7BAAhAZ8DAAAA6wICCqQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIeYCAACLBusCIugCAQD4BAAh6QIBAPgEACHrAgEA-wQAIewCgAAAAAHtAgEA-wQAIe4CAQD7BAAhCqQCAQAAAAGsAkAAAAABrQJAAAAAAeYCAAAA6wIC6AIBAAAAAekCAQAAAAHrAgEAAAAB7AKAAAAAAe0CAQAAAAHuAgEAAAABCREAAJcFACAVAACYBgAgpAIBAAAAAawCQAAAAAGtAkAAAAAB7wIBAAAAAfECAAAA8QIC8gIQAAAAAfMCAQAAAAECAAAAIQAgNQAAlwYAIAMAAAAhACA1AACXBgAgNgAAlQYAIAEuAADRCQAwAgAAACEAIC4AAJUGACACAAAAjgUAIC4AAJQGACAHpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAh7wIBAPgEACHxAgAAkAXxAiLyAhAAkQUAIfMCAQD7BAAhCREAAJQFACAVAACWBgAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAh7wIBAPgEACHxAgAAkAXxAiLyAhAAkQUAIfMCAQD7BAAhBzUAAMwJACA2AADPCQAgnAMAAM0JACCdAwAAzgkAIKADAAAjACChAwAAIwAgogMAAGIAIAkRAACXBQAgFQAAmAYAIKQCAQAAAAGsAkAAAAABrQJAAAAAAe8CAQAAAAHxAgAAAPECAvICEAAAAAHzAgEAAAABAzUAAMwJACCcAwAAzQkAIKIDAABiACAYBAAAmgYAIAYAAJsGACANAACcBgAgDwAAnQYAIBYAAJ4GACAXAACfBgAgGgAAoAYAIKQCAQAAAAGlAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAAB2AIBAAAAAdsCQAAAAAHmAgAAAPcCAusCAQAAAAH1AgAAAPUCAvcCgAAAAAH4AgEAAAAB-gIBAAAAAfsCQAAAAAH8AkAAAAAB_QJAAAAAAf4CQAAAAAEDNQAAygkAIJwDAADLCQAgogMAAAUAIAM1AADICQAgnAMAAMkJACCiAwAAAQAgAzUAAMYJACCcAwAAxwkAIKIDAABDACADNQAAxAkAIJwDAADFCQAgogMAAAkAIAQ1AACOBgAwnAMAAI8GADCeAwAAkQYAIKIDAACKBQAwBDUAAIEGADCcAwAAggYAMJ4DAACEBgAgogMAAIUGADAENQAA7QUAMJwDAADuBQAwngMAAPAFACCiAwAA8QUAMBgEAACaBgAgBgAAmwYAIA4AAKsGACAPAACdBgAgFgAAngYAIBcAAJ8GACAaAACgBgAgpAIBAAAAAaUCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAHYAgEAAAAB2wJAAAAAAeYCAAAA9wIC6wIBAAAAAfUCAAAA9QIC9wKAAAAAAfkCAQAAAAH6AgEAAAAB-wJAAAAAAfwCQAAAAAH9AkAAAAAB_gJAAAAAAQIAAAAaACA1AACqBgAgAwAAABoAIDUAAKoGACA2AACoBgAgAS4AAMMJADACAAAAGgAgLgAAqAYAIAIAAADhBQAgLgAApwYAIBGkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAh2AIBAPgEACHbAkAA0gUAIeYCAADkBfcCIusCAQD4BAAh9QIAAOMF9QIi9wKAAAAAAfkCAQD7BAAh-gIBAPsEACH7AkAA0gUAIfwCQADSBQAh_QJAANIFACH-AkAA0gUAIRgEAADmBQAgBgAA5wUAIA4AAKkGACAPAADpBQAgFgAA6gUAIBcAAOsFACAaAADsBQAgpAIBAPgEACGlAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIdgCAQD4BAAh2wJAANIFACHmAgAA5AX3AiLrAgEA-AQAIfUCAADjBfUCIvcCgAAAAAH5AgEA-wQAIfoCAQD7BAAh-wJAANIFACH8AkAA0gUAIf0CQADSBQAh_gJAANIFACEHNQAAvgkAIDYAAMEJACCcAwAAvwkAIJ0DAADACQAgoAMAABAAIKEDAAAQACCiAwAAQwAgGAQAAJoGACAGAACbBgAgDgAAqwYAIA8AAJ0GACAWAACeBgAgFwAAnwYAIBoAAKAGACCkAgEAAAABpQIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAdgCAQAAAAHbAkAAAAAB5gIAAAD3AgLrAgEAAAAB9QIAAAD1AgL3AoAAAAAB-QIBAAAAAfoCAQAAAAH7AkAAAAAB_AJAAAAAAf0CQAAAAAH-AkAAAAABAzUAAL4JACCcAwAAvwkAIKIDAABDACAJBAAAugYAIAkAALsGACCkAgEAAAABpQIBAAAAAasCgAAAAAGsAkAAAAABrQJAAAAAAf8CAQAAAAGAAwEAAAABAgAAABUAIDUAALkGACADAAAAFQAgNQAAuQYAIDYAALYGACABLgAAvQkAMA8EAADPBAAgCQAA6AQAIAoAAOgEACChAgAA5wQAMKICAAATABCjAgAA5wQAMKQCAQAAAAGlAgEA-wMAIasCAADBBAAgrAJAAP8DACGtAkAA_wMAIeICAQD7AwAh_wIBAPsDACGAAwEA-wMAIZgDAADmBAAgAgAAABUAIC4AALYGACACAAAAtAYAIC4AALUGACALoQIAALMGADCiAgAAtAYAEKMCAACzBgAwpAIBAPsDACGlAgEA-wMAIasCAADBBAAgrAJAAP8DACGtAkAA_wMAIeICAQD7AwAh_wIBAPsDACGAAwEA-wMAIQuhAgAAswYAMKICAAC0BgAQowIAALMGADCkAgEA-wMAIaUCAQD7AwAhqwIAAMEEACCsAkAA_wMAIa0CQAD_AwAh4gIBAPsDACH_AgEA-wMAIYADAQD7AwAhB6QCAQD4BAAhpQIBAPgEACGrAoAAAAABrAJAAPoEACGtAkAA-gQAIf8CAQD4BAAhgAMBAPgEACEJBAAAtwYAIAkAALgGACCkAgEA-AQAIaUCAQD4BAAhqwKAAAAAAawCQAD6BAAhrQJAAPoEACH_AgEA-AQAIYADAQD4BAAhBTUAALUJACA2AAC7CQAgnAMAALYJACCdAwAAugkAIKIDAAAFACAFNQAAswkAIDYAALgJACCcAwAAtAkAIJ0DAAC3CQAgogMAAEMAIAkEAAC6BgAgCQAAuwYAIKQCAQAAAAGlAgEAAAABqwKAAAAAAawCQAAAAAGtAkAAAAAB_wIBAAAAAYADAQAAAAEDNQAAtQkAIJwDAAC2CQAgogMAAAUAIAM1AACzCQAgnAMAALQJACCiAwAAQwAgCQQAALoGACAKAADGBgAgpAIBAAAAAaUCAQAAAAGrAoAAAAABrAJAAAAAAa0CQAAAAAHiAgEAAAABgAMBAAAAAQIAAAAVACA1AADFBgAgAwAAABUAIDUAAMUGACA2AADDBgAgAS4AALIJADACAAAAFQAgLgAAwwYAIAIAAAC0BgAgLgAAwgYAIAekAgEA-AQAIaUCAQD4BAAhqwKAAAAAAawCQAD6BAAhrQJAAPoEACHiAgEA-AQAIYADAQD4BAAhCQQAALcGACAKAADEBgAgpAIBAPgEACGlAgEA-AQAIasCgAAAAAGsAkAA-gQAIa0CQAD6BAAh4gIBAPgEACGAAwEA-AQAIQU1AACtCQAgNgAAsAkAIJwDAACuCQAgnQMAAK8JACCiAwAAQwAgCQQAALoGACAKAADGBgAgpAIBAAAAAaUCAQAAAAGrAoAAAAABrAJAAAAAAa0CQAAAAAHiAgEAAAABgAMBAAAAAQM1AACtCQAgnAMAAK4JACCiAwAAQwAgAzUAAKsJACCcAwAArAkAIKIDAAAFACADNQAAqQkAIJwDAACqCQAgogMAAAEAIAQ1AAC8BgAwnAMAAL0GADCeAwAAvwYAIKIDAACwBgAwBDUAAKwGADCcAwAArQYAMJ4DAACvBgAgogMAALAGADAENQAAoQYAMJwDAACiBgAwngMAAKQGACCiAwAA3QUAMAQ1AADZBQAwnAMAANoFADCeAwAA3AUAIKIDAADdBQAwDAQAAN4GACAFAADfBgAgHwAA4AYAIKQCAQAAAAGlAgEAAAABrAJAAAAAAa0CQAAAAAHbAkAAAAABhAOAAAAAAYYDAgAAAAGHAwEAAAABiAMBAAAAAQIAAAAJACA1AADNBgAgAwAAAAcAIDUAAM0GACA2AADRBgAgDgAAAAcAIAQAANIGACAFAADTBgAgHwAA1AYAIC4AANEGACCkAgEA-AQAIaUCAQD4BAAhrAJAAPoEACGtAkAA-gQAIdsCQADSBQAhhAOAAAAAAYYDAgCnBQAhhwMBAPgEACGIAwEA-wQAIQwEAADSBgAgBQAA0wYAIB8AANQGACCkAgEA-AQAIaUCAQD4BAAhrAJAAPoEACGtAkAA-gQAIdsCQADSBQAhhAOAAAAAAYYDAgCnBQAhhwMBAPgEACGIAwEA-wQAIQU1AACgCQAgNgAApwkAIJwDAAChCQAgnQMAAKYJACCiAwAABQAgBTUAAJ4JACA2AACkCQAgnAMAAJ8JACCdAwAAowkAIKIDAAABACALNQAA1QYAMDYAANkGADCcAwAA1gYAMJ0DAADXBgAwngMAANgGACCfAwAA3QUAMKADAADdBQAwoQMAAN0FADCiAwAA3QUAMKMDAADaBgAwpAMAAOAFADAYBAAAmgYAIAYAAJsGACANAACcBgAgDgAAqwYAIBYAAJ4GACAXAACfBgAgGgAAoAYAIKQCAQAAAAGlAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAAB2AIBAAAAAdsCQAAAAAHmAgAAAPcCAusCAQAAAAH1AgAAAPUCAvcCgAAAAAH4AgEAAAAB-QIBAAAAAfsCQAAAAAH8AkAAAAAB_QJAAAAAAf4CQAAAAAECAAAAGgAgNQAA3QYAIAMAAAAaACA1AADdBgAgNgAA3AYAIAEuAACiCQAwAgAAABoAIC4AANwGACACAAAA4QUAIC4AANsGACARpAIBAPgEACGlAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIdgCAQD4BAAh2wJAANIFACHmAgAA5AX3AiLrAgEA-AQAIfUCAADjBfUCIvcCgAAAAAH4AgEA-wQAIfkCAQD7BAAh-wJAANIFACH8AkAA0gUAIf0CQADSBQAh_gJAANIFACEYBAAA5gUAIAYAAOcFACANAADoBQAgDgAAqQYAIBYAAOoFACAXAADrBQAgGgAA7AUAIKQCAQD4BAAhpQIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHYAgEA-AQAIdsCQADSBQAh5gIAAOQF9wIi6wIBAPgEACH1AgAA4wX1AiL3AoAAAAAB-AIBAPsEACH5AgEA-wQAIfsCQADSBQAh_AJAANIFACH9AkAA0gUAIf4CQADSBQAhGAQAAJoGACAGAACbBgAgDQAAnAYAIA4AAKsGACAWAACeBgAgFwAAnwYAIBoAAKAGACCkAgEAAAABpQIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAdgCAQAAAAHbAkAAAAAB5gIAAAD3AgLrAgEAAAAB9QIAAAD1AgL3AoAAAAAB-AIBAAAAAfkCAQAAAAH7AkAAAAAB_AJAAAAAAf0CQAAAAAH-AkAAAAABAzUAAKAJACCcAwAAoQkAIKIDAAAFACADNQAAngkAIJwDAACfCQAgogMAAAEAIAQ1AADVBgAwnAMAANYGADCeAwAA2AYAIKIDAADdBQAwAzUAAJwJACCcAwAAnQkAIKIDAAABACADNQAAzQYAIJwDAADOBgAgogMAAAkAIAM1AADLBQAgnAMAAMwFACCiAwAAQwAgBDUAAL8FADCcAwAAwAUAMJ4DAADCBQAgogMAAMMFADAAAAAHNQAAlwkAIDYAAJoJACCcAwAAmAkAIJ0DAACZCQAgoAMAABgAIKEDAAAYACCiAwAAGgAgAzUAAJcJACCcAwAAmAkAIKIDAAAaACAAAAAFNQAAkgkAIDYAAJUJACCcAwAAkwkAIJ0DAACUCQAgogMAABoAIAM1AACSCQAgnAMAAJMJACCiAwAAGgAgAAAAAAAAAAAAAAAAAAAHNQAAjQkAIDYAAJAJACCcAwAAjgkAIJ0DAACPCQAgoAMAAAsAIKEDAAALACCiAwAAWgAgAzUAAI0JACCcAwAAjgkAIKIDAABaACAAAAAAAAc1AACICQAgNgAAiwkAIJwDAACJCQAgnQMAAIoJACCgAwAACwAgoQMAAAsAIKIDAABaACADNQAAiAkAIJwDAACJCQAgogMAAFoAIAAAAAU1AAD9CAAgNgAAhgkAIJwDAAD-CAAgnQMAAIUJACCiAwAAAQAgCzUAAMMHADA2AADIBwAwnAMAAMQHADCdAwAAxQcAMJ4DAADGBwAgnwMAAMcHADCgAwAAxwcAMKEDAADHBwAwogMAAMcHADCjAwAAyQcAMKQDAADKBwAwCzUAALcHADA2AAC8BwAwnAMAALgHADCdAwAAuQcAMJ4DAAC6BwAgnwMAALsHADCgAwAAuwcAMKEDAAC7BwAwogMAALsHADCjAwAAvQcAMKQDAAC-BwAwCzUAAK4HADA2AACyBwAwnAMAAK8HADCdAwAAsAcAMJ4DAACxBwAgnwMAALAGADCgAwAAsAYAMKEDAACwBgAwogMAALAGADCjAwAAswcAMKQDAACzBgAwCzUAAKUHADA2AACpBwAwnAMAAKYHADCdAwAApwcAMJ4DAACoBwAgnwMAAN0FADCgAwAA3QUAMKEDAADdBQAwogMAAN0FADCjAwAAqgcAMKQDAADgBQAwCzUAAJwHADA2AACgBwAwnAMAAJ0HADCdAwAAngcAMJ4DAACfBwAgnwMAAPEFADCgAwAA8QUAMKEDAADxBQAwogMAAPEFADCjAwAAoQcAMKQDAAD0BQAwCzUAAJAHADA2AACVBwAwnAMAAJEHADCdAwAAkgcAMJ4DAACTBwAgnwMAAJQHADCgAwAAlAcAMKEDAACUBwAwogMAAJQHADCjAwAAlgcAMKQDAACXBwAwCKQCAQAAAAGnAgAAAKcCAqgCAQAAAAGpAgEAAAABqgIBAAAAAasCgAAAAAGsAkAAAAABrQJAAAAAAQIAAABKACA1AACbBwAgAwAAAEoAIDUAAJsHACA2AACaBwAgAS4AAIQJADAOBAAAyQQAIKECAADHBAAwogIAAEgAEKMCAADHBAAwpAIBAAAAAaUCAQC-BAAhpwIAAMgEpwIiqAIBAPsDACGpAgEA-wMAIaoCAQD7AwAhqwIAAMEEACCsAkAA_wMAIa0CQAD_AwAhlAMAAMYEACACAAAASgAgLgAAmgcAIAIAAACYBwAgLgAAmQcAIAyhAgAAlwcAMKICAACYBwAQowIAAJcHADCkAgEA-wMAIaUCAQC-BAAhpwIAAMgEpwIiqAIBAPsDACGpAgEA-wMAIaoCAQD7AwAhqwIAAMEEACCsAkAA_wMAIa0CQAD_AwAhDKECAACXBwAwogIAAJgHABCjAgAAlwcAMKQCAQD7AwAhpQIBAL4EACGnAgAAyASnAiKoAgEA-wMAIakCAQD7AwAhqgIBAPsDACGrAgAAwQQAIKwCQAD_AwAhrQJAAP8DACEIpAIBAPgEACGnAgAA-QSnAiKoAgEA-AQAIakCAQD4BAAhqgIBAPgEACGrAoAAAAABrAJAAPoEACGtAkAA-gQAIQikAgEA-AQAIacCAAD5BKcCIqgCAQD4BAAhqQIBAPgEACGqAgEA-AQAIasCgAAAAAGsAkAA-gQAIa0CQAD6BAAhCKQCAQAAAAGnAgAAAKcCAqgCAQAAAAGpAgEAAAABqgIBAAAAAasCgAAAAAGsAkAAAAABrQJAAAAAAQ8QAADpBgAgGAAA_gUAIBkAAP8FACCkAgEAAAABrAJAAAAAAa0CQAAAAAHdAgEAAAAB3gIBAAAAAd8CAQAAAAHhAgAAAOECAuICAQAAAAHjAgEAAAAB5AIBAAAAAeYCAAAA5gIC5wJAAAAAAQIAAAAtACA1AACkBwAgAwAAAC0AIDUAAKQHACA2AACjBwAgAS4AAIMJADACAAAALQAgLgAAowcAIAIAAAD1BQAgLgAAogcAIAykAgEA-AQAIawCQAD6BAAhrQJAAPoEACHdAgEA-AQAId4CAQD7BAAh3wIBAPsEACHhAgAA9wXhAiLiAgEA-AQAIeMCAQD4BAAh5AIBAPsEACHmAgAA-AXmAiLnAkAA0gUAIQ8QAADoBgAgGAAA-gUAIBkAAPsFACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACHdAgEA-AQAId4CAQD7BAAh3wIBAPsEACHhAgAA9wXhAiLiAgEA-AQAIeMCAQD4BAAh5AIBAPsEACHmAgAA-AXmAiLnAkAA0gUAIQ8QAADpBgAgGAAA_gUAIBkAAP8FACCkAgEAAAABrAJAAAAAAa0CQAAAAAHdAgEAAAAB3gIBAAAAAd8CAQAAAAHhAgAAAOECAuICAQAAAAHjAgEAAAAB5AIBAAAAAeYCAAAA5gIC5wJAAAAAARgGAACbBgAgDQAAnAYAIA4AAKsGACAPAACdBgAgFgAAngYAIBcAAJ8GACAaAACgBgAgpAIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAdgCAQAAAAHbAkAAAAAB5gIAAAD3AgLrAgEAAAAB9QIAAAD1AgL3AoAAAAAB-AIBAAAAAfkCAQAAAAH6AgEAAAAB-wJAAAAAAfwCQAAAAAH9AkAAAAAB_gJAAAAAAQIAAAAaACA1AACtBwAgAwAAABoAIDUAAK0HACA2AACsBwAgAS4AAIIJADACAAAAGgAgLgAArAcAIAIAAADhBQAgLgAAqwcAIBGkAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIdgCAQD4BAAh2wJAANIFACHmAgAA5AX3AiLrAgEA-AQAIfUCAADjBfUCIvcCgAAAAAH4AgEA-wQAIfkCAQD7BAAh-gIBAPsEACH7AkAA0gUAIfwCQADSBQAh_QJAANIFACH-AkAA0gUAIRgGAADnBQAgDQAA6AUAIA4AAKkGACAPAADpBQAgFgAA6gUAIBcAAOsFACAaAADsBQAgpAIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHYAgEA-AQAIdsCQADSBQAh5gIAAOQF9wIi6wIBAPgEACH1AgAA4wX1AiL3AoAAAAAB-AIBAPsEACH5AgEA-wQAIfoCAQD7BAAh-wJAANIFACH8AkAA0gUAIf0CQADSBQAh_gJAANIFACEYBgAAmwYAIA0AAJwGACAOAACrBgAgDwAAnQYAIBYAAJ4GACAXAACfBgAgGgAAoAYAIKQCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAHYAgEAAAAB2wJAAAAAAeYCAAAA9wIC6wIBAAAAAfUCAAAA9QIC9wKAAAAAAfgCAQAAAAH5AgEAAAAB-gIBAAAAAfsCQAAAAAH8AkAAAAAB_QJAAAAAAf4CQAAAAAEJCQAAuwYAIAoAAMYGACCkAgEAAAABqwKAAAAAAawCQAAAAAGtAkAAAAAB4gIBAAAAAf8CAQAAAAGAAwEAAAABAgAAABUAIDUAALYHACADAAAAFQAgNQAAtgcAIDYAALUHACABLgAAgQkAMAIAAAAVACAuAAC1BwAgAgAAALQGACAuAAC0BwAgB6QCAQD4BAAhqwKAAAAAAawCQAD6BAAhrQJAAPoEACHiAgEA-AQAIf8CAQD4BAAhgAMBAPgEACEJCQAAuAYAIAoAAMQGACCkAgEA-AQAIasCgAAAAAGsAkAA-gQAIa0CQAD6BAAh4gIBAPgEACH_AgEA-AQAIYADAQD4BAAhCQkAALsGACAKAADGBgAgpAIBAAAAAasCgAAAAAGsAkAAAAABrQJAAAAAAeICAQAAAAH_AgEAAAABgAMBAAAAAREGAADIBgAgCAAA_gYAIAsAAMkGACAMAADKBgAgGwAAywYAIBwAAMwGACCkAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAABxwIBAAAAAdgCAQAAAAHbAkAAAAAB5gIAAACGAwKBAwEAAAABgwMAAACDAwKEA4AAAAABAgAAAEMAIDUAAMIHACADAAAAQwAgNQAAwgcAIDYAAMEHACABLgAAgAkAMBcEAADPBAAgBgAAtQQAIAgAANAEACALAADRBAAgDAAA0QQAIBsAANIEACAcAADSBAAgoQIAAMsEADCiAgAAEAAQowIAAMsEADCkAgEAAAABpQIBAPsDACGpAgEA-wMAIawCQAD_AwAhrQJAAP8DACHHAgEAAAAB2AIBAPsDACHbAkAAzgQAIeYCAADNBIYDIoEDAQD7AwAhgwMAAMwEgwMihAMAAIAEACCWAwAAygQAIAIAAABDACAuAADBBwAgAgAAAL8HACAuAADABwAgD6ECAAC-BwAwogIAAL8HABCjAgAAvgcAMKQCAQD7AwAhpQIBAPsDACGpAgEA-wMAIawCQAD_AwAhrQJAAP8DACHHAgEAvgQAIdgCAQD7AwAh2wJAAM4EACHmAgAAzQSGAyKBAwEA-wMAIYMDAADMBIMDIoQDAACABAAgD6ECAAC-BwAwogIAAL8HABCjAgAAvgcAMKQCAQD7AwAhpQIBAPsDACGpAgEA-wMAIawCQAD_AwAhrQJAAP8DACHHAgEAvgQAIdgCAQD7AwAh2wJAAM4EACHmAgAAzQSGAyKBAwEA-wMAIYMDAADMBIMDIoQDAACABAAgC6QCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhxwIBAPsEACHYAgEA-AQAIdsCQADSBQAh5gIAANEFhgMigQMBAPgEACGDAwAA0AWDAyKEA4AAAAABEQYAANQFACAIAAD9BgAgCwAA1QUAIAwAANYFACAbAADXBQAgHAAA2AUAIKQCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhxwIBAPsEACHYAgEA-AQAIdsCQADSBQAh5gIAANEFhgMigQMBAPgEACGDAwAA0AWDAyKEA4AAAAABEQYAAMgGACAIAAD-BgAgCwAAyQYAIAwAAMoGACAbAADLBgAgHAAAzAYAIKQCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAHHAgEAAAAB2AIBAAAAAdsCQAAAAAHmAgAAAIYDAoEDAQAAAAGDAwAAAIMDAoQDgAAAAAEMBQAA3wYAIAgAAIUHACAfAADgBgAgpAIBAAAAAawCQAAAAAGtAkAAAAABxwIBAAAAAdsCQAAAAAGEA4AAAAABhgMCAAAAAYcDAQAAAAGIAwEAAAABAgAAAAkAIDUAAM4HACADAAAACQAgNQAAzgcAIDYAAM0HACABLgAA_wgAMBIEAADPBAAgBQAAtQQAIAgAANAEACAfAADSBAAgoQIAAPEEADCiAgAABwAQowIAAPEEADCkAgEAAAABpQIBAPsDACGsAkAA_wMAIa0CQAD_AwAhxwIBAAAAAdsCQADOBAAhhAMAAIAEACCGAwIA_QMAIYcDAQD7AwAhiAMBAL4EACGZAwAA8AQAIAIAAAAJACAuAADNBwAgAgAAAMsHACAuAADMBwAgDaECAADKBwAwogIAAMsHABCjAgAAygcAMKQCAQD7AwAhpQIBAPsDACGsAkAA_wMAIa0CQAD_AwAhxwIBAL4EACHbAkAAzgQAIYQDAACABAAghgMCAP0DACGHAwEA-wMAIYgDAQC-BAAhDaECAADKBwAwogIAAMsHABCjAgAAygcAMKQCAQD7AwAhpQIBAPsDACGsAkAA_wMAIa0CQAD_AwAhxwIBAL4EACHbAkAAzgQAIYQDAACABAAghgMCAP0DACGHAwEA-wMAIYgDAQC-BAAhCaQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIccCAQD7BAAh2wJAANIFACGEA4AAAAABhgMCAKcFACGHAwEA-AQAIYgDAQD7BAAhDAUAANMGACAIAACEBwAgHwAA1AYAIKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIccCAQD7BAAh2wJAANIFACGEA4AAAAABhgMCAKcFACGHAwEA-AQAIYgDAQD7BAAhDAUAAN8GACAIAACFBwAgHwAA4AYAIKQCAQAAAAGsAkAAAAABrQJAAAAAAccCAQAAAAHbAkAAAAABhAOAAAAAAYYDAgAAAAGHAwEAAAABiAMBAAAAAQM1AAD9CAAgnAMAAP4IACCiAwAAAQAgBDUAAMMHADCcAwAAxAcAMJ4DAADGBwAgogMAAMcHADAENQAAtwcAMJwDAAC4BwAwngMAALoHACCiAwAAuwcAMAQ1AACuBwAwnAMAAK8HADCeAwAAsQcAIKIDAACwBgAwBDUAAKUHADCcAwAApgcAMJ4DAACoBwAgogMAAN0FADAENQAAnAcAMJwDAACdBwAwngMAAJ8HACCiAwAA8QUAMAQ1AACQBwAwnAMAAJEHADCeAwAAkwcAIKIDAACUBwAwAAAACzUAAMcIADA2AADMCAAwnAMAAMgIADCdAwAAyQgAMJ4DAADKCAAgnwMAAMsIADCgAwAAywgAMKEDAADLCAAwogMAAMsIADCjAwAAzQgAMKQDAADOCAAwCzUAAL4IADA2AADCCAAwnAMAAL8IADCdAwAAwAgAMJ4DAADBCAAgnwMAAMcHADCgAwAAxwcAMKEDAADHBwAwogMAAMcHADCjAwAAwwgAMKQDAADKBwAwCzUAALUIADA2AAC5CAAwnAMAALYIADCdAwAAtwgAMJ4DAAC4CAAgnwMAALsHADCgAwAAuwcAMKEDAAC7BwAwogMAALsHADCjAwAAuggAMKQDAAC-BwAwCzUAAKwIADA2AACwCAAwnAMAAK0IADCdAwAArggAMJ4DAACvCAAgnwMAAN0FADCgAwAA3QUAMKEDAADdBQAwogMAAN0FADCjAwAAsQgAMKQDAADgBQAwCzUAAKMIADA2AACnCAAwnAMAAKQIADCdAwAApQgAMJ4DAACmCAAgnwMAAIoFADCgAwAAigUAMKEDAACKBQAwogMAAIoFADCjAwAAqAgAMKQDAACNBQAwCzUAAJoIADA2AACeCAAwnAMAAJsIADCdAwAAnAgAMJ4DAACdCAAgnwMAAPEFADCgAwAA8QUAMKEDAADxBQAwogMAAPEFADCjAwAAnwgAMKQDAAD0BQAwCzUAAJEIADA2AACVCAAwnAMAAJIIADCdAwAAkwgAMJ4DAACUCAAgnwMAAPEFADCgAwAA8QUAMKEDAADxBQAwogMAAPEFADCjAwAAlggAMKQDAAD0BQAwCzUAAIUIADA2AACKCAAwnAMAAIYIADCdAwAAhwgAMJ4DAACICAAgnwMAAIkIADCgAwAAiQgAMKEDAACJCAAwogMAAIkIADCjAwAAiwgAMKQDAACMCAAwCzUAAPwHADA2AACACAAwnAMAAP0HADCdAwAA_gcAMJ4DAAD_BwAgnwMAAMMFADCgAwAAwwUAMKEDAADDBQAwogMAAMMFADCjAwAAgQgAMKQDAADGBQAwCzUAAPAHADA2AAD1BwAwnAMAAPEHADCdAwAA8gcAMJ4DAADzBwAgnwMAAPQHADCgAwAA9AcAMKEDAAD0BwAwogMAAPQHADCjAwAA9gcAMKQDAAD3BwAwCzUAAOQHADA2AADpBwAwnAMAAOUHADCdAwAA5gcAMJ4DAADnBwAgnwMAAOgHADCgAwAA6AcAMKEDAADoBwAwogMAAOgHADCjAwAA6gcAMKQDAADrBwAwBxMAAJkFACCkAgEAAAABrAJAAAAAAcACEAAAAAHBAgEAAAABwgKAAAAAAcMCQAAAAAECAAAAYgAgNQAA7wcAIAMAAABiACA1AADvBwAgNgAA7gcAIAEuAAD8CAAwDBIAALUEACATAAC2BAAgoQIAALMEADCiAgAAIwAQowIAALMEADCkAgEAAAABrAJAAP8DACG_AgEA-wMAIcACEAC0BAAhwQIBAPsDACHCAgAAgAQAIMMCQAD_AwAhAgAAAGIAIC4AAO4HACACAAAA7AcAIC4AAO0HACAKoQIAAOsHADCiAgAA7AcAEKMCAADrBwAwpAIBAPsDACGsAkAA_wMAIb8CAQD7AwAhwAIQALQEACHBAgEA-wMAIcICAACABAAgwwJAAP8DACEKoQIAAOsHADCiAgAA7AcAEKMCAADrBwAwpAIBAPsDACGsAkAA_wMAIb8CAQD7AwAhwAIQALQEACHBAgEA-wMAIcICAACABAAgwwJAAP8DACEGpAIBAPgEACGsAkAA-gQAIcACEACDBQAhwQIBAPgEACHCAoAAAAABwwJAAPoEACEHEwAAhQUAIKQCAQD4BAAhrAJAAPoEACHAAhAAgwUAIcECAQD4BAAhwgKAAAAAAcMCQAD6BAAhBxMAAJkFACCkAgEAAAABrAJAAAAAAcACEAAAAAHBAgEAAAABwgKAAAAAAcMCQAAAAAEGpAIBAAAAAawCQAAAAAGtAkAAAAABxAIBAAAAAcUCEAAAAAHGAkAAAAABAgAAAF8AIDUAAPsHACADAAAAXwAgNQAA-wcAIDYAAPoHACABLgAA-wgAMAwSAAC1BAAgoQIAALgEADCiAgAAXQAQowIAALgEADCkAgEAAAABrAJAAP8DACGtAkAA_wMAIb8CAQD7AwAhxAIBAPsDACHFAhAAtAQAIcYCQAD_AwAhkwMAALcEACACAAAAXwAgLgAA-gcAIAIAAAD4BwAgLgAA-QcAIAqhAgAA9wcAMKICAAD4BwAQowIAAPcHADCkAgEA-wMAIawCQAD_AwAhrQJAAP8DACG_AgEA-wMAIcQCAQD7AwAhxQIQALQEACHGAkAA_wMAIQqhAgAA9wcAMKICAAD4BwAQowIAAPcHADCkAgEA-wMAIawCQAD_AwAhrQJAAP8DACG_AgEA-wMAIcQCAQD7AwAhxQIQALQEACHGAkAA_wMAIQakAgEA-AQAIawCQAD6BAAhrQJAAPoEACHEAgEA-AQAIcUCEACDBQAhxgJAAPoEACEGpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhxAIBAPgEACHFAhAAgwUAIcYCQAD6BAAhBqQCAQAAAAGsAkAAAAABrQJAAAAAAcQCAQAAAAHFAhAAAAABxgJAAAAAAQ0IAACsBQAgpAIBAAAAAawCQAAAAAGtAkAAAAABxAIBAAAAAccCAQAAAAHJAgAAAMkCAsoCEAAAAAHLAgEAAAABzAICAAAAAc0CBAAAAAHOAkAAAAABzwIBAAAAAQIAAAA8ACA1AACECAAgAwAAADwAIDUAAIQIACA2AACDCAAgAS4AAPoIADACAAAAPAAgLgAAgwgAIAIAAADHBQAgLgAAgggAIAykAgEA-AQAIawCQAD6BAAhrQJAAPoEACHEAgEA-AQAIccCAQD7BAAhyQIAAKYFyQIiygIQAIMFACHLAgEA-AQAIcwCAgCnBQAhzQIEAKgFACHOAkAA-gQAIc8CAQD4BAAhDQgAAKoFACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACHEAgEA-AQAIccCAQD7BAAhyQIAAKYFyQIiygIQAIMFACHLAgEA-AQAIcwCAgCnBQAhzQIEAKgFACHOAkAA-gQAIc8CAQD4BAAhDQgAAKwFACCkAgEAAAABrAJAAAAAAa0CQAAAAAHEAgEAAAABxwIBAAAAAckCAAAAyQICygIQAAAAAcsCAQAAAAHMAgIAAAABzQIEAAAAAc4CQAAAAAHPAgEAAAABEAcAAOIGACAdAADjBgAgHgAA5AYAIKQCAQAAAAGnAgAAANcCAqgCAQAAAAGsAkAAAAABrQJAAAAAAcsCAQAAAAHMAgIAAAABzQIEAAAAAdcCAQAAAAHZAgEAAAAB2gKAAAAAAdsCQAAAAAHcAkAAAAABAgAAAFoAIDUAAJAIACADAAAAWgAgNQAAkAgAIDYAAI8IACABLgAA-QgAMBgGAADCBAAgBwAAwwQAIB0AAMQEACAeAADFBAAgoQIAALwEADCiAgAACwAQowIAALwEADCkAgEAAAABpwIAAL0E1wIiqAIBAPsDACGsAkAA_wMAIa0CQAD_AwAhywIBAL4EACHMAgIAwAQAIc0CBAC_BAAh1QIAALsEACDXAgEA-wMAIdgCAQC-BAAh2QIBAPsDACHaAgAAwQQAINsCQAD_AwAh3AJAAP8DACGUAwAAuQQAIJUDAAC6BAAgAgAAAFoAIC4AAI8IACACAAAAjQgAIC4AAI4IACARoQIAAIwIADCiAgAAjQgAEKMCAACMCAAwpAIBAPsDACGnAgAAvQTXAiKoAgEA-wMAIawCQAD_AwAhrQJAAP8DACHLAgEAvgQAIcwCAgDABAAhzQIEAL8EACHXAgEA-wMAIdgCAQC-BAAh2QIBAPsDACHaAgAAwQQAINsCQAD_AwAh3AJAAP8DACERoQIAAIwIADCiAgAAjQgAEKMCAACMCAAwpAIBAPsDACGnAgAAvQTXAiKoAgEA-wMAIawCQAD_AwAhrQJAAP8DACHLAgEAvgQAIcwCAgDABAAhzQIEAL8EACHXAgEA-wMAIdgCAQC-BAAh2QIBAPsDACHaAgAAwQQAINsCQAD_AwAh3AJAAP8DACENpAIBAPgEACGnAgAAuAXXAiKoAgEA-AQAIawCQAD6BAAhrQJAAPoEACHLAgEA-wQAIcwCAgC6BQAhzQIEALkFACHXAgEA-AQAIdkCAQD4BAAh2gKAAAAAAdsCQAD6BAAh3AJAAPoEACEQBwAAvAUAIB0AAL0FACAeAAC-BQAgpAIBAPgEACGnAgAAuAXXAiKoAgEA-AQAIawCQAD6BAAhrQJAAPoEACHLAgEA-wQAIcwCAgC6BQAhzQIEALkFACHXAgEA-AQAIdkCAQD4BAAh2gKAAAAAAdsCQAD6BAAh3AJAAPoEACEQBwAA4gYAIB0AAOMGACAeAADkBgAgpAIBAAAAAacCAAAA1wICqAIBAAAAAawCQAAAAAGtAkAAAAABywIBAAAAAcwCAgAAAAHNAgQAAAAB1wIBAAAAAdkCAQAAAAHaAoAAAAAB2wJAAAAAAdwCQAAAAAEPBAAAgAYAIBAAAOkGACAYAAD-BQAgpAIBAAAAAaUCAQAAAAGsAkAAAAABrQJAAAAAAd0CAQAAAAHfAgEAAAAB4QIAAADhAgLiAgEAAAAB4wIBAAAAAeQCAQAAAAHmAgAAAOYCAucCQAAAAAECAAAALQAgNQAAmQgAIAMAAAAtACA1AACZCAAgNgAAmAgAIAEuAAD4CAAwAgAAAC0AIC4AAJgIACACAAAA9QUAIC4AAJcIACAMpAIBAPgEACGlAgEA-wQAIawCQAD6BAAhrQJAAPoEACHdAgEA-AQAId8CAQD7BAAh4QIAAPcF4QIi4gIBAPgEACHjAgEA-AQAIeQCAQD7BAAh5gIAAPgF5gIi5wJAANIFACEPBAAA_AUAIBAAAOgGACAYAAD6BQAgpAIBAPgEACGlAgEA-wQAIawCQAD6BAAhrQJAAPoEACHdAgEA-AQAId8CAQD7BAAh4QIAAPcF4QIi4gIBAPgEACHjAgEA-AQAIeQCAQD7BAAh5gIAAPgF5gIi5wJAANIFACEPBAAAgAYAIBAAAOkGACAYAAD-BQAgpAIBAAAAAaUCAQAAAAGsAkAAAAABrQJAAAAAAd0CAQAAAAHfAgEAAAAB4QIAAADhAgLiAgEAAAAB4wIBAAAAAeQCAQAAAAHmAgAAAOYCAucCQAAAAAEPBAAAgAYAIBAAAOkGACAZAAD_BQAgpAIBAAAAAaUCAQAAAAGsAkAAAAABrQJAAAAAAd4CAQAAAAHfAgEAAAAB4QIAAADhAgLiAgEAAAAB4wIBAAAAAeQCAQAAAAHmAgAAAOYCAucCQAAAAAECAAAALQAgNQAAoggAIAMAAAAtACA1AACiCAAgNgAAoQgAIAEuAAD3CAAwAgAAAC0AIC4AAKEIACACAAAA9QUAIC4AAKAIACAMpAIBAPgEACGlAgEA-wQAIawCQAD6BAAhrQJAAPoEACHeAgEA-wQAId8CAQD7BAAh4QIAAPcF4QIi4gIBAPgEACHjAgEA-AQAIeQCAQD7BAAh5gIAAPgF5gIi5wJAANIFACEPBAAA_AUAIBAAAOgGACAZAAD7BQAgpAIBAPgEACGlAgEA-wQAIawCQAD6BAAhrQJAAPoEACHeAgEA-wQAId8CAQD7BAAh4QIAAPcF4QIi4gIBAPgEACHjAgEA-AQAIeQCAQD7BAAh5gIAAPgF5gIi5wJAANIFACEPBAAAgAYAIBAAAOkGACAZAAD_BQAgpAIBAAAAAaUCAQAAAAGsAkAAAAABrQJAAAAAAd4CAQAAAAHfAgEAAAAB4QIAAADhAgLiAgEAAAAB4wIBAAAAAeQCAQAAAAHmAgAAAOYCAucCQAAAAAEJEAAAlgUAIBUAAJgGACCkAgEAAAABrAJAAAAAAa0CQAAAAAHfAgEAAAAB8QIAAADxAgLyAhAAAAAB8wIBAAAAAQIAAAAhACA1AACrCAAgAwAAACEAIDUAAKsIACA2AACqCAAgAS4AAPYIADACAAAAIQAgLgAAqggAIAIAAACOBQAgLgAAqQgAIAekAgEA-AQAIawCQAD6BAAhrQJAAPoEACHfAgEA-AQAIfECAACQBfECIvICEACRBQAh8wIBAPsEACEJEAAAkwUAIBUAAJYGACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACHfAgEA-AQAIfECAACQBfECIvICEACRBQAh8wIBAPsEACEJEAAAlgUAIBUAAJgGACCkAgEAAAABrAJAAAAAAa0CQAAAAAHfAgEAAAAB8QIAAADxAgLyAhAAAAAB8wIBAAAAARgEAACaBgAgDQAAnAYAIA4AAKsGACAPAACdBgAgFgAAngYAIBcAAJ8GACAaAACgBgAgpAIBAAAAAaUCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAHbAkAAAAAB5gIAAAD3AgLrAgEAAAAB9QIAAAD1AgL3AoAAAAAB-AIBAAAAAfkCAQAAAAH6AgEAAAAB-wJAAAAAAfwCQAAAAAH9AkAAAAAB_gJAAAAAAQIAAAAaACA1AAC0CAAgAwAAABoAIDUAALQIACA2AACzCAAgAS4AAPUIADACAAAAGgAgLgAAswgAIAIAAADhBQAgLgAAsggAIBGkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAh2wJAANIFACHmAgAA5AX3AiLrAgEA-AQAIfUCAADjBfUCIvcCgAAAAAH4AgEA-wQAIfkCAQD7BAAh-gIBAPsEACH7AkAA0gUAIfwCQADSBQAh_QJAANIFACH-AkAA0gUAIRgEAADmBQAgDQAA6AUAIA4AAKkGACAPAADpBQAgFgAA6gUAIBcAAOsFACAaAADsBQAgpAIBAPgEACGlAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIdsCQADSBQAh5gIAAOQF9wIi6wIBAPgEACH1AgAA4wX1AiL3AoAAAAAB-AIBAPsEACH5AgEA-wQAIfoCAQD7BAAh-wJAANIFACH8AkAA0gUAIf0CQADSBQAh_gJAANIFACEYBAAAmgYAIA0AAJwGACAOAACrBgAgDwAAnQYAIBYAAJ4GACAXAACfBgAgGgAAoAYAIKQCAQAAAAGlAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAAB2wJAAAAAAeYCAAAA9wIC6wIBAAAAAfUCAAAA9QIC9wKAAAAAAfgCAQAAAAH5AgEAAAAB-gIBAAAAAfsCQAAAAAH8AkAAAAAB_QJAAAAAAf4CQAAAAAERBAAAxwYAIAgAAP4GACALAADJBgAgDAAAygYAIBsAAMsGACAcAADMBgAgpAIBAAAAAaUCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAHHAgEAAAAB2wJAAAAAAeYCAAAAhgMCgQMBAAAAAYMDAAAAgwMChAOAAAAAAQIAAABDACA1AAC9CAAgAwAAAEMAIDUAAL0IACA2AAC8CAAgAS4AAPQIADACAAAAQwAgLgAAvAgAIAIAAAC_BwAgLgAAuwgAIAukAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhxwIBAPsEACHbAkAA0gUAIeYCAADRBYYDIoEDAQD4BAAhgwMAANAFgwMihAOAAAAAAREEAADTBQAgCAAA_QYAIAsAANUFACAMAADWBQAgGwAA1wUAIBwAANgFACCkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhxwIBAPsEACHbAkAA0gUAIeYCAADRBYYDIoEDAQD4BAAhgwMAANAFgwMihAOAAAAAAREEAADHBgAgCAAA_gYAIAsAAMkGACAMAADKBgAgGwAAywYAIBwAAMwGACCkAgEAAAABpQIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAccCAQAAAAHbAkAAAAAB5gIAAACGAwKBAwEAAAABgwMAAACDAwKEA4AAAAABDAQAAN4GACAIAACFBwAgHwAA4AYAIKQCAQAAAAGlAgEAAAABrAJAAAAAAa0CQAAAAAHHAgEAAAAB2wJAAAAAAYQDgAAAAAGGAwIAAAABiAMBAAAAAQIAAAAJACA1AADGCAAgAwAAAAkAIDUAAMYIACA2AADFCAAgAS4AAPMIADACAAAACQAgLgAAxQgAIAIAAADLBwAgLgAAxAgAIAmkAgEA-AQAIaUCAQD4BAAhrAJAAPoEACGtAkAA-gQAIccCAQD7BAAh2wJAANIFACGEA4AAAAABhgMCAKcFACGIAwEA-wQAIQwEAADSBgAgCAAAhAcAIB8AANQGACCkAgEA-AQAIaUCAQD4BAAhrAJAAPoEACGtAkAA-gQAIccCAQD7BAAh2wJAANIFACGEA4AAAAABhgMCAKcFACGIAwEA-wQAIQwEAADeBgAgCAAAhQcAIB8AAOAGACCkAgEAAAABpQIBAAAAAawCQAAAAAGtAkAAAAABxwIBAAAAAdsCQAAAAAGEA4AAAAABhgMCAAAAAYgDAQAAAAEMGgAA1AcAIB8AANMHACAgAADQBwAgIQAA0QcAICIAANIHACAjAADVBwAgpAIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAYEDAQAAAAGJAwEAAAABAgAAAAUAIDUAANIIACADAAAABQAgNQAA0ggAIDYAANEIACABLgAA8ggAMBEDAAC1BAAgGgAA5QQAIB8AANIEACAgAADrBAAgIQAA7AQAICIAANEEACAjAADzBAAgoQIAAPIEADCiAgAAAwAQowIAAPIEADCkAgEAAAABqQIBAPsDACGsAkAA_wMAIa0CQAD_AwAhgQMBAAAAAYkDAQD7AwAhigMBAPsDACECAAAABQAgLgAA0QgAIAIAAADPCAAgLgAA0AgAIAqhAgAAzggAMKICAADPCAAQowIAAM4IADCkAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIYEDAQD7AwAhiQMBAPsDACGKAwEA-wMAIQqhAgAAzggAMKICAADPCAAQowIAAM4IADCkAgEA-wMAIakCAQD7AwAhrAJAAP8DACGtAkAA_wMAIYEDAQD7AwAhiQMBAPsDACGKAwEA-wMAIQakAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIYEDAQD4BAAhiQMBAPgEACEMGgAAjgcAIB8AAI0HACAgAACKBwAgIQAAiwcAICIAAIwHACAjAACPBwAgpAIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACGBAwEA-AQAIYkDAQD4BAAhDBoAANQHACAfAADTBwAgIAAA0AcAICEAANEHACAiAADSBwAgIwAA1QcAIKQCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAGBAwEAAAABiQMBAAAAAQQ1AADHCAAwnAMAAMgIADCeAwAAyggAIKIDAADLCAAwBDUAAL4IADCcAwAAvwgAMJ4DAADBCAAgogMAAMcHADAENQAAtQgAMJwDAAC2CAAwngMAALgIACCiAwAAuwcAMAQ1AACsCAAwnAMAAK0IADCeAwAArwgAIKIDAADdBQAwBDUAAKMIADCcAwAApAgAMJ4DAACmCAAgogMAAIoFADAENQAAmggAMJwDAACbCAAwngMAAJ0IACCiAwAA8QUAMAQ1AACRCAAwnAMAAJIIADCeAwAAlAgAIKIDAADxBQAwBDUAAIUIADCcAwAAhggAMJ4DAACICAAgogMAAIkIADAENQAA_AcAMJwDAAD9BwAwngMAAP8HACCiAwAAwwUAMAQ1AADwBwAwnAMAAPEHADCeAwAA8wcAIKIDAAD0BwAwBDUAAOQHADCcAwAA5QcAMJ4DAADnBwAgogMAAOgHADAAAAAAAAAAAAAADhYAAOIIACAaAADjCAAgHgAA5QgAIB8AAOEIACAgAADfCAAgIQAA4AgAICQAAN4IACAlAADjCAAgJgAA5AgAICcAAOYIACAoAADnCAAgjQMAAPQEACCOAwAA9AQAII8DAAD0BAAgBwQAAOsIACAFAADoCAAgCAAA7AgAIB8AAOEIACDHAgAA9AQAINsCAAD0BAAgiAMAAPQEACAJBAAA6wgAIAYAAOgIACAIAADsCAAgCwAA7QgAIAwAAO0IACAbAADhCAAgHAAA4QgAIMcCAAD0BAAg2wIAAPQEACAHAwAA6AgAIBoAAOMIACAfAADhCAAgIAAA3wgAICEAAOAIACAiAADtCAAgIwAA8QgAIAkGAADoCAAgBwAA6QgAIB0AAOoIACAeAADlCAAgywIAAPQEACDMAgAA9AQAIM0CAAD0BAAg2AIAAPQEACDaAgAA9AQAIAAQBAAA6wgAIAYAAOgIACANAADqCAAgDgAA6ggAIA8AAOkIACAWAADiCAAgFwAA8AgAIBoAAOMIACDbAgAA9AQAIPgCAAD0BAAg-QIAAPQEACD6AgAA9AQAIPsCAAD0BAAg_AIAAPQEACD9AgAA9AQAIP4CAAD0BAAgAhIAAOgIACATAADiCAAgAAAGpAIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAYEDAQAAAAGJAwEAAAABCaQCAQAAAAGlAgEAAAABrAJAAAAAAa0CQAAAAAHHAgEAAAAB2wJAAAAAAYQDgAAAAAGGAwIAAAABiAMBAAAAAQukAgEAAAABpQIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAccCAQAAAAHbAkAAAAAB5gIAAACGAwKBAwEAAAABgwMAAACDAwKEA4AAAAABEaQCAQAAAAGlAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAAB2wJAAAAAAeYCAAAA9wIC6wIBAAAAAfUCAAAA9QIC9wKAAAAAAfgCAQAAAAH5AgEAAAAB-gIBAAAAAfsCQAAAAAH8AkAAAAAB_QJAAAAAAf4CQAAAAAEHpAIBAAAAAawCQAAAAAGtAkAAAAAB3wIBAAAAAfECAAAA8QIC8gIQAAAAAfMCAQAAAAEMpAIBAAAAAaUCAQAAAAGsAkAAAAABrQJAAAAAAd4CAQAAAAHfAgEAAAAB4QIAAADhAgLiAgEAAAAB4wIBAAAAAeQCAQAAAAHmAgAAAOYCAucCQAAAAAEMpAIBAAAAAaUCAQAAAAGsAkAAAAABrQJAAAAAAd0CAQAAAAHfAgEAAAAB4QIAAADhAgLiAgEAAAAB4wIBAAAAAeQCAQAAAAHmAgAAAOYCAucCQAAAAAENpAIBAAAAAacCAAAA1wICqAIBAAAAAawCQAAAAAGtAkAAAAABywIBAAAAAcwCAgAAAAHNAgQAAAAB1wIBAAAAAdkCAQAAAAHaAoAAAAAB2wJAAAAAAdwCQAAAAAEMpAIBAAAAAawCQAAAAAGtAkAAAAABxAIBAAAAAccCAQAAAAHJAgAAAMkCAsoCEAAAAAHLAgEAAAABzAICAAAAAc0CBAAAAAHOAkAAAAABzwIBAAAAAQakAgEAAAABrAJAAAAAAa0CQAAAAAHEAgEAAAABxQIQAAAAAcYCQAAAAAEGpAIBAAAAAawCQAAAAAHAAhAAAAABwQIBAAAAAcICgAAAAAHDAkAAAAABEhYAANcIACAaAADYCAAgHgAA2wgAIB8AANYIACAgAADUCAAgIQAA1QgAICUAANkIACAmAADaCAAgJwAA3AgAICgAAN0IACCkAgEAAAABrAJAAAAAAa0CQAAAAAGLAwEAAAABjAMBAAAAAY0DAQAAAAGOAwEAAAABjwMBAAAAAQIAAAABACA1AAD9CAAgCaQCAQAAAAGsAkAAAAABrQJAAAAAAccCAQAAAAHbAkAAAAABhAOAAAAAAYYDAgAAAAGHAwEAAAABiAMBAAAAAQukAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAABxwIBAAAAAdgCAQAAAAHbAkAAAAAB5gIAAACGAwKBAwEAAAABgwMAAACDAwKEA4AAAAABB6QCAQAAAAGrAoAAAAABrAJAAAAAAa0CQAAAAAHiAgEAAAAB_wIBAAAAAYADAQAAAAERpAIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAdgCAQAAAAHbAkAAAAAB5gIAAAD3AgLrAgEAAAAB9QIAAAD1AgL3AoAAAAAB-AIBAAAAAfkCAQAAAAH6AgEAAAAB-wJAAAAAAfwCQAAAAAH9AkAAAAAB_gJAAAAAAQykAgEAAAABrAJAAAAAAa0CQAAAAAHdAgEAAAAB3gIBAAAAAd8CAQAAAAHhAgAAAOECAuICAQAAAAHjAgEAAAAB5AIBAAAAAeYCAAAA5gIC5wJAAAAAAQikAgEAAAABpwIAAACnAgKoAgEAAAABqQIBAAAAAaoCAQAAAAGrAoAAAAABrAJAAAAAAa0CQAAAAAEDAAAADQAgNQAA_QgAIDYAAIcJACAUAAAADQAgFgAA3QcAIBoAAN4HACAeAADhBwAgHwAA3AcAICAAANoHACAhAADbBwAgJQAA3wcAICYAAOAHACAnAADiBwAgKAAA4wcAIC4AAIcJACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACGLAwEA-AQAIYwDAQD4BAAhjQMBAPsEACGOAwEA-wQAIY8DAQD7BAAhEhYAAN0HACAaAADeBwAgHgAA4QcAIB8AANwHACAgAADaBwAgIQAA2wcAICUAAN8HACAmAADgBwAgJwAA4gcAICgAAOMHACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACGLAwEA-AQAIYwDAQD4BAAhjQMBAPsEACGOAwEA-wQAIY8DAQD7BAAhEQYAAOEGACAdAADjBgAgHgAA5AYAIKQCAQAAAAGnAgAAANcCAqgCAQAAAAGsAkAAAAABrQJAAAAAAcsCAQAAAAHMAgIAAAABzQIEAAAAAdcCAQAAAAHYAgEAAAAB2QIBAAAAAdoCgAAAAAHbAkAAAAAB3AJAAAAAAQIAAABaACA1AACICQAgAwAAAAsAIDUAAIgJACA2AACMCQAgEwAAAAsAIAYAALsFACAdAAC9BQAgHgAAvgUAIC4AAIwJACCkAgEA-AQAIacCAAC4BdcCIqgCAQD4BAAhrAJAAPoEACGtAkAA-gQAIcsCAQD7BAAhzAICALoFACHNAgQAuQUAIdcCAQD4BAAh2AIBAPsEACHZAgEA-AQAIdoCgAAAAAHbAkAA-gQAIdwCQAD6BAAhEQYAALsFACAdAAC9BQAgHgAAvgUAIKQCAQD4BAAhpwIAALgF1wIiqAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhywIBAPsEACHMAgIAugUAIc0CBAC5BQAh1wIBAPgEACHYAgEA-wQAIdkCAQD4BAAh2gKAAAAAAdsCQAD6BAAh3AJAAPoEACERBgAA4QYAIAcAAOIGACAeAADkBgAgpAIBAAAAAacCAAAA1wICqAIBAAAAAawCQAAAAAGtAkAAAAABywIBAAAAAcwCAgAAAAHNAgQAAAAB1wIBAAAAAdgCAQAAAAHZAgEAAAAB2gKAAAAAAdsCQAAAAAHcAkAAAAABAgAAAFoAIDUAAI0JACADAAAACwAgNQAAjQkAIDYAAJEJACATAAAACwAgBgAAuwUAIAcAALwFACAeAAC-BQAgLgAAkQkAIKQCAQD4BAAhpwIAALgF1wIiqAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhywIBAPsEACHMAgIAugUAIc0CBAC5BQAh1wIBAPgEACHYAgEA-wQAIdkCAQD4BAAh2gKAAAAAAdsCQAD6BAAh3AJAAPoEACERBgAAuwUAIAcAALwFACAeAAC-BQAgpAIBAPgEACGnAgAAuAXXAiKoAgEA-AQAIawCQAD6BAAhrQJAAPoEACHLAgEA-wQAIcwCAgC6BQAhzQIEALkFACHXAgEA-AQAIdgCAQD7BAAh2QIBAPgEACHaAoAAAAAB2wJAAPoEACHcAkAA-gQAIRkEAACaBgAgBgAAmwYAIA0AAJwGACAOAACrBgAgDwAAnQYAIBYAAJ4GACAaAACgBgAgpAIBAAAAAaUCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAHYAgEAAAAB2wJAAAAAAeYCAAAA9wIC6wIBAAAAAfUCAAAA9QIC9wKAAAAAAfgCAQAAAAH5AgEAAAAB-gIBAAAAAfsCQAAAAAH8AkAAAAAB_QJAAAAAAf4CQAAAAAECAAAAGgAgNQAAkgkAIAMAAAAYACA1AACSCQAgNgAAlgkAIBsAAAAYACAEAADmBQAgBgAA5wUAIA0AAOgFACAOAACpBgAgDwAA6QUAIBYAAOoFACAaAADsBQAgLgAAlgkAIKQCAQD4BAAhpQIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHYAgEA-AQAIdsCQADSBQAh5gIAAOQF9wIi6wIBAPgEACH1AgAA4wX1AiL3AoAAAAAB-AIBAPsEACH5AgEA-wQAIfoCAQD7BAAh-wJAANIFACH8AkAA0gUAIf0CQADSBQAh_gJAANIFACEZBAAA5gUAIAYAAOcFACANAADoBQAgDgAAqQYAIA8AAOkFACAWAADqBQAgGgAA7AUAIKQCAQD4BAAhpQIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHYAgEA-AQAIdsCQADSBQAh5gIAAOQF9wIi6wIBAPgEACH1AgAA4wX1AiL3AoAAAAAB-AIBAPsEACH5AgEA-wQAIfoCAQD7BAAh-wJAANIFACH8AkAA0gUAIf0CQADSBQAh_gJAANIFACEZBAAAmgYAIAYAAJsGACANAACcBgAgDgAAqwYAIA8AAJ0GACAWAACeBgAgFwAAnwYAIKQCAQAAAAGlAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAAB2AIBAAAAAdsCQAAAAAHmAgAAAPcCAusCAQAAAAH1AgAAAPUCAvcCgAAAAAH4AgEAAAAB-QIBAAAAAfoCAQAAAAH7AkAAAAAB_AJAAAAAAf0CQAAAAAH-AkAAAAABAgAAABoAIDUAAJcJACADAAAAGAAgNQAAlwkAIDYAAJsJACAbAAAAGAAgBAAA5gUAIAYAAOcFACANAADoBQAgDgAAqQYAIA8AAOkFACAWAADqBQAgFwAA6wUAIC4AAJsJACCkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAh2AIBAPgEACHbAkAA0gUAIeYCAADkBfcCIusCAQD4BAAh9QIAAOMF9QIi9wKAAAAAAfgCAQD7BAAh-QIBAPsEACH6AgEA-wQAIfsCQADSBQAh_AJAANIFACH9AkAA0gUAIf4CQADSBQAhGQQAAOYFACAGAADnBQAgDQAA6AUAIA4AAKkGACAPAADpBQAgFgAA6gUAIBcAAOsFACCkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAh2AIBAPgEACHbAkAA0gUAIeYCAADkBfcCIusCAQD4BAAh9QIAAOMF9QIi9wKAAAAAAfgCAQD7BAAh-QIBAPsEACH6AgEA-wQAIfsCQADSBQAh_AJAANIFACH9AkAA0gUAIf4CQADSBQAhEhYAANcIACAaAADYCAAgHgAA2wgAIB8AANYIACAgAADUCAAgIQAA1QgAICQAANMIACAlAADZCAAgJwAA3AgAICgAAN0IACCkAgEAAAABrAJAAAAAAa0CQAAAAAGLAwEAAAABjAMBAAAAAY0DAQAAAAGOAwEAAAABjwMBAAAAAQIAAAABACA1AACcCQAgEhYAANcIACAaAADYCAAgHgAA2wgAIB8AANYIACAhAADVCAAgJAAA0wgAICUAANkIACAmAADaCAAgJwAA3AgAICgAAN0IACCkAgEAAAABrAJAAAAAAa0CQAAAAAGLAwEAAAABjAMBAAAAAY0DAQAAAAGOAwEAAAABjwMBAAAAAQIAAAABACA1AACeCQAgDQMAAM8HACAaAADUBwAgHwAA0wcAICEAANEHACAiAADSBwAgIwAA1QcAIKQCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAGBAwEAAAABiQMBAAAAAYoDAQAAAAECAAAABQAgNQAAoAkAIBGkAgEAAAABpQIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAdgCAQAAAAHbAkAAAAAB5gIAAAD3AgLrAgEAAAAB9QIAAAD1AgL3AoAAAAAB-AIBAAAAAfkCAQAAAAH7AkAAAAAB_AJAAAAAAf0CQAAAAAH-AkAAAAABAwAAAA0AIDUAAJ4JACA2AAClCQAgFAAAAA0AIBYAAN0HACAaAADeBwAgHgAA4QcAIB8AANwHACAhAADbBwAgJAAA2QcAICUAAN8HACAmAADgBwAgJwAA4gcAICgAAOMHACAuAAClCQAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhiwMBAPgEACGMAwEA-AQAIY0DAQD7BAAhjgMBAPsEACGPAwEA-wQAIRIWAADdBwAgGgAA3gcAIB4AAOEHACAfAADcBwAgIQAA2wcAICQAANkHACAlAADfBwAgJgAA4AcAICcAAOIHACAoAADjBwAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhiwMBAPgEACGMAwEA-AQAIY0DAQD7BAAhjgMBAPsEACGPAwEA-wQAIQMAAAADACA1AACgCQAgNgAAqAkAIA8AAAADACADAACJBwAgGgAAjgcAIB8AAI0HACAhAACLBwAgIgAAjAcAICMAAI8HACAuAACoCQAgpAIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACGBAwEA-AQAIYkDAQD4BAAhigMBAPgEACENAwAAiQcAIBoAAI4HACAfAACNBwAgIQAAiwcAICIAAIwHACAjAACPBwAgpAIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACGBAwEA-AQAIYkDAQD4BAAhigMBAPgEACESFgAA1wgAIBoAANgIACAeAADbCAAgHwAA1ggAICAAANQIACAkAADTCAAgJQAA2QgAICYAANoIACAnAADcCAAgKAAA3QgAIKQCAQAAAAGsAkAAAAABrQJAAAAAAYsDAQAAAAGMAwEAAAABjQMBAAAAAY4DAQAAAAGPAwEAAAABAgAAAAEAIDUAAKkJACANAwAAzwcAIBoAANQHACAfAADTBwAgIAAA0AcAICIAANIHACAjAADVBwAgpAIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAYEDAQAAAAGJAwEAAAABigMBAAAAAQIAAAAFACA1AACrCQAgEgQAAMcGACAGAADIBgAgCAAA_gYAIAsAAMkGACAbAADLBgAgHAAAzAYAIKQCAQAAAAGlAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAABxwIBAAAAAdgCAQAAAAHbAkAAAAAB5gIAAACGAwKBAwEAAAABgwMAAACDAwKEA4AAAAABAgAAAEMAIDUAAK0JACADAAAAEAAgNQAArQkAIDYAALEJACAUAAAAEAAgBAAA0wUAIAYAANQFACAIAAD9BgAgCwAA1QUAIBsAANcFACAcAADYBQAgLgAAsQkAIKQCAQD4BAAhpQIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHHAgEA-wQAIdgCAQD4BAAh2wJAANIFACHmAgAA0QWGAyKBAwEA-AQAIYMDAADQBYMDIoQDgAAAAAESBAAA0wUAIAYAANQFACAIAAD9BgAgCwAA1QUAIBsAANcFACAcAADYBQAgpAIBAPgEACGlAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIccCAQD7BAAh2AIBAPgEACHbAkAA0gUAIeYCAADRBYYDIoEDAQD4BAAhgwMAANAFgwMihAOAAAAAAQekAgEAAAABpQIBAAAAAasCgAAAAAGsAkAAAAABrQJAAAAAAeICAQAAAAGAAwEAAAABEgQAAMcGACAGAADIBgAgCAAA_gYAIAwAAMoGACAbAADLBgAgHAAAzAYAIKQCAQAAAAGlAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAABxwIBAAAAAdgCAQAAAAHbAkAAAAAB5gIAAACGAwKBAwEAAAABgwMAAACDAwKEA4AAAAABAgAAAEMAIDUAALMJACANAwAAzwcAIBoAANQHACAfAADTBwAgIAAA0AcAICEAANEHACAjAADVBwAgpAIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAYEDAQAAAAGJAwEAAAABigMBAAAAAQIAAAAFACA1AAC1CQAgAwAAABAAIDUAALMJACA2AAC5CQAgFAAAABAAIAQAANMFACAGAADUBQAgCAAA_QYAIAwAANYFACAbAADXBQAgHAAA2AUAIC4AALkJACCkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhxwIBAPsEACHYAgEA-AQAIdsCQADSBQAh5gIAANEFhgMigQMBAPgEACGDAwAA0AWDAyKEA4AAAAABEgQAANMFACAGAADUBQAgCAAA_QYAIAwAANYFACAbAADXBQAgHAAA2AUAIKQCAQD4BAAhpQIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHHAgEA-wQAIdgCAQD4BAAh2wJAANIFACHmAgAA0QWGAyKBAwEA-AQAIYMDAADQBYMDIoQDgAAAAAEDAAAAAwAgNQAAtQkAIDYAALwJACAPAAAAAwAgAwAAiQcAIBoAAI4HACAfAACNBwAgIAAAigcAICEAAIsHACAjAACPBwAgLgAAvAkAIKQCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhgQMBAPgEACGJAwEA-AQAIYoDAQD4BAAhDQMAAIkHACAaAACOBwAgHwAAjQcAICAAAIoHACAhAACLBwAgIwAAjwcAIKQCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhgQMBAPgEACGJAwEA-AQAIYoDAQD4BAAhB6QCAQAAAAGlAgEAAAABqwKAAAAAAawCQAAAAAGtAkAAAAAB_wIBAAAAAYADAQAAAAESBAAAxwYAIAYAAMgGACAIAAD-BgAgCwAAyQYAIAwAAMoGACAbAADLBgAgpAIBAAAAAaUCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAHHAgEAAAAB2AIBAAAAAdsCQAAAAAHmAgAAAIYDAoEDAQAAAAGDAwAAAIMDAoQDgAAAAAECAAAAQwAgNQAAvgkAIAMAAAAQACA1AAC-CQAgNgAAwgkAIBQAAAAQACAEAADTBQAgBgAA1AUAIAgAAP0GACALAADVBQAgDAAA1gUAIBsAANcFACAuAADCCQAgpAIBAPgEACGlAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIccCAQD7BAAh2AIBAPgEACHbAkAA0gUAIeYCAADRBYYDIoEDAQD4BAAhgwMAANAFgwMihAOAAAAAARIEAADTBQAgBgAA1AUAIAgAAP0GACALAADVBQAgDAAA1gUAIBsAANcFACCkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhxwIBAPsEACHYAgEA-AQAIdsCQADSBQAh5gIAANEFhgMigQMBAPgEACGDAwAA0AWDAyKEA4AAAAABEaQCAQAAAAGlAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAAB2AIBAAAAAdsCQAAAAAHmAgAAAPcCAusCAQAAAAH1AgAAAPUCAvcCgAAAAAH5AgEAAAAB-gIBAAAAAfsCQAAAAAH8AkAAAAAB_QJAAAAAAf4CQAAAAAENBAAA3gYAIAUAAN8GACAIAACFBwAgpAIBAAAAAaUCAQAAAAGsAkAAAAABrQJAAAAAAccCAQAAAAHbAkAAAAABhAOAAAAAAYYDAgAAAAGHAwEAAAABiAMBAAAAAQIAAAAJACA1AADECQAgEgQAAMcGACAGAADIBgAgCAAA_gYAIAsAAMkGACAMAADKBgAgHAAAzAYAIKQCAQAAAAGlAgEAAAABqQIBAAAAAawCQAAAAAGtAkAAAAABxwIBAAAAAdgCAQAAAAHbAkAAAAAB5gIAAACGAwKBAwEAAAABgwMAAACDAwKEA4AAAAABAgAAAEMAIDUAAMYJACASFgAA1wgAIBoAANgIACAeAADbCAAgIAAA1AgAICEAANUIACAkAADTCAAgJQAA2QgAICYAANoIACAnAADcCAAgKAAA3QgAIKQCAQAAAAGsAkAAAAABrQJAAAAAAYsDAQAAAAGMAwEAAAABjQMBAAAAAY4DAQAAAAGPAwEAAAABAgAAAAEAIDUAAMgJACANAwAAzwcAIBoAANQHACAgAADQBwAgIQAA0QcAICIAANIHACAjAADVBwAgpAIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAYEDAQAAAAGJAwEAAAABigMBAAAAAQIAAAAFACA1AADKCQAgCBIAAJgFACCkAgEAAAABrAJAAAAAAb8CAQAAAAHAAhAAAAABwQIBAAAAAcICgAAAAAHDAkAAAAABAgAAAGIAIDUAAMwJACADAAAAIwAgNQAAzAkAIDYAANAJACAKAAAAIwAgEgAAhAUAIC4AANAJACCkAgEA-AQAIawCQAD6BAAhvwIBAPgEACHAAhAAgwUAIcECAQD4BAAhwgKAAAAAAcMCQAD6BAAhCBIAAIQFACCkAgEA-AQAIawCQAD6BAAhvwIBAPgEACHAAhAAgwUAIcECAQD4BAAhwgKAAAAAAcMCQAD6BAAhB6QCAQAAAAGsAkAAAAABrQJAAAAAAe8CAQAAAAHxAgAAAPECAvICEAAAAAHzAgEAAAABCqQCAQAAAAGsAkAAAAABrQJAAAAAAeYCAAAA6wIC6AIBAAAAAekCAQAAAAHrAgEAAAAB7AKAAAAAAe0CAQAAAAHuAgEAAAABDQMAAM8HACAfAADTBwAgIAAA0AcAICEAANEHACAiAADSBwAgIwAA1QcAIKQCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAGBAwEAAAABiQMBAAAAAYoDAQAAAAECAAAABQAgNQAA0wkAIBIWAADXCAAgGgAA2AgAIB4AANsIACAfAADWCAAgIAAA1AgAICEAANUIACAkAADTCAAgJgAA2ggAICcAANwIACAoAADdCAAgpAIBAAAAAawCQAAAAAGtAkAAAAABiwMBAAAAAYwDAQAAAAGNAwEAAAABjgMBAAAAAY8DAQAAAAECAAAAAQAgNQAA1QkAIBIWAADXCAAgHgAA2wgAIB8AANYIACAgAADUCAAgIQAA1QgAICQAANMIACAlAADZCAAgJgAA2ggAICcAANwIACAoAADdCAAgpAIBAAAAAawCQAAAAAGtAkAAAAABiwMBAAAAAYwDAQAAAAGNAwEAAAABjgMBAAAAAY8DAQAAAAECAAAAAQAgNQAA1wkAIAMAAAADACA1AADTCQAgNgAA2wkAIA8AAAADACADAACJBwAgHwAAjQcAICAAAIoHACAhAACLBwAgIgAAjAcAICMAAI8HACAuAADbCQAgpAIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACGBAwEA-AQAIYkDAQD4BAAhigMBAPgEACENAwAAiQcAIB8AAI0HACAgAACKBwAgIQAAiwcAICIAAIwHACAjAACPBwAgpAIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACGBAwEA-AQAIYkDAQD4BAAhigMBAPgEACEDAAAADQAgNQAA1QkAIDYAAN4JACAUAAAADQAgFgAA3QcAIBoAAN4HACAeAADhBwAgHwAA3AcAICAAANoHACAhAADbBwAgJAAA2QcAICYAAOAHACAnAADiBwAgKAAA4wcAIC4AAN4JACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACGLAwEA-AQAIYwDAQD4BAAhjQMBAPsEACGOAwEA-wQAIY8DAQD7BAAhEhYAAN0HACAaAADeBwAgHgAA4QcAIB8AANwHACAgAADaBwAgIQAA2wcAICQAANkHACAmAADgBwAgJwAA4gcAICgAAOMHACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACGLAwEA-AQAIYwDAQD4BAAhjQMBAPsEACGOAwEA-wQAIY8DAQD7BAAhAwAAAA0AIDUAANcJACA2AADhCQAgFAAAAA0AIBYAAN0HACAeAADhBwAgHwAA3AcAICAAANoHACAhAADbBwAgJAAA2QcAICUAAN8HACAmAADgBwAgJwAA4gcAICgAAOMHACAuAADhCQAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhiwMBAPgEACGMAwEA-AQAIY0DAQD7BAAhjgMBAPsEACGPAwEA-wQAIRIWAADdBwAgHgAA4QcAIB8AANwHACAgAADaBwAgIQAA2wcAICQAANkHACAlAADfBwAgJgAA4AcAICcAAOIHACAoAADjBwAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhiwMBAPgEACGMAwEA-AQAIY0DAQD7BAAhjgMBAPsEACGPAwEA-wQAIQykAgEAAAABpQIBAAAAAawCQAAAAAGtAkAAAAAB3QIBAAAAAd4CAQAAAAHhAgAAAOECAuICAQAAAAHjAgEAAAAB5AIBAAAAAeYCAAAA5gIC5wJAAAAAAQMAAAAHACA1AADECQAgNgAA5QkAIA8AAAAHACAEAADSBgAgBQAA0wYAIAgAAIQHACAuAADlCQAgpAIBAPgEACGlAgEA-AQAIawCQAD6BAAhrQJAAPoEACHHAgEA-wQAIdsCQADSBQAhhAOAAAAAAYYDAgCnBQAhhwMBAPgEACGIAwEA-wQAIQ0EAADSBgAgBQAA0wYAIAgAAIQHACCkAgEA-AQAIaUCAQD4BAAhrAJAAPoEACGtAkAA-gQAIccCAQD7BAAh2wJAANIFACGEA4AAAAABhgMCAKcFACGHAwEA-AQAIYgDAQD7BAAhAwAAABAAIDUAAMYJACA2AADoCQAgFAAAABAAIAQAANMFACAGAADUBQAgCAAA_QYAIAsAANUFACAMAADWBQAgHAAA2AUAIC4AAOgJACCkAgEA-AQAIaUCAQD4BAAhqQIBAPgEACGsAkAA-gQAIa0CQAD6BAAhxwIBAPsEACHYAgEA-AQAIdsCQADSBQAh5gIAANEFhgMigQMBAPgEACGDAwAA0AWDAyKEA4AAAAABEgQAANMFACAGAADUBQAgCAAA_QYAIAsAANUFACAMAADWBQAgHAAA2AUAIKQCAQD4BAAhpQIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHHAgEA-wQAIdgCAQD4BAAh2wJAANIFACHmAgAA0QWGAyKBAwEA-AQAIYMDAADQBYMDIoQDgAAAAAEDAAAADQAgNQAAyAkAIDYAAOsJACAUAAAADQAgFgAA3QcAIBoAAN4HACAeAADhBwAgIAAA2gcAICEAANsHACAkAADZBwAgJQAA3wcAICYAAOAHACAnAADiBwAgKAAA4wcAIC4AAOsJACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACGLAwEA-AQAIYwDAQD4BAAhjQMBAPsEACGOAwEA-wQAIY8DAQD7BAAhEhYAAN0HACAaAADeBwAgHgAA4QcAICAAANoHACAhAADbBwAgJAAA2QcAICUAAN8HACAmAADgBwAgJwAA4gcAICgAAOMHACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACGLAwEA-AQAIYwDAQD4BAAhjQMBAPsEACGOAwEA-wQAIY8DAQD7BAAhAwAAAAMAIDUAAMoJACA2AADuCQAgDwAAAAMAIAMAAIkHACAaAACOBwAgIAAAigcAICEAAIsHACAiAACMBwAgIwAAjwcAIC4AAO4JACCkAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIYEDAQD4BAAhiQMBAPgEACGKAwEA-AQAIQ0DAACJBwAgGgAAjgcAICAAAIoHACAhAACLBwAgIgAAjAcAICMAAI8HACCkAgEA-AQAIakCAQD4BAAhrAJAAPoEACGtAkAA-gQAIYEDAQD4BAAhiQMBAPgEACGKAwEA-AQAIRGkAgEAAAABpQIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAdgCAQAAAAHbAkAAAAAB5gIAAAD3AgLrAgEAAAAB9QIAAAD1AgL3AoAAAAAB-AIBAAAAAfoCAQAAAAH7AkAAAAAB_AJAAAAAAf0CQAAAAAH-AkAAAAABAwAAAA0AIDUAAKkJACA2AADyCQAgFAAAAA0AIBYAAN0HACAaAADeBwAgHgAA4QcAIB8AANwHACAgAADaBwAgJAAA2QcAICUAAN8HACAmAADgBwAgJwAA4gcAICgAAOMHACAuAADyCQAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhiwMBAPgEACGMAwEA-AQAIY0DAQD7BAAhjgMBAPsEACGPAwEA-wQAIRIWAADdBwAgGgAA3gcAIB4AAOEHACAfAADcBwAgIAAA2gcAICQAANkHACAlAADfBwAgJgAA4AcAICcAAOIHACAoAADjBwAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhiwMBAPgEACGMAwEA-AQAIY0DAQD7BAAhjgMBAPsEACGPAwEA-wQAIQMAAAADACA1AACrCQAgNgAA9QkAIA8AAAADACADAACJBwAgGgAAjgcAIB8AAI0HACAgAACKBwAgIgAAjAcAICMAAI8HACAuAAD1CQAgpAIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACGBAwEA-AQAIYkDAQD4BAAhigMBAPgEACENAwAAiQcAIBoAAI4HACAfAACNBwAgIAAAigcAICIAAIwHACAjAACPBwAgpAIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACGBAwEA-AQAIYkDAQD4BAAhigMBAPgEACEMpAIBAAAAAawCQAAAAAGtAkAAAAABvwIBAAAAAcQCAQAAAAHJAgAAAMkCAsoCEAAAAAHLAgEAAAABzAICAAAAAc0CBAAAAAHOAkAAAAABzwIBAAAAAQMAAAANACA1AACcCQAgNgAA-QkAIBQAAAANACAWAADdBwAgGgAA3gcAIB4AAOEHACAfAADcBwAgIAAA2gcAICEAANsHACAkAADZBwAgJQAA3wcAICcAAOIHACAoAADjBwAgLgAA-QkAIKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIYsDAQD4BAAhjAMBAPgEACGNAwEA-wQAIY4DAQD7BAAhjwMBAPsEACESFgAA3QcAIBoAAN4HACAeAADhBwAgHwAA3AcAICAAANoHACAhAADbBwAgJAAA2QcAICUAAN8HACAnAADiBwAgKAAA4wcAIKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIYsDAQD4BAAhjAMBAPgEACGNAwEA-wQAIY4DAQD7BAAhjwMBAPsEACERBgAA4QYAIAcAAOIGACAdAADjBgAgpAIBAAAAAacCAAAA1wICqAIBAAAAAawCQAAAAAGtAkAAAAABywIBAAAAAcwCAgAAAAHNAgQAAAAB1wIBAAAAAdgCAQAAAAHZAgEAAAAB2gKAAAAAAdsCQAAAAAHcAkAAAAABAgAAAFoAIDUAAPoJACASFgAA1wgAIBoAANgIACAfAADWCAAgIAAA1AgAICEAANUIACAkAADTCAAgJQAA2QgAICYAANoIACAnAADcCAAgKAAA3QgAIKQCAQAAAAGsAkAAAAABrQJAAAAAAYsDAQAAAAGMAwEAAAABjQMBAAAAAY4DAQAAAAGPAwEAAAABAgAAAAEAIDUAAPwJACADAAAACwAgNQAA-gkAIDYAAIAKACATAAAACwAgBgAAuwUAIAcAALwFACAdAAC9BQAgLgAAgAoAIKQCAQD4BAAhpwIAALgF1wIiqAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhywIBAPsEACHMAgIAugUAIc0CBAC5BQAh1wIBAPgEACHYAgEA-wQAIdkCAQD4BAAh2gKAAAAAAdsCQAD6BAAh3AJAAPoEACERBgAAuwUAIAcAALwFACAdAAC9BQAgpAIBAPgEACGnAgAAuAXXAiKoAgEA-AQAIawCQAD6BAAhrQJAAPoEACHLAgEA-wQAIcwCAgC6BQAhzQIEALkFACHXAgEA-AQAIdgCAQD7BAAh2QIBAPgEACHaAoAAAAAB2wJAAPoEACHcAkAA-gQAIQMAAAANACA1AAD8CQAgNgAAgwoAIBQAAAANACAWAADdBwAgGgAA3gcAIB8AANwHACAgAADaBwAgIQAA2wcAICQAANkHACAlAADfBwAgJgAA4AcAICcAAOIHACAoAADjBwAgLgAAgwoAIKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIYsDAQD4BAAhjAMBAPgEACGNAwEA-wQAIY4DAQD7BAAhjwMBAPsEACESFgAA3QcAIBoAAN4HACAfAADcBwAgIAAA2gcAICEAANsHACAkAADZBwAgJQAA3wcAICYAAOAHACAnAADiBwAgKAAA4wcAIKQCAQD4BAAhrAJAAPoEACGtAkAA-gQAIYsDAQD4BAAhjAMBAPgEACGNAwEA-wQAIY4DAQD7BAAhjwMBAPsEACESFgAA1wgAIBoAANgIACAeAADbCAAgHwAA1ggAICAAANQIACAhAADVCAAgJAAA0wgAICUAANkIACAmAADaCAAgKAAA3QgAIKQCAQAAAAGsAkAAAAABrQJAAAAAAYsDAQAAAAGMAwEAAAABjQMBAAAAAY4DAQAAAAGPAwEAAAABAgAAAAEAIDUAAIQKACADAAAADQAgNQAAhAoAIDYAAIgKACAUAAAADQAgFgAA3QcAIBoAAN4HACAeAADhBwAgHwAA3AcAICAAANoHACAhAADbBwAgJAAA2QcAICUAAN8HACAmAADgBwAgKAAA4wcAIC4AAIgKACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACGLAwEA-AQAIYwDAQD4BAAhjQMBAPsEACGOAwEA-wQAIY8DAQD7BAAhEhYAAN0HACAaAADeBwAgHgAA4QcAIB8AANwHACAgAADaBwAgIQAA2wcAICQAANkHACAlAADfBwAgJgAA4AcAICgAAOMHACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACGLAwEA-AQAIYwDAQD4BAAhjQMBAPsEACGOAwEA-wQAIY8DAQD7BAAhEhYAANcIACAaAADYCAAgHgAA2wgAIB8AANYIACAgAADUCAAgIQAA1QgAICQAANMIACAlAADZCAAgJgAA2ggAICcAANwIACCkAgEAAAABrAJAAAAAAa0CQAAAAAGLAwEAAAABjAMBAAAAAY0DAQAAAAGOAwEAAAABjwMBAAAAAQIAAAABACA1AACJCgAgEhoAANgIACAeAADbCAAgHwAA1ggAICAAANQIACAhAADVCAAgJAAA0wgAICUAANkIACAmAADaCAAgJwAA3AgAICgAAN0IACCkAgEAAAABrAJAAAAAAa0CQAAAAAGLAwEAAAABjAMBAAAAAY0DAQAAAAGOAwEAAAABjwMBAAAAAQIAAAABACA1AACLCgAgGQQAAJoGACAGAACbBgAgDQAAnAYAIA4AAKsGACAPAACdBgAgFwAAnwYAIBoAAKAGACCkAgEAAAABpQIBAAAAAakCAQAAAAGsAkAAAAABrQJAAAAAAdgCAQAAAAHbAkAAAAAB5gIAAAD3AgLrAgEAAAAB9QIAAAD1AgL3AoAAAAAB-AIBAAAAAfkCAQAAAAH6AgEAAAAB-wJAAAAAAfwCQAAAAAH9AkAAAAAB_gJAAAAAAQIAAAAaACA1AACNCgAgAwAAAA0AIDUAAIsKACA2AACRCgAgFAAAAA0AIBoAAN4HACAeAADhBwAgHwAA3AcAICAAANoHACAhAADbBwAgJAAA2QcAICUAAN8HACAmAADgBwAgJwAA4gcAICgAAOMHACAuAACRCgAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhiwMBAPgEACGMAwEA-AQAIY0DAQD7BAAhjgMBAPsEACGPAwEA-wQAIRIaAADeBwAgHgAA4QcAIB8AANwHACAgAADaBwAgIQAA2wcAICQAANkHACAlAADfBwAgJgAA4AcAICcAAOIHACAoAADjBwAgpAIBAPgEACGsAkAA-gQAIa0CQAD6BAAhiwMBAPgEACGMAwEA-AQAIY0DAQD7BAAhjgMBAPsEACGPAwEA-wQAIQMAAAAYACA1AACNCgAgNgAAlAoAIBsAAAAYACAEAADmBQAgBgAA5wUAIA0AAOgFACAOAACpBgAgDwAA6QUAIBcAAOsFACAaAADsBQAgLgAAlAoAIKQCAQD4BAAhpQIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHYAgEA-AQAIdsCQADSBQAh5gIAAOQF9wIi6wIBAPgEACH1AgAA4wX1AiL3AoAAAAAB-AIBAPsEACH5AgEA-wQAIfoCAQD7BAAh-wJAANIFACH8AkAA0gUAIf0CQADSBQAh_gJAANIFACEZBAAA5gUAIAYAAOcFACANAADoBQAgDgAAqQYAIA8AAOkFACAXAADrBQAgGgAA7AUAIKQCAQD4BAAhpQIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACHYAgEA-AQAIdsCQADSBQAh5gIAAOQF9wIi6wIBAPgEACH1AgAA4wX1AiL3AoAAAAAB-AIBAPsEACH5AgEA-wQAIfoCAQD7BAAh-wJAANIFACH8AkAA0gUAIf0CQADSBQAh_gJAANIFACEHpAIBAAAAAawCQAAAAAGtAkAAAAAB3wIBAAAAAe8CAQAAAAHxAgAAAPECAvICEAAAAAEDAAAADQAgNQAAiQoAIDYAAJgKACAUAAAADQAgFgAA3QcAIBoAAN4HACAeAADhBwAgHwAA3AcAICAAANoHACAhAADbBwAgJAAA2QcAICUAAN8HACAmAADgBwAgJwAA4gcAIC4AAJgKACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACGLAwEA-AQAIYwDAQD4BAAhjQMBAPsEACGOAwEA-wQAIY8DAQD7BAAhEhYAAN0HACAaAADeBwAgHgAA4QcAIB8AANwHACAgAADaBwAgIQAA2wcAICQAANkHACAlAADfBwAgJgAA4AcAICcAAOIHACCkAgEA-AQAIawCQAD6BAAhrQJAAPoEACGLAwEA-AQAIYwDAQD4BAAhjQMBAPsEACGOAwEA-wQAIY8DAQD7BAAhDQMAAM8HACAaAADUBwAgHwAA0wcAICAAANAHACAhAADRBwAgIgAA0gcAIKQCAQAAAAGpAgEAAAABrAJAAAAAAa0CQAAAAAGBAwEAAAABiQMBAAAAAYoDAQAAAAECAAAABQAgNQAAmQoAIAMAAAADACA1AACZCgAgNgAAnQoAIA8AAAADACADAACJBwAgGgAAjgcAIB8AAI0HACAgAACKBwAgIQAAiwcAICIAAIwHACAuAACdCgAgpAIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACGBAwEA-AQAIYkDAQD4BAAhigMBAPgEACENAwAAiQcAIBoAAI4HACAfAACNBwAgIAAAigcAICEAAIsHACAiAACMBwAgpAIBAPgEACGpAgEA-AQAIawCQAD6BAAhrQJAAPoEACGBAwEA-AQAIYkDAQD4BAAhigMBAPgEACEMFAAVFlYIGlcMHlwPH1UHIFMDIVQFJAYCJVgMJlsEJ2AUKGMJCAMAARQAExpHDB9GByAKAyFEBSJFBiNLEgUEAAIFAAEIDAQUABEfQAcFBg4BBw8DFAAQHREFHj0PCAQAAgYAAQgSBAsWBgwXBhQADhsbBxw1BwMEAAIJAAUKAAUJBAACBgABDRwFDh0FDx4DFAANFiIIFyoLGi4MAxAABxEAARUkCQMSAAETJQgUAAoBEyYAARAABwQEMAIQMQcYAAEZLwEDFjIAFzMAGjQABAs2AAw3ABs4ABw5AAIIPgQSAAEBHj8AAR9BAAEETAIGGlEAH1AAIE0AIU4AIk8AI1IAARIAAQsWaAAaaQAebAAfZwAgZQAhZgAkZAAlagAmawAnbQAobgAAAAADFAAaOwAbPAAcAAAAAxQAGjsAGzwAHAEDAAEBAwABAxQAITsAIjwAIwAAAAMUACE7ACI8ACMDBAACBQABCKUBBAMEAAIFAAEIqwEEBRQAKDsAKzwALF0AKV4AKgAAAAAABRQAKDsAKzwALF0AKV4AKgMEAAIGAAEIvQEEAwQAAgYAAQjDAQQDFAAxOwAyPAAzAAAAAxQAMTsAMjwAMwMEAAIJAAUKAAUDBAACCQAFCgAFAxQAODsAOTwAOgAAAAMUADg7ADk8ADoFBAACBgABDesBBQ7sAQUP7QEDBQQAAgYAAQ3zAQUO9AEFD_UBAwMUAD87AEA8AEEAAAADFAA_OwBAPABBAxAABxEAARWHAgkDEAAHEQABFY0CCQUUAEY7AEk8AEpdAEdeAEgAAAAAAAUUAEY7AEk8AEpdAEdeAEgBEAAHARAABwMUAE87AFA8AFEAAAADFABPOwBQPABRBAS2AgIQtwIHGAABGbUCAQQEvgICEL8CBxgAARm9AgEDFABWOwBXPABYAAAAAxQAVjsAVzwAWAEG0QIBAQbXAgEFFABdOwBgPABhXQBeXgBfAAAAAAAFFABdOwBgPABhXQBeXgBfAAAABRQAZzsAajwAa10AaF4AaQAAAAAABRQAZzsAajwAa10AaF4AaQIIggMEEgABAgiIAwQSAAEFFABwOwBzPAB0XQBxXgByAAAAAAAFFABwOwBzPAB0XQBxXgByARIAAQESAAEFFAB5OwB8PAB9XQB6XgB7AAAAAAAFFAB5OwB8PAB9XQB6XgB7ARIAAQESAAEFFACCATsAhQE8AIYBXQCDAV4AhAEAAAAAAAUUAIIBOwCFATwAhgFdAIMBXgCEAQEExgMCAQTMAwIDFACLATsAjAE8AI0BAAAAAxQAiwE7AIwBPACNASkCASpvAStxASxyAS1zAS91ATB3FjF4FzJ6ATN8FjR9GDd-ATh_ATmAARY9gwEZPoQBHT-FAQJAhgECQYcBAkKIAQJDiQECRIsBAkWNARZGjgEeR5ABAkiSARZJkwEfSpQBAkuVAQJMlgEWTZkBIE6aASRPmwEDUJwBA1GdAQNSngEDU58BA1ShAQNVowEWVqQBJVenAQNYqQEWWaoBJlqsAQNbrQEDXK4BFl-xASdgsgEtYbMBBWK0AQVjtQEFZLYBBWW3AQVmuQEFZ7sBFmi8AS5pvwEFasEBFmvCAS9sxAEFbcUBBW7GARZvyQEwcMoBNHHLAQZyzAEGc80BBnTOAQZ1zwEGdtEBBnfTARZ41AE1edYBBnrYARZ72QE2fNoBBn3bAQZ-3AEWf98BN4AB4AE7gQHhAQeCAeIBB4MB4wEHhAHkAQeFAeUBB4YB5wEHhwHpARaIAeoBPIkB7wEHigHxARaLAfIBPYwB9gEHjQH3AQeOAfgBFo8B-wE-kAH8AUKRAf0BCJIB_gEIkwH_AQiUAYACCJUBgQIIlgGDAgiXAYUCFpgBhgJDmQGJAgiaAYsCFpsBjAJEnAGOAgidAY8CCJ4BkAIWnwGTAkWgAZQCS6EBlQILogGWAgujAZcCC6QBmAILpQGZAgumAZsCC6cBnQIWqAGeAkypAaACC6oBogIWqwGjAk2sAaQCC60BpQILrgGmAhavAakCTrABqgJSsQGrAgyyAawCDLMBrQIMtAGuAgy1Aa8CDLYBsQIMtwGzAha4AbQCU7kBuQIMugG7Aha7AbwCVLwBwAIMvQHBAgy-AcICFr8BxQJVwAHGAlnBAccCBMIByAIEwwHJAgTEAcoCBMUBywIExgHNAgTHAc8CFsgB0AJayQHTAgTKAdUCFssB1gJbzAHYAgTNAdkCBM4B2gIWzwHdAlzQAd4CYtEB4AJj0gHhAmPTAeQCY9QB5QJj1QHmAmPWAegCY9cB6gIW2AHrAmTZAe0CY9oB7wIW2wHwAmXcAfECY90B8gJj3gHzAhbfAfYCZuAB9wJs4QH4Ag_iAfkCD-MB-gIP5AH7Ag_lAfwCD-YB_gIP5wGAAxboAYEDbekBhAMP6gGGAxbrAYcDbuwBiQMP7QGKAw_uAYsDFu8BjgNv8AGPA3XxAZADFPIBkQMU8wGSAxT0AZMDFPUBlAMU9gGWAxT3AZgDFvgBmQN2-QGbAxT6AZ0DFvsBngN3_AGfAxT9AaADFP4BoQMW_wGkA3iAAqUDfoECpgMJggKnAwmDAqgDCYQCqQMJhQKqAwmGAqwDCYcCrgMWiAKvA3-JArEDCYoCswMWiwK0A4ABjAK1AwmNArYDCY4CtwMWjwK6A4EBkAK7A4cBkQK8AxKSAr0DEpMCvgMSlAK_AxKVAsADEpYCwgMSlwLEAxaYAsUDiAGZAsgDEpoCygMWmwLLA4kBnALNAxKdAs4DEp4CzwMWnwLSA4oBoALTA44B" -} - -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.world`: Exposes CRUD operations for the **World** model. - * Example usage: - * ```ts - * // Fetch zero or more Worlds - * const worlds = await prisma.world.findMany() - * ``` - */ - get world(): Prisma.WorldDelegate; - - /** - * `prisma.worldBibleVersion`: Exposes CRUD operations for the **WorldBibleVersion** model. - * Example usage: - * ```ts - * // Fetch zero or more WorldBibleVersions - * const worldBibleVersions = await prisma.worldBibleVersion.findMany() - * ``` - */ - get worldBibleVersion(): Prisma.WorldBibleVersionDelegate; - - /** - * `prisma.loreEntry`: Exposes CRUD operations for the **LoreEntry** model. - * Example usage: - * ```ts - * // Fetch zero or more LoreEntries - * const loreEntries = await prisma.loreEntry.findMany() - * ``` - */ - get loreEntry(): Prisma.LoreEntryDelegate; - - /** - * `prisma.loreRelationship`: Exposes CRUD operations for the **LoreRelationship** model. - * Example usage: - * ```ts - * // Fetch zero or more LoreRelationships - * const loreRelationships = await prisma.loreRelationship.findMany() - * ``` - */ - get loreRelationship(): Prisma.LoreRelationshipDelegate; - - /** - * `prisma.proposal`: Exposes CRUD operations for the **Proposal** model. - * Example usage: - * ```ts - * // Fetch zero or more Proposals - * const proposals = await prisma.proposal.findMany() - * ``` - */ - get proposal(): Prisma.ProposalDelegate; - - /** - * `prisma.appVote`: Exposes CRUD operations for the **AppVote** model. - * Example usage: - * ```ts - * // Fetch zero or more AppVotes - * const appVotes = await prisma.appVote.findMany() - * ``` - */ - get appVote(): Prisma.AppVoteDelegate; - - /** - * `prisma.aIReport`: Exposes CRUD operations for the **AIReport** model. - * Example usage: - * ```ts - * // Fetch zero or more AIReports - * const aIReports = await prisma.aIReport.findMany() - * ``` - */ - get aIReport(): Prisma.AIReportDelegate; - - /** - * `prisma.moderationReport`: Exposes CRUD operations for the **ModerationReport** model. - * Example usage: - * ```ts - * // Fetch zero or more ModerationReports - * const moderationReports = await prisma.moderationReport.findMany() - * ``` - */ - get moderationReport(): Prisma.ModerationReportDelegate; - - /** - * `prisma.hiveReference`: Exposes CRUD operations for the **HiveReference** model. - * Example usage: - * ```ts - * // Fetch zero or more HiveReferences - * const hiveReferences = await prisma.hiveReference.findMany() - * ``` - */ - get hiveReference(): Prisma.HiveReferenceDelegate; - - /** - * `prisma.hiveEvent`: Exposes CRUD operations for the **HiveEvent** model. - * Example usage: - * ```ts - * // Fetch zero or more HiveEvents - * const hiveEvents = await prisma.hiveEvent.findMany() - * ``` - */ - get hiveEvent(): Prisma.HiveEventDelegate; - - /** - * `prisma.rewardRecord`: Exposes CRUD operations for the **RewardRecord** model. - * Example usage: - * ```ts - * // Fetch zero or more RewardRecords - * const rewardRecords = await prisma.rewardRecord.findMany() - * ``` - */ - get rewardRecord(): Prisma.RewardRecordDelegate; - - /** - * `prisma.userRewardSummary`: Exposes CRUD operations for the **UserRewardSummary** model. - * Example usage: - * ```ts - * // Fetch zero or more UserRewardSummaries - * const userRewardSummaries = await prisma.userRewardSummary.findMany() - * ``` - */ - get userRewardSummary(): Prisma.UserRewardSummaryDelegate; - - /** - * `prisma.userReputationSnapshot`: Exposes CRUD operations for the **UserReputationSnapshot** model. - * Example usage: - * ```ts - * // Fetch zero or more UserReputationSnapshots - * const userReputationSnapshots = await prisma.userReputationSnapshot.findMany() - * ``` - */ - get userReputationSnapshot(): Prisma.UserReputationSnapshotDelegate; - - /** - * `prisma.searchIndex`: Exposes CRUD operations for the **SearchIndex** model. - * Example usage: - * ```ts - * // Fetch zero or more SearchIndices - * const searchIndices = await prisma.searchIndex.findMany() - * ``` - */ - get searchIndex(): Prisma.SearchIndexDelegate; -} - -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 deleted file mode 100644 index 5353583..0000000 --- a/apps/api/src/generated/prisma/internal/prismaNamespace.ts +++ /dev/null @@ -1,2321 +0,0 @@ - -/* !!! 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', - World: 'World', - WorldBibleVersion: 'WorldBibleVersion', - LoreEntry: 'LoreEntry', - LoreRelationship: 'LoreRelationship', - Proposal: 'Proposal', - AppVote: 'AppVote', - AIReport: 'AIReport', - ModerationReport: 'ModerationReport', - HiveReference: 'HiveReference', - HiveEvent: 'HiveEvent', - RewardRecord: 'RewardRecord', - UserRewardSummary: 'UserRewardSummary', - UserReputationSnapshot: 'UserReputationSnapshot', - SearchIndex: 'SearchIndex' -} 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" | "world" | "worldBibleVersion" | "loreEntry" | "loreRelationship" | "proposal" | "appVote" | "aIReport" | "moderationReport" | "hiveReference" | "hiveEvent" | "rewardRecord" | "userRewardSummary" | "userReputationSnapshot" | "searchIndex" - 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 - } - } - } - World: { - payload: Prisma.$WorldPayload - fields: Prisma.WorldFieldRefs - operations: { - findUnique: { - args: Prisma.WorldFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.WorldFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.WorldFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.WorldFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.WorldFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.WorldCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.WorldCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.WorldCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.WorldDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.WorldUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.WorldDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.WorldUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.WorldUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.WorldUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.WorldAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.WorldGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.WorldCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - WorldBibleVersion: { - payload: Prisma.$WorldBibleVersionPayload - fields: Prisma.WorldBibleVersionFieldRefs - operations: { - findUnique: { - args: Prisma.WorldBibleVersionFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.WorldBibleVersionFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.WorldBibleVersionFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.WorldBibleVersionFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.WorldBibleVersionFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.WorldBibleVersionCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.WorldBibleVersionCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.WorldBibleVersionCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.WorldBibleVersionDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.WorldBibleVersionUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.WorldBibleVersionDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.WorldBibleVersionUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.WorldBibleVersionUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.WorldBibleVersionUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.WorldBibleVersionAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.WorldBibleVersionGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.WorldBibleVersionCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - LoreEntry: { - payload: Prisma.$LoreEntryPayload - fields: Prisma.LoreEntryFieldRefs - operations: { - findUnique: { - args: Prisma.LoreEntryFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.LoreEntryFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.LoreEntryFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.LoreEntryFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.LoreEntryFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.LoreEntryCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.LoreEntryCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.LoreEntryCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.LoreEntryDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.LoreEntryUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.LoreEntryDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.LoreEntryUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.LoreEntryUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.LoreEntryUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.LoreEntryAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.LoreEntryGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.LoreEntryCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - LoreRelationship: { - payload: Prisma.$LoreRelationshipPayload - fields: Prisma.LoreRelationshipFieldRefs - operations: { - findUnique: { - args: Prisma.LoreRelationshipFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.LoreRelationshipFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.LoreRelationshipFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.LoreRelationshipFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.LoreRelationshipFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.LoreRelationshipCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.LoreRelationshipCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.LoreRelationshipCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.LoreRelationshipDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.LoreRelationshipUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.LoreRelationshipDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.LoreRelationshipUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.LoreRelationshipUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.LoreRelationshipUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.LoreRelationshipAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.LoreRelationshipGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.LoreRelationshipCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - Proposal: { - payload: Prisma.$ProposalPayload - fields: Prisma.ProposalFieldRefs - operations: { - findUnique: { - args: Prisma.ProposalFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.ProposalFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.ProposalFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.ProposalFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.ProposalFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.ProposalCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.ProposalCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.ProposalCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.ProposalDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.ProposalUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.ProposalDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.ProposalUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.ProposalUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.ProposalUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.ProposalAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.ProposalGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.ProposalCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - AppVote: { - payload: Prisma.$AppVotePayload - fields: Prisma.AppVoteFieldRefs - operations: { - findUnique: { - args: Prisma.AppVoteFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.AppVoteFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.AppVoteFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.AppVoteFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.AppVoteFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.AppVoteCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.AppVoteCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.AppVoteCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.AppVoteDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.AppVoteUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.AppVoteDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.AppVoteUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.AppVoteUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.AppVoteUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.AppVoteAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.AppVoteGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.AppVoteCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - AIReport: { - payload: Prisma.$AIReportPayload - fields: Prisma.AIReportFieldRefs - operations: { - findUnique: { - args: Prisma.AIReportFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.AIReportFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.AIReportFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.AIReportFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.AIReportFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.AIReportCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.AIReportCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.AIReportCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.AIReportDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.AIReportUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.AIReportDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.AIReportUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.AIReportUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.AIReportUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.AIReportAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.AIReportGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.AIReportCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - ModerationReport: { - payload: Prisma.$ModerationReportPayload - fields: Prisma.ModerationReportFieldRefs - operations: { - findUnique: { - args: Prisma.ModerationReportFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.ModerationReportFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.ModerationReportFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.ModerationReportFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.ModerationReportFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.ModerationReportCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.ModerationReportCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.ModerationReportCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.ModerationReportDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.ModerationReportUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.ModerationReportDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.ModerationReportUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.ModerationReportUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.ModerationReportUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.ModerationReportAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.ModerationReportGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.ModerationReportCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - HiveReference: { - payload: Prisma.$HiveReferencePayload - fields: Prisma.HiveReferenceFieldRefs - operations: { - findUnique: { - args: Prisma.HiveReferenceFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.HiveReferenceFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.HiveReferenceFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.HiveReferenceFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.HiveReferenceFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.HiveReferenceCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.HiveReferenceCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.HiveReferenceCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.HiveReferenceDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.HiveReferenceUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.HiveReferenceDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.HiveReferenceUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.HiveReferenceUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.HiveReferenceUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.HiveReferenceAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.HiveReferenceGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.HiveReferenceCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - HiveEvent: { - payload: Prisma.$HiveEventPayload - fields: Prisma.HiveEventFieldRefs - operations: { - findUnique: { - args: Prisma.HiveEventFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.HiveEventFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.HiveEventFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.HiveEventFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.HiveEventFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.HiveEventCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.HiveEventCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.HiveEventCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.HiveEventDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.HiveEventUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.HiveEventDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.HiveEventUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.HiveEventUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.HiveEventUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.HiveEventAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.HiveEventGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.HiveEventCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - RewardRecord: { - payload: Prisma.$RewardRecordPayload - fields: Prisma.RewardRecordFieldRefs - operations: { - findUnique: { - args: Prisma.RewardRecordFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.RewardRecordFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.RewardRecordFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.RewardRecordFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.RewardRecordFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.RewardRecordCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.RewardRecordCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.RewardRecordCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.RewardRecordDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.RewardRecordUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.RewardRecordDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.RewardRecordUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.RewardRecordUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.RewardRecordUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.RewardRecordAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.RewardRecordGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.RewardRecordCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - UserRewardSummary: { - payload: Prisma.$UserRewardSummaryPayload - fields: Prisma.UserRewardSummaryFieldRefs - operations: { - findUnique: { - args: Prisma.UserRewardSummaryFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.UserRewardSummaryFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.UserRewardSummaryFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.UserRewardSummaryFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.UserRewardSummaryFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.UserRewardSummaryCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.UserRewardSummaryCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.UserRewardSummaryCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.UserRewardSummaryDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.UserRewardSummaryUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.UserRewardSummaryDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.UserRewardSummaryUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.UserRewardSummaryUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.UserRewardSummaryUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.UserRewardSummaryAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.UserRewardSummaryGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.UserRewardSummaryCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - UserReputationSnapshot: { - payload: Prisma.$UserReputationSnapshotPayload - fields: Prisma.UserReputationSnapshotFieldRefs - operations: { - findUnique: { - args: Prisma.UserReputationSnapshotFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.UserReputationSnapshotFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.UserReputationSnapshotFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.UserReputationSnapshotFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.UserReputationSnapshotFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.UserReputationSnapshotCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.UserReputationSnapshotCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.UserReputationSnapshotCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.UserReputationSnapshotDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.UserReputationSnapshotUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.UserReputationSnapshotDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.UserReputationSnapshotUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.UserReputationSnapshotUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.UserReputationSnapshotUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.UserReputationSnapshotAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.UserReputationSnapshotGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.UserReputationSnapshotCountArgs - result: runtime.Types.Utils.Optional | number - } - } - } - SearchIndex: { - payload: Prisma.$SearchIndexPayload - fields: Prisma.SearchIndexFieldRefs - operations: { - findUnique: { - args: Prisma.SearchIndexFindUniqueArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findUniqueOrThrow: { - args: Prisma.SearchIndexFindUniqueOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findFirst: { - args: Prisma.SearchIndexFindFirstArgs - result: runtime.Types.Utils.PayloadToResult | null - } - findFirstOrThrow: { - args: Prisma.SearchIndexFindFirstOrThrowArgs - result: runtime.Types.Utils.PayloadToResult - } - findMany: { - args: Prisma.SearchIndexFindManyArgs - result: runtime.Types.Utils.PayloadToResult[] - } - create: { - args: Prisma.SearchIndexCreateArgs - result: runtime.Types.Utils.PayloadToResult - } - createMany: { - args: Prisma.SearchIndexCreateManyArgs - result: BatchPayload - } - createManyAndReturn: { - args: Prisma.SearchIndexCreateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - delete: { - args: Prisma.SearchIndexDeleteArgs - result: runtime.Types.Utils.PayloadToResult - } - update: { - args: Prisma.SearchIndexUpdateArgs - result: runtime.Types.Utils.PayloadToResult - } - deleteMany: { - args: Prisma.SearchIndexDeleteManyArgs - result: BatchPayload - } - updateMany: { - args: Prisma.SearchIndexUpdateManyArgs - result: BatchPayload - } - updateManyAndReturn: { - args: Prisma.SearchIndexUpdateManyAndReturnArgs - result: runtime.Types.Utils.PayloadToResult[] - } - upsert: { - args: Prisma.SearchIndexUpsertArgs - result: runtime.Types.Utils.PayloadToResult - } - aggregate: { - args: Prisma.SearchIndexAggregateArgs - result: runtime.Types.Utils.Optional - } - groupBy: { - args: Prisma.SearchIndexGroupByArgs - result: runtime.Types.Utils.Optional[] - } - count: { - args: Prisma.SearchIndexCountArgs - 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', - hiveUsername: 'hiveUsername', - normalizedHiveUsername: 'normalizedHiveUsername', - displayName: 'displayName', - avatarUrl: 'avatarUrl', - bio: 'bio', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] - - -export const WorldScalarFieldEnum = { - id: 'id', - slug: 'slug', - title: 'title', - description: 'description', - founderId: 'founderId', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type WorldScalarFieldEnum = (typeof WorldScalarFieldEnum)[keyof typeof WorldScalarFieldEnum] - - -export const WorldBibleVersionScalarFieldEnum = { - id: 'id', - worldId: 'worldId', - versionNumber: 'versionNumber', - creatorId: 'creatorId', - content: 'content', - changeSummary: 'changeSummary', - publishedAt: 'publishedAt', - hiveReferenceId: 'hiveReferenceId', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type WorldBibleVersionScalarFieldEnum = (typeof WorldBibleVersionScalarFieldEnum)[keyof typeof WorldBibleVersionScalarFieldEnum] - - -export const LoreEntryScalarFieldEnum = { - id: 'id', - worldId: 'worldId', - authorId: 'authorId', - title: 'title', - slug: 'slug', - loreType: 'loreType', - content: 'content', - status: 'status', - publishedAt: 'publishedAt', - hiveReferenceId: 'hiveReferenceId', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type LoreEntryScalarFieldEnum = (typeof LoreEntryScalarFieldEnum)[keyof typeof LoreEntryScalarFieldEnum] - - -export const LoreRelationshipScalarFieldEnum = { - id: 'id', - worldId: 'worldId', - sourceId: 'sourceId', - targetId: 'targetId', - relationType: 'relationType', - metadata: 'metadata', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type LoreRelationshipScalarFieldEnum = (typeof LoreRelationshipScalarFieldEnum)[keyof typeof LoreRelationshipScalarFieldEnum] - - -export const ProposalScalarFieldEnum = { - id: 'id', - worldId: 'worldId', - authorId: 'authorId', - proposalType: 'proposalType', - status: 'status', - title: 'title', - summary: 'summary', - proposedContent: 'proposedContent', - targetLoreEntryId: 'targetLoreEntryId', - resultingLoreEntryId: 'resultingLoreEntryId', - resultingBibleVersionId: 'resultingBibleVersionId', - submittedAt: 'submittedAt', - votingStartedAt: 'votingStartedAt', - approvedAt: 'approvedAt', - rejectedAt: 'rejectedAt', - publishedAt: 'publishedAt', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type ProposalScalarFieldEnum = (typeof ProposalScalarFieldEnum)[keyof typeof ProposalScalarFieldEnum] - - -export const AppVoteScalarFieldEnum = { - id: 'id', - proposalId: 'proposalId', - voterId: 'voterId', - choice: 'choice', - reputationScoreAtVote: 'reputationScoreAtVote', - reputationSnapshotId: 'reputationSnapshotId', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type AppVoteScalarFieldEnum = (typeof AppVoteScalarFieldEnum)[keyof typeof AppVoteScalarFieldEnum] - - -export const AIReportScalarFieldEnum = { - id: 'id', - proposalId: 'proposalId', - provider: 'provider', - model: 'model', - status: 'status', - summary: 'summary', - findings: 'findings', - errorCode: 'errorCode', - errorMessage: 'errorMessage', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type AIReportScalarFieldEnum = (typeof AIReportScalarFieldEnum)[keyof typeof AIReportScalarFieldEnum] - - -export const ModerationReportScalarFieldEnum = { - id: 'id', - reporterId: 'reporterId', - reviewerId: 'reviewerId', - worldId: 'worldId', - proposalId: 'proposalId', - targetType: 'targetType', - targetId: 'targetId', - reason: 'reason', - details: 'details', - status: 'status', - reviewedAt: 'reviewedAt', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type ModerationReportScalarFieldEnum = (typeof ModerationReportScalarFieldEnum)[keyof typeof ModerationReportScalarFieldEnum] - - -export const HiveReferenceScalarFieldEnum = { - id: 'id', - entityType: 'entityType', - entityId: 'entityId', - hiveAuthorUsername: 'hiveAuthorUsername', - authorId: 'authorId', - permlink: 'permlink', - transactionId: 'transactionId', - blockNumber: 'blockNumber', - operationIndex: 'operationIndex', - publicationMetadata: 'publicationMetadata', - publishedAt: 'publishedAt', - indexedAt: 'indexedAt', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type HiveReferenceScalarFieldEnum = (typeof HiveReferenceScalarFieldEnum)[keyof typeof HiveReferenceScalarFieldEnum] - - -export const HiveEventScalarFieldEnum = { - id: 'id', - blockNumber: 'blockNumber', - transactionId: 'transactionId', - operationIndex: 'operationIndex', - eventType: 'eventType', - blockchainTimestamp: 'blockchainTimestamp', - payload: 'payload', - processedAt: 'processedAt', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type HiveEventScalarFieldEnum = (typeof HiveEventScalarFieldEnum)[keyof typeof HiveEventScalarFieldEnum] - - -export const RewardRecordScalarFieldEnum = { - id: 'id', - userId: 'userId', - hiveReferenceId: 'hiveReferenceId', - rewardType: 'rewardType', - assetSymbol: 'assetSymbol', - amount: 'amount', - transactionId: 'transactionId', - operationIndex: 'operationIndex', - blockNumber: 'blockNumber', - payoutAt: 'payoutAt', - idempotencyKey: 'idempotencyKey', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type RewardRecordScalarFieldEnum = (typeof RewardRecordScalarFieldEnum)[keyof typeof RewardRecordScalarFieldEnum] - - -export const UserRewardSummaryScalarFieldEnum = { - id: 'id', - userId: 'userId', - assetSymbol: 'assetSymbol', - totalAmount: 'totalAmount', - lastCalculatedAt: 'lastCalculatedAt', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type UserRewardSummaryScalarFieldEnum = (typeof UserRewardSummaryScalarFieldEnum)[keyof typeof UserRewardSummaryScalarFieldEnum] - - -export const UserReputationSnapshotScalarFieldEnum = { - id: 'id', - userId: 'userId', - score: 'score', - calculationVersion: 'calculationVersion', - breakdown: 'breakdown', - calculatedAt: 'calculatedAt', - createdAt: 'createdAt' -} as const - -export type UserReputationSnapshotScalarFieldEnum = (typeof UserReputationSnapshotScalarFieldEnum)[keyof typeof UserReputationSnapshotScalarFieldEnum] - - -export const SearchIndexScalarFieldEnum = { - id: 'id', - worldId: 'worldId', - entityType: 'entityType', - entityId: 'entityId', - title: 'title', - searchableContent: 'searchableContent', - metadata: 'metadata', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type SearchIndexScalarFieldEnum = (typeof SearchIndexScalarFieldEnum)[keyof typeof SearchIndexScalarFieldEnum] - - -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 '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 '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 '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 'LoreType' - */ -export type EnumLoreTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'LoreType'> - - - -/** - * Reference to a field of type 'LoreType[]' - */ -export type ListEnumLoreTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'LoreType[]'> - - - -/** - * Reference to a field of type 'LoreStatus' - */ -export type EnumLoreStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'LoreStatus'> - - - -/** - * Reference to a field of type 'LoreStatus[]' - */ -export type ListEnumLoreStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'LoreStatus[]'> - - - -/** - * Reference to a field of type 'ProposalType' - */ -export type EnumProposalTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ProposalType'> - - - -/** - * Reference to a field of type 'ProposalType[]' - */ -export type ListEnumProposalTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ProposalType[]'> - - - -/** - * Reference to a field of type 'ProposalStatus' - */ -export type EnumProposalStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ProposalStatus'> - - - -/** - * Reference to a field of type 'ProposalStatus[]' - */ -export type ListEnumProposalStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ProposalStatus[]'> - - - -/** - * Reference to a field of type 'VoteChoice' - */ -export type EnumVoteChoiceFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'VoteChoice'> - - - -/** - * Reference to a field of type 'VoteChoice[]' - */ -export type ListEnumVoteChoiceFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'VoteChoice[]'> - - - -/** - * Reference to a field of type 'Decimal' - */ -export type DecimalFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Decimal'> - - - -/** - * Reference to a field of type 'Decimal[]' - */ -export type ListDecimalFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Decimal[]'> - - - -/** - * Reference to a field of type 'AIReportStatus' - */ -export type EnumAIReportStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'AIReportStatus'> - - - -/** - * Reference to a field of type 'AIReportStatus[]' - */ -export type ListEnumAIReportStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'AIReportStatus[]'> - - - -/** - * Reference to a field of type 'ModerationTargetType' - */ -export type EnumModerationTargetTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ModerationTargetType'> - - - -/** - * Reference to a field of type 'ModerationTargetType[]' - */ -export type ListEnumModerationTargetTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ModerationTargetType[]'> - - - -/** - * Reference to a field of type 'ModerationStatus' - */ -export type EnumModerationStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ModerationStatus'> - - - -/** - * Reference to a field of type 'ModerationStatus[]' - */ -export type ListEnumModerationStatusFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'ModerationStatus[]'> - - - -/** - * Reference to a field of type 'HiveEntityType' - */ -export type EnumHiveEntityTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'HiveEntityType'> - - - -/** - * Reference to a field of type 'HiveEntityType[]' - */ -export type ListEnumHiveEntityTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'HiveEntityType[]'> - - - -/** - * Reference to a field of type 'BigInt' - */ -export type BigIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'BigInt'> - - - -/** - * Reference to a field of type 'BigInt[]' - */ -export type ListBigIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'BigInt[]'> - - - -/** - * Reference to a field of type 'HiveEventType' - */ -export type EnumHiveEventTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'HiveEventType'> - - - -/** - * Reference to a field of type 'HiveEventType[]' - */ -export type ListEnumHiveEventTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'HiveEventType[]'> - - - -/** - * Reference to a field of type 'RewardType' - */ -export type EnumRewardTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'RewardType'> - - - -/** - * Reference to a field of type 'RewardType[]' - */ -export type ListEnumRewardTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'RewardType[]'> - - - -/** - * Reference to a field of type 'SearchEntityType' - */ -export type EnumSearchEntityTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'SearchEntityType'> - - - -/** - * Reference to a field of type 'SearchEntityType[]' - */ -export type ListEnumSearchEntityTypeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'SearchEntityType[]'> - - - -/** - * 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 - world?: Prisma.WorldOmit - worldBibleVersion?: Prisma.WorldBibleVersionOmit - loreEntry?: Prisma.LoreEntryOmit - loreRelationship?: Prisma.LoreRelationshipOmit - proposal?: Prisma.ProposalOmit - appVote?: Prisma.AppVoteOmit - aIReport?: Prisma.AIReportOmit - moderationReport?: Prisma.ModerationReportOmit - hiveReference?: Prisma.HiveReferenceOmit - hiveEvent?: Prisma.HiveEventOmit - rewardRecord?: Prisma.RewardRecordOmit - userRewardSummary?: Prisma.UserRewardSummaryOmit - userReputationSnapshot?: Prisma.UserReputationSnapshotOmit - searchIndex?: Prisma.SearchIndexOmit -} - -/* 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 deleted file mode 100644 index 25b5bd7..0000000 --- a/apps/api/src/generated/prisma/internal/prismaNamespaceBrowser.ts +++ /dev/null @@ -1,378 +0,0 @@ - -/* !!! 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', - World: 'World', - WorldBibleVersion: 'WorldBibleVersion', - LoreEntry: 'LoreEntry', - LoreRelationship: 'LoreRelationship', - Proposal: 'Proposal', - AppVote: 'AppVote', - AIReport: 'AIReport', - ModerationReport: 'ModerationReport', - HiveReference: 'HiveReference', - HiveEvent: 'HiveEvent', - RewardRecord: 'RewardRecord', - UserRewardSummary: 'UserRewardSummary', - UserReputationSnapshot: 'UserReputationSnapshot', - SearchIndex: 'SearchIndex' -} 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', - hiveUsername: 'hiveUsername', - normalizedHiveUsername: 'normalizedHiveUsername', - displayName: 'displayName', - avatarUrl: 'avatarUrl', - bio: 'bio', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] - - -export const WorldScalarFieldEnum = { - id: 'id', - slug: 'slug', - title: 'title', - description: 'description', - founderId: 'founderId', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type WorldScalarFieldEnum = (typeof WorldScalarFieldEnum)[keyof typeof WorldScalarFieldEnum] - - -export const WorldBibleVersionScalarFieldEnum = { - id: 'id', - worldId: 'worldId', - versionNumber: 'versionNumber', - creatorId: 'creatorId', - content: 'content', - changeSummary: 'changeSummary', - publishedAt: 'publishedAt', - hiveReferenceId: 'hiveReferenceId', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type WorldBibleVersionScalarFieldEnum = (typeof WorldBibleVersionScalarFieldEnum)[keyof typeof WorldBibleVersionScalarFieldEnum] - - -export const LoreEntryScalarFieldEnum = { - id: 'id', - worldId: 'worldId', - authorId: 'authorId', - title: 'title', - slug: 'slug', - loreType: 'loreType', - content: 'content', - status: 'status', - publishedAt: 'publishedAt', - hiveReferenceId: 'hiveReferenceId', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type LoreEntryScalarFieldEnum = (typeof LoreEntryScalarFieldEnum)[keyof typeof LoreEntryScalarFieldEnum] - - -export const LoreRelationshipScalarFieldEnum = { - id: 'id', - worldId: 'worldId', - sourceId: 'sourceId', - targetId: 'targetId', - relationType: 'relationType', - metadata: 'metadata', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type LoreRelationshipScalarFieldEnum = (typeof LoreRelationshipScalarFieldEnum)[keyof typeof LoreRelationshipScalarFieldEnum] - - -export const ProposalScalarFieldEnum = { - id: 'id', - worldId: 'worldId', - authorId: 'authorId', - proposalType: 'proposalType', - status: 'status', - title: 'title', - summary: 'summary', - proposedContent: 'proposedContent', - targetLoreEntryId: 'targetLoreEntryId', - resultingLoreEntryId: 'resultingLoreEntryId', - resultingBibleVersionId: 'resultingBibleVersionId', - submittedAt: 'submittedAt', - votingStartedAt: 'votingStartedAt', - approvedAt: 'approvedAt', - rejectedAt: 'rejectedAt', - publishedAt: 'publishedAt', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type ProposalScalarFieldEnum = (typeof ProposalScalarFieldEnum)[keyof typeof ProposalScalarFieldEnum] - - -export const AppVoteScalarFieldEnum = { - id: 'id', - proposalId: 'proposalId', - voterId: 'voterId', - choice: 'choice', - reputationScoreAtVote: 'reputationScoreAtVote', - reputationSnapshotId: 'reputationSnapshotId', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type AppVoteScalarFieldEnum = (typeof AppVoteScalarFieldEnum)[keyof typeof AppVoteScalarFieldEnum] - - -export const AIReportScalarFieldEnum = { - id: 'id', - proposalId: 'proposalId', - provider: 'provider', - model: 'model', - status: 'status', - summary: 'summary', - findings: 'findings', - errorCode: 'errorCode', - errorMessage: 'errorMessage', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type AIReportScalarFieldEnum = (typeof AIReportScalarFieldEnum)[keyof typeof AIReportScalarFieldEnum] - - -export const ModerationReportScalarFieldEnum = { - id: 'id', - reporterId: 'reporterId', - reviewerId: 'reviewerId', - worldId: 'worldId', - proposalId: 'proposalId', - targetType: 'targetType', - targetId: 'targetId', - reason: 'reason', - details: 'details', - status: 'status', - reviewedAt: 'reviewedAt', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type ModerationReportScalarFieldEnum = (typeof ModerationReportScalarFieldEnum)[keyof typeof ModerationReportScalarFieldEnum] - - -export const HiveReferenceScalarFieldEnum = { - id: 'id', - entityType: 'entityType', - entityId: 'entityId', - hiveAuthorUsername: 'hiveAuthorUsername', - authorId: 'authorId', - permlink: 'permlink', - transactionId: 'transactionId', - blockNumber: 'blockNumber', - operationIndex: 'operationIndex', - publicationMetadata: 'publicationMetadata', - publishedAt: 'publishedAt', - indexedAt: 'indexedAt', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type HiveReferenceScalarFieldEnum = (typeof HiveReferenceScalarFieldEnum)[keyof typeof HiveReferenceScalarFieldEnum] - - -export const HiveEventScalarFieldEnum = { - id: 'id', - blockNumber: 'blockNumber', - transactionId: 'transactionId', - operationIndex: 'operationIndex', - eventType: 'eventType', - blockchainTimestamp: 'blockchainTimestamp', - payload: 'payload', - processedAt: 'processedAt', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type HiveEventScalarFieldEnum = (typeof HiveEventScalarFieldEnum)[keyof typeof HiveEventScalarFieldEnum] - - -export const RewardRecordScalarFieldEnum = { - id: 'id', - userId: 'userId', - hiveReferenceId: 'hiveReferenceId', - rewardType: 'rewardType', - assetSymbol: 'assetSymbol', - amount: 'amount', - transactionId: 'transactionId', - operationIndex: 'operationIndex', - blockNumber: 'blockNumber', - payoutAt: 'payoutAt', - idempotencyKey: 'idempotencyKey', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type RewardRecordScalarFieldEnum = (typeof RewardRecordScalarFieldEnum)[keyof typeof RewardRecordScalarFieldEnum] - - -export const UserRewardSummaryScalarFieldEnum = { - id: 'id', - userId: 'userId', - assetSymbol: 'assetSymbol', - totalAmount: 'totalAmount', - lastCalculatedAt: 'lastCalculatedAt', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type UserRewardSummaryScalarFieldEnum = (typeof UserRewardSummaryScalarFieldEnum)[keyof typeof UserRewardSummaryScalarFieldEnum] - - -export const UserReputationSnapshotScalarFieldEnum = { - id: 'id', - userId: 'userId', - score: 'score', - calculationVersion: 'calculationVersion', - breakdown: 'breakdown', - calculatedAt: 'calculatedAt', - createdAt: 'createdAt' -} as const - -export type UserReputationSnapshotScalarFieldEnum = (typeof UserReputationSnapshotScalarFieldEnum)[keyof typeof UserReputationSnapshotScalarFieldEnum] - - -export const SearchIndexScalarFieldEnum = { - id: 'id', - worldId: 'worldId', - entityType: 'entityType', - entityId: 'entityId', - title: 'title', - searchableContent: 'searchableContent', - metadata: 'metadata', - createdAt: 'createdAt', - updatedAt: 'updatedAt' -} as const - -export type SearchIndexScalarFieldEnum = (typeof SearchIndexScalarFieldEnum)[keyof typeof SearchIndexScalarFieldEnum] - - -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 deleted file mode 100644 index 44f04d0..0000000 --- a/apps/api/src/generated/prisma/models.ts +++ /dev/null @@ -1,26 +0,0 @@ - -/* !!! 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/World.js' -export type * from './models/WorldBibleVersion.js' -export type * from './models/LoreEntry.js' -export type * from './models/LoreRelationship.js' -export type * from './models/Proposal.js' -export type * from './models/AppVote.js' -export type * from './models/AIReport.js' -export type * from './models/ModerationReport.js' -export type * from './models/HiveReference.js' -export type * from './models/HiveEvent.js' -export type * from './models/RewardRecord.js' -export type * from './models/UserRewardSummary.js' -export type * from './models/UserReputationSnapshot.js' -export type * from './models/SearchIndex.js' -export type * from './commonInputTypes.js' \ No newline at end of file diff --git a/apps/api/src/generated/prisma/models/AIReport.ts b/apps/api/src/generated/prisma/models/AIReport.ts deleted file mode 100644 index 1d88dcf..0000000 --- a/apps/api/src/generated/prisma/models/AIReport.ts +++ /dev/null @@ -1,1553 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `AIReport` 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 AIReport - * - */ -export type AIReportModel = runtime.Types.Result.DefaultSelection - -export type AggregateAIReport = { - _count: AIReportCountAggregateOutputType | null - _min: AIReportMinAggregateOutputType | null - _max: AIReportMaxAggregateOutputType | null -} - -export type AIReportMinAggregateOutputType = { - id: string | null - proposalId: string | null - provider: string | null - model: string | null - status: $Enums.AIReportStatus | null - summary: string | null - errorCode: string | null - errorMessage: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type AIReportMaxAggregateOutputType = { - id: string | null - proposalId: string | null - provider: string | null - model: string | null - status: $Enums.AIReportStatus | null - summary: string | null - errorCode: string | null - errorMessage: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type AIReportCountAggregateOutputType = { - id: number - proposalId: number - provider: number - model: number - status: number - summary: number - findings: number - errorCode: number - errorMessage: number - createdAt: number - updatedAt: number - _all: number -} - - -export type AIReportMinAggregateInputType = { - id?: true - proposalId?: true - provider?: true - model?: true - status?: true - summary?: true - errorCode?: true - errorMessage?: true - createdAt?: true - updatedAt?: true -} - -export type AIReportMaxAggregateInputType = { - id?: true - proposalId?: true - provider?: true - model?: true - status?: true - summary?: true - errorCode?: true - errorMessage?: true - createdAt?: true - updatedAt?: true -} - -export type AIReportCountAggregateInputType = { - id?: true - proposalId?: true - provider?: true - model?: true - status?: true - summary?: true - findings?: true - errorCode?: true - errorMessage?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type AIReportAggregateArgs = { - /** - * Filter which AIReport to aggregate. - */ - where?: Prisma.AIReportWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of AIReports to fetch. - */ - orderBy?: Prisma.AIReportOrderByWithRelationInput | Prisma.AIReportOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.AIReportWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` AIReports 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` AIReports. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned AIReports - **/ - _count?: true | AIReportCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: AIReportMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: AIReportMaxAggregateInputType -} - -export type GetAIReportAggregateType = { - [P in keyof T & keyof AggregateAIReport]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type AIReportGroupByArgs = { - where?: Prisma.AIReportWhereInput - orderBy?: Prisma.AIReportOrderByWithAggregationInput | Prisma.AIReportOrderByWithAggregationInput[] - by: Prisma.AIReportScalarFieldEnum[] | Prisma.AIReportScalarFieldEnum - having?: Prisma.AIReportScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: AIReportCountAggregateInputType | true - _min?: AIReportMinAggregateInputType - _max?: AIReportMaxAggregateInputType -} - -export type AIReportGroupByOutputType = { - id: string - proposalId: string - provider: string - model: string - status: $Enums.AIReportStatus - summary: string | null - findings: runtime.JsonValue | null - errorCode: string | null - errorMessage: string | null - createdAt: Date - updatedAt: Date - _count: AIReportCountAggregateOutputType | null - _min: AIReportMinAggregateOutputType | null - _max: AIReportMaxAggregateOutputType | null -} - -export type GetAIReportGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof AIReportGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type AIReportWhereInput = { - AND?: Prisma.AIReportWhereInput | Prisma.AIReportWhereInput[] - OR?: Prisma.AIReportWhereInput[] - NOT?: Prisma.AIReportWhereInput | Prisma.AIReportWhereInput[] - id?: Prisma.StringFilter<"AIReport"> | string - proposalId?: Prisma.StringFilter<"AIReport"> | string - provider?: Prisma.StringFilter<"AIReport"> | string - model?: Prisma.StringFilter<"AIReport"> | string - status?: Prisma.EnumAIReportStatusFilter<"AIReport"> | $Enums.AIReportStatus - summary?: Prisma.StringNullableFilter<"AIReport"> | string | null - findings?: Prisma.JsonNullableFilter<"AIReport"> - errorCode?: Prisma.StringNullableFilter<"AIReport"> | string | null - errorMessage?: Prisma.StringNullableFilter<"AIReport"> | string | null - createdAt?: Prisma.DateTimeFilter<"AIReport"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"AIReport"> | Date | string - proposal?: Prisma.XOR -} - -export type AIReportOrderByWithRelationInput = { - id?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - provider?: Prisma.SortOrder - model?: Prisma.SortOrder - status?: Prisma.SortOrder - summary?: Prisma.SortOrderInput | Prisma.SortOrder - findings?: Prisma.SortOrderInput | Prisma.SortOrder - errorCode?: Prisma.SortOrderInput | Prisma.SortOrder - errorMessage?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - proposal?: Prisma.ProposalOrderByWithRelationInput -} - -export type AIReportWhereUniqueInput = Prisma.AtLeast<{ - id?: string - AND?: Prisma.AIReportWhereInput | Prisma.AIReportWhereInput[] - OR?: Prisma.AIReportWhereInput[] - NOT?: Prisma.AIReportWhereInput | Prisma.AIReportWhereInput[] - proposalId?: Prisma.StringFilter<"AIReport"> | string - provider?: Prisma.StringFilter<"AIReport"> | string - model?: Prisma.StringFilter<"AIReport"> | string - status?: Prisma.EnumAIReportStatusFilter<"AIReport"> | $Enums.AIReportStatus - summary?: Prisma.StringNullableFilter<"AIReport"> | string | null - findings?: Prisma.JsonNullableFilter<"AIReport"> - errorCode?: Prisma.StringNullableFilter<"AIReport"> | string | null - errorMessage?: Prisma.StringNullableFilter<"AIReport"> | string | null - createdAt?: Prisma.DateTimeFilter<"AIReport"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"AIReport"> | Date | string - proposal?: Prisma.XOR -}, "id"> - -export type AIReportOrderByWithAggregationInput = { - id?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - provider?: Prisma.SortOrder - model?: Prisma.SortOrder - status?: Prisma.SortOrder - summary?: Prisma.SortOrderInput | Prisma.SortOrder - findings?: Prisma.SortOrderInput | Prisma.SortOrder - errorCode?: Prisma.SortOrderInput | Prisma.SortOrder - errorMessage?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.AIReportCountOrderByAggregateInput - _max?: Prisma.AIReportMaxOrderByAggregateInput - _min?: Prisma.AIReportMinOrderByAggregateInput -} - -export type AIReportScalarWhereWithAggregatesInput = { - AND?: Prisma.AIReportScalarWhereWithAggregatesInput | Prisma.AIReportScalarWhereWithAggregatesInput[] - OR?: Prisma.AIReportScalarWhereWithAggregatesInput[] - NOT?: Prisma.AIReportScalarWhereWithAggregatesInput | Prisma.AIReportScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"AIReport"> | string - proposalId?: Prisma.StringWithAggregatesFilter<"AIReport"> | string - provider?: Prisma.StringWithAggregatesFilter<"AIReport"> | string - model?: Prisma.StringWithAggregatesFilter<"AIReport"> | string - status?: Prisma.EnumAIReportStatusWithAggregatesFilter<"AIReport"> | $Enums.AIReportStatus - summary?: Prisma.StringNullableWithAggregatesFilter<"AIReport"> | string | null - findings?: Prisma.JsonNullableWithAggregatesFilter<"AIReport"> - errorCode?: Prisma.StringNullableWithAggregatesFilter<"AIReport"> | string | null - errorMessage?: Prisma.StringNullableWithAggregatesFilter<"AIReport"> | string | null - createdAt?: Prisma.DateTimeWithAggregatesFilter<"AIReport"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"AIReport"> | Date | string -} - -export type AIReportCreateInput = { - id?: string - provider: string - model: string - status?: $Enums.AIReportStatus - summary?: string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: string | null - errorMessage?: string | null - createdAt?: Date | string - updatedAt?: Date | string - proposal: Prisma.ProposalCreateNestedOneWithoutAiReportsInput -} - -export type AIReportUncheckedCreateInput = { - id?: string - proposalId: string - provider: string - model: string - status?: $Enums.AIReportStatus - summary?: string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: string | null - errorMessage?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AIReportUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - provider?: Prisma.StringFieldUpdateOperationsInput | string - model?: Prisma.StringFieldUpdateOperationsInput | string - status?: Prisma.EnumAIReportStatusFieldUpdateOperationsInput | $Enums.AIReportStatus - summary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - errorMessage?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - proposal?: Prisma.ProposalUpdateOneRequiredWithoutAiReportsNestedInput -} - -export type AIReportUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalId?: Prisma.StringFieldUpdateOperationsInput | string - provider?: Prisma.StringFieldUpdateOperationsInput | string - model?: Prisma.StringFieldUpdateOperationsInput | string - status?: Prisma.EnumAIReportStatusFieldUpdateOperationsInput | $Enums.AIReportStatus - summary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - errorMessage?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AIReportCreateManyInput = { - id?: string - proposalId: string - provider: string - model: string - status?: $Enums.AIReportStatus - summary?: string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: string | null - errorMessage?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AIReportUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - provider?: Prisma.StringFieldUpdateOperationsInput | string - model?: Prisma.StringFieldUpdateOperationsInput | string - status?: Prisma.EnumAIReportStatusFieldUpdateOperationsInput | $Enums.AIReportStatus - summary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - errorMessage?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AIReportUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalId?: Prisma.StringFieldUpdateOperationsInput | string - provider?: Prisma.StringFieldUpdateOperationsInput | string - model?: Prisma.StringFieldUpdateOperationsInput | string - status?: Prisma.EnumAIReportStatusFieldUpdateOperationsInput | $Enums.AIReportStatus - summary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - errorMessage?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AIReportListRelationFilter = { - every?: Prisma.AIReportWhereInput - some?: Prisma.AIReportWhereInput - none?: Prisma.AIReportWhereInput -} - -export type AIReportOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type AIReportCountOrderByAggregateInput = { - id?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - provider?: Prisma.SortOrder - model?: Prisma.SortOrder - status?: Prisma.SortOrder - summary?: Prisma.SortOrder - findings?: Prisma.SortOrder - errorCode?: Prisma.SortOrder - errorMessage?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type AIReportMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - provider?: Prisma.SortOrder - model?: Prisma.SortOrder - status?: Prisma.SortOrder - summary?: Prisma.SortOrder - errorCode?: Prisma.SortOrder - errorMessage?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type AIReportMinOrderByAggregateInput = { - id?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - provider?: Prisma.SortOrder - model?: Prisma.SortOrder - status?: Prisma.SortOrder - summary?: Prisma.SortOrder - errorCode?: Prisma.SortOrder - errorMessage?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type AIReportCreateNestedManyWithoutProposalInput = { - create?: Prisma.XOR | Prisma.AIReportCreateWithoutProposalInput[] | Prisma.AIReportUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.AIReportCreateOrConnectWithoutProposalInput | Prisma.AIReportCreateOrConnectWithoutProposalInput[] - createMany?: Prisma.AIReportCreateManyProposalInputEnvelope - connect?: Prisma.AIReportWhereUniqueInput | Prisma.AIReportWhereUniqueInput[] -} - -export type AIReportUncheckedCreateNestedManyWithoutProposalInput = { - create?: Prisma.XOR | Prisma.AIReportCreateWithoutProposalInput[] | Prisma.AIReportUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.AIReportCreateOrConnectWithoutProposalInput | Prisma.AIReportCreateOrConnectWithoutProposalInput[] - createMany?: Prisma.AIReportCreateManyProposalInputEnvelope - connect?: Prisma.AIReportWhereUniqueInput | Prisma.AIReportWhereUniqueInput[] -} - -export type AIReportUpdateManyWithoutProposalNestedInput = { - create?: Prisma.XOR | Prisma.AIReportCreateWithoutProposalInput[] | Prisma.AIReportUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.AIReportCreateOrConnectWithoutProposalInput | Prisma.AIReportCreateOrConnectWithoutProposalInput[] - upsert?: Prisma.AIReportUpsertWithWhereUniqueWithoutProposalInput | Prisma.AIReportUpsertWithWhereUniqueWithoutProposalInput[] - createMany?: Prisma.AIReportCreateManyProposalInputEnvelope - set?: Prisma.AIReportWhereUniqueInput | Prisma.AIReportWhereUniqueInput[] - disconnect?: Prisma.AIReportWhereUniqueInput | Prisma.AIReportWhereUniqueInput[] - delete?: Prisma.AIReportWhereUniqueInput | Prisma.AIReportWhereUniqueInput[] - connect?: Prisma.AIReportWhereUniqueInput | Prisma.AIReportWhereUniqueInput[] - update?: Prisma.AIReportUpdateWithWhereUniqueWithoutProposalInput | Prisma.AIReportUpdateWithWhereUniqueWithoutProposalInput[] - updateMany?: Prisma.AIReportUpdateManyWithWhereWithoutProposalInput | Prisma.AIReportUpdateManyWithWhereWithoutProposalInput[] - deleteMany?: Prisma.AIReportScalarWhereInput | Prisma.AIReportScalarWhereInput[] -} - -export type AIReportUncheckedUpdateManyWithoutProposalNestedInput = { - create?: Prisma.XOR | Prisma.AIReportCreateWithoutProposalInput[] | Prisma.AIReportUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.AIReportCreateOrConnectWithoutProposalInput | Prisma.AIReportCreateOrConnectWithoutProposalInput[] - upsert?: Prisma.AIReportUpsertWithWhereUniqueWithoutProposalInput | Prisma.AIReportUpsertWithWhereUniqueWithoutProposalInput[] - createMany?: Prisma.AIReportCreateManyProposalInputEnvelope - set?: Prisma.AIReportWhereUniqueInput | Prisma.AIReportWhereUniqueInput[] - disconnect?: Prisma.AIReportWhereUniqueInput | Prisma.AIReportWhereUniqueInput[] - delete?: Prisma.AIReportWhereUniqueInput | Prisma.AIReportWhereUniqueInput[] - connect?: Prisma.AIReportWhereUniqueInput | Prisma.AIReportWhereUniqueInput[] - update?: Prisma.AIReportUpdateWithWhereUniqueWithoutProposalInput | Prisma.AIReportUpdateWithWhereUniqueWithoutProposalInput[] - updateMany?: Prisma.AIReportUpdateManyWithWhereWithoutProposalInput | Prisma.AIReportUpdateManyWithWhereWithoutProposalInput[] - deleteMany?: Prisma.AIReportScalarWhereInput | Prisma.AIReportScalarWhereInput[] -} - -export type EnumAIReportStatusFieldUpdateOperationsInput = { - set?: $Enums.AIReportStatus -} - -export type AIReportCreateWithoutProposalInput = { - id?: string - provider: string - model: string - status?: $Enums.AIReportStatus - summary?: string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: string | null - errorMessage?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AIReportUncheckedCreateWithoutProposalInput = { - id?: string - provider: string - model: string - status?: $Enums.AIReportStatus - summary?: string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: string | null - errorMessage?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AIReportCreateOrConnectWithoutProposalInput = { - where: Prisma.AIReportWhereUniqueInput - create: Prisma.XOR -} - -export type AIReportCreateManyProposalInputEnvelope = { - data: Prisma.AIReportCreateManyProposalInput | Prisma.AIReportCreateManyProposalInput[] - skipDuplicates?: boolean -} - -export type AIReportUpsertWithWhereUniqueWithoutProposalInput = { - where: Prisma.AIReportWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type AIReportUpdateWithWhereUniqueWithoutProposalInput = { - where: Prisma.AIReportWhereUniqueInput - data: Prisma.XOR -} - -export type AIReportUpdateManyWithWhereWithoutProposalInput = { - where: Prisma.AIReportScalarWhereInput - data: Prisma.XOR -} - -export type AIReportScalarWhereInput = { - AND?: Prisma.AIReportScalarWhereInput | Prisma.AIReportScalarWhereInput[] - OR?: Prisma.AIReportScalarWhereInput[] - NOT?: Prisma.AIReportScalarWhereInput | Prisma.AIReportScalarWhereInput[] - id?: Prisma.StringFilter<"AIReport"> | string - proposalId?: Prisma.StringFilter<"AIReport"> | string - provider?: Prisma.StringFilter<"AIReport"> | string - model?: Prisma.StringFilter<"AIReport"> | string - status?: Prisma.EnumAIReportStatusFilter<"AIReport"> | $Enums.AIReportStatus - summary?: Prisma.StringNullableFilter<"AIReport"> | string | null - findings?: Prisma.JsonNullableFilter<"AIReport"> - errorCode?: Prisma.StringNullableFilter<"AIReport"> | string | null - errorMessage?: Prisma.StringNullableFilter<"AIReport"> | string | null - createdAt?: Prisma.DateTimeFilter<"AIReport"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"AIReport"> | Date | string -} - -export type AIReportCreateManyProposalInput = { - id?: string - provider: string - model: string - status?: $Enums.AIReportStatus - summary?: string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: string | null - errorMessage?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AIReportUpdateWithoutProposalInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - provider?: Prisma.StringFieldUpdateOperationsInput | string - model?: Prisma.StringFieldUpdateOperationsInput | string - status?: Prisma.EnumAIReportStatusFieldUpdateOperationsInput | $Enums.AIReportStatus - summary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - errorMessage?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AIReportUncheckedUpdateWithoutProposalInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - provider?: Prisma.StringFieldUpdateOperationsInput | string - model?: Prisma.StringFieldUpdateOperationsInput | string - status?: Prisma.EnumAIReportStatusFieldUpdateOperationsInput | $Enums.AIReportStatus - summary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - errorMessage?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AIReportUncheckedUpdateManyWithoutProposalInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - provider?: Prisma.StringFieldUpdateOperationsInput | string - model?: Prisma.StringFieldUpdateOperationsInput | string - status?: Prisma.EnumAIReportStatusFieldUpdateOperationsInput | $Enums.AIReportStatus - summary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - findings?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - errorCode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - errorMessage?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - - -export type AIReportSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - proposalId?: boolean - provider?: boolean - model?: boolean - status?: boolean - summary?: boolean - findings?: boolean - errorCode?: boolean - errorMessage?: boolean - createdAt?: boolean - updatedAt?: boolean - proposal?: boolean | Prisma.ProposalDefaultArgs -}, ExtArgs["result"]["aIReport"]> - -export type AIReportSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - proposalId?: boolean - provider?: boolean - model?: boolean - status?: boolean - summary?: boolean - findings?: boolean - errorCode?: boolean - errorMessage?: boolean - createdAt?: boolean - updatedAt?: boolean - proposal?: boolean | Prisma.ProposalDefaultArgs -}, ExtArgs["result"]["aIReport"]> - -export type AIReportSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - proposalId?: boolean - provider?: boolean - model?: boolean - status?: boolean - summary?: boolean - findings?: boolean - errorCode?: boolean - errorMessage?: boolean - createdAt?: boolean - updatedAt?: boolean - proposal?: boolean | Prisma.ProposalDefaultArgs -}, ExtArgs["result"]["aIReport"]> - -export type AIReportSelectScalar = { - id?: boolean - proposalId?: boolean - provider?: boolean - model?: boolean - status?: boolean - summary?: boolean - findings?: boolean - errorCode?: boolean - errorMessage?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type AIReportOmit = runtime.Types.Extensions.GetOmit<"id" | "proposalId" | "provider" | "model" | "status" | "summary" | "findings" | "errorCode" | "errorMessage" | "createdAt" | "updatedAt", ExtArgs["result"]["aIReport"]> -export type AIReportInclude = { - proposal?: boolean | Prisma.ProposalDefaultArgs -} -export type AIReportIncludeCreateManyAndReturn = { - proposal?: boolean | Prisma.ProposalDefaultArgs -} -export type AIReportIncludeUpdateManyAndReturn = { - proposal?: boolean | Prisma.ProposalDefaultArgs -} - -export type $AIReportPayload = { - name: "AIReport" - objects: { - proposal: Prisma.$ProposalPayload - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - proposalId: string - provider: string - model: string - status: $Enums.AIReportStatus - summary: string | null - findings: runtime.JsonValue | null - errorCode: string | null - errorMessage: string | null - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["aIReport"]> - composites: {} -} - -export type AIReportGetPayload = runtime.Types.Result.GetResult - -export type AIReportCountArgs = - Omit & { - select?: AIReportCountAggregateInputType | true - } - -export interface AIReportDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['AIReport'], meta: { name: 'AIReport' } } - /** - * Find zero or one AIReport that matches the filter. - * @param {AIReportFindUniqueArgs} args - Arguments to find a AIReport - * @example - * // Get one AIReport - * const aIReport = await prisma.aIReport.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__AIReportClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one AIReport that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {AIReportFindUniqueOrThrowArgs} args - Arguments to find a AIReport - * @example - * // Get one AIReport - * const aIReport = await prisma.aIReport.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__AIReportClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first AIReport 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 {AIReportFindFirstArgs} args - Arguments to find a AIReport - * @example - * // Get one AIReport - * const aIReport = await prisma.aIReport.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__AIReportClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first AIReport 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 {AIReportFindFirstOrThrowArgs} args - Arguments to find a AIReport - * @example - * // Get one AIReport - * const aIReport = await prisma.aIReport.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__AIReportClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more AIReports 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 {AIReportFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all AIReports - * const aIReports = await prisma.aIReport.findMany() - * - * // Get first 10 AIReports - * const aIReports = await prisma.aIReport.findMany({ take: 10 }) - * - * // Only select the `id` - * const aIReportWithIdOnly = await prisma.aIReport.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a AIReport. - * @param {AIReportCreateArgs} args - Arguments to create a AIReport. - * @example - * // Create one AIReport - * const AIReport = await prisma.aIReport.create({ - * data: { - * // ... data to create a AIReport - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__AIReportClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many AIReports. - * @param {AIReportCreateManyArgs} args - Arguments to create many AIReports. - * @example - * // Create many AIReports - * const aIReport = await prisma.aIReport.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many AIReports and returns the data saved in the database. - * @param {AIReportCreateManyAndReturnArgs} args - Arguments to create many AIReports. - * @example - * // Create many AIReports - * const aIReport = await prisma.aIReport.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many AIReports and only return the `id` - * const aIReportWithIdOnly = await prisma.aIReport.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 AIReport. - * @param {AIReportDeleteArgs} args - Arguments to delete one AIReport. - * @example - * // Delete one AIReport - * const AIReport = await prisma.aIReport.delete({ - * where: { - * // ... filter to delete one AIReport - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__AIReportClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one AIReport. - * @param {AIReportUpdateArgs} args - Arguments to update one AIReport. - * @example - * // Update one AIReport - * const aIReport = await prisma.aIReport.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__AIReportClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more AIReports. - * @param {AIReportDeleteManyArgs} args - Arguments to filter AIReports to delete. - * @example - * // Delete a few AIReports - * const { count } = await prisma.aIReport.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more AIReports. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {AIReportUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many AIReports - * const aIReport = await prisma.aIReport.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more AIReports and returns the data updated in the database. - * @param {AIReportUpdateManyAndReturnArgs} args - Arguments to update many AIReports. - * @example - * // Update many AIReports - * const aIReport = await prisma.aIReport.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more AIReports and only return the `id` - * const aIReportWithIdOnly = await prisma.aIReport.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 AIReport. - * @param {AIReportUpsertArgs} args - Arguments to update or create a AIReport. - * @example - * // Update or create a AIReport - * const aIReport = await prisma.aIReport.upsert({ - * create: { - * // ... data to create a AIReport - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the AIReport we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__AIReportClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of AIReports. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {AIReportCountArgs} args - Arguments to filter AIReports to count. - * @example - * // Count the number of AIReports - * const count = await prisma.aIReport.count({ - * where: { - * // ... the filter for the AIReports 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 AIReport. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {AIReportAggregateArgs} 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 AIReport. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {AIReportGroupByArgs} 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 AIReportGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: AIReportGroupByArgs['orderBy'] } - : { orderBy?: AIReportGroupByArgs['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 ? GetAIReportGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the AIReport model - */ -readonly fields: AIReportFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for AIReport. - * 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__AIReportClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - proposal = {}>(args?: Prisma.Subset>): Prisma.Prisma__ProposalClient, 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 AIReport model - */ -export interface AIReportFieldRefs { - readonly id: Prisma.FieldRef<"AIReport", 'String'> - readonly proposalId: Prisma.FieldRef<"AIReport", 'String'> - readonly provider: Prisma.FieldRef<"AIReport", 'String'> - readonly model: Prisma.FieldRef<"AIReport", 'String'> - readonly status: Prisma.FieldRef<"AIReport", 'AIReportStatus'> - readonly summary: Prisma.FieldRef<"AIReport", 'String'> - readonly findings: Prisma.FieldRef<"AIReport", 'Json'> - readonly errorCode: Prisma.FieldRef<"AIReport", 'String'> - readonly errorMessage: Prisma.FieldRef<"AIReport", 'String'> - readonly createdAt: Prisma.FieldRef<"AIReport", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"AIReport", 'DateTime'> -} - - -// Custom InputTypes -/** - * AIReport findUnique - */ -export type AIReportFindUniqueArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null - /** - * Filter, which AIReport to fetch. - */ - where: Prisma.AIReportWhereUniqueInput -} - -/** - * AIReport findUniqueOrThrow - */ -export type AIReportFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null - /** - * Filter, which AIReport to fetch. - */ - where: Prisma.AIReportWhereUniqueInput -} - -/** - * AIReport findFirst - */ -export type AIReportFindFirstArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null - /** - * Filter, which AIReport to fetch. - */ - where?: Prisma.AIReportWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of AIReports to fetch. - */ - orderBy?: Prisma.AIReportOrderByWithRelationInput | Prisma.AIReportOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for AIReports. - */ - cursor?: Prisma.AIReportWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` AIReports 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` AIReports. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of AIReports. - */ - distinct?: Prisma.AIReportScalarFieldEnum | Prisma.AIReportScalarFieldEnum[] -} - -/** - * AIReport findFirstOrThrow - */ -export type AIReportFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null - /** - * Filter, which AIReport to fetch. - */ - where?: Prisma.AIReportWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of AIReports to fetch. - */ - orderBy?: Prisma.AIReportOrderByWithRelationInput | Prisma.AIReportOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for AIReports. - */ - cursor?: Prisma.AIReportWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` AIReports 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` AIReports. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of AIReports. - */ - distinct?: Prisma.AIReportScalarFieldEnum | Prisma.AIReportScalarFieldEnum[] -} - -/** - * AIReport findMany - */ -export type AIReportFindManyArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null - /** - * Filter, which AIReports to fetch. - */ - where?: Prisma.AIReportWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of AIReports to fetch. - */ - orderBy?: Prisma.AIReportOrderByWithRelationInput | Prisma.AIReportOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing AIReports. - */ - cursor?: Prisma.AIReportWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` AIReports 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` AIReports. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of AIReports. - */ - distinct?: Prisma.AIReportScalarFieldEnum | Prisma.AIReportScalarFieldEnum[] -} - -/** - * AIReport create - */ -export type AIReportCreateArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null - /** - * The data needed to create a AIReport. - */ - data: Prisma.XOR -} - -/** - * AIReport createMany - */ -export type AIReportCreateManyArgs = { - /** - * The data used to create many AIReports. - */ - data: Prisma.AIReportCreateManyInput | Prisma.AIReportCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * AIReport createManyAndReturn - */ -export type AIReportCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelectCreateManyAndReturn | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * The data used to create many AIReports. - */ - data: Prisma.AIReportCreateManyInput | Prisma.AIReportCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportIncludeCreateManyAndReturn | null -} - -/** - * AIReport update - */ -export type AIReportUpdateArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null - /** - * The data needed to update a AIReport. - */ - data: Prisma.XOR - /** - * Choose, which AIReport to update. - */ - where: Prisma.AIReportWhereUniqueInput -} - -/** - * AIReport updateMany - */ -export type AIReportUpdateManyArgs = { - /** - * The data used to update AIReports. - */ - data: Prisma.XOR - /** - * Filter which AIReports to update - */ - where?: Prisma.AIReportWhereInput - /** - * Limit how many AIReports to update. - */ - limit?: number -} - -/** - * AIReport updateManyAndReturn - */ -export type AIReportUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * The data used to update AIReports. - */ - data: Prisma.XOR - /** - * Filter which AIReports to update - */ - where?: Prisma.AIReportWhereInput - /** - * Limit how many AIReports to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportIncludeUpdateManyAndReturn | null -} - -/** - * AIReport upsert - */ -export type AIReportUpsertArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null - /** - * The filter to search for the AIReport to update in case it exists. - */ - where: Prisma.AIReportWhereUniqueInput - /** - * In case the AIReport found by the `where` argument doesn't exist, create a new AIReport with this data. - */ - create: Prisma.XOR - /** - * In case the AIReport was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * AIReport delete - */ -export type AIReportDeleteArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null - /** - * Filter which AIReport to delete. - */ - where: Prisma.AIReportWhereUniqueInput -} - -/** - * AIReport deleteMany - */ -export type AIReportDeleteManyArgs = { - /** - * Filter which AIReports to delete - */ - where?: Prisma.AIReportWhereInput - /** - * Limit how many AIReports to delete. - */ - limit?: number -} - -/** - * AIReport without action - */ -export type AIReportDefaultArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null -} diff --git a/apps/api/src/generated/prisma/models/AppVote.ts b/apps/api/src/generated/prisma/models/AppVote.ts deleted file mode 100644 index 8e4da2c..0000000 --- a/apps/api/src/generated/prisma/models/AppVote.ts +++ /dev/null @@ -1,1807 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `AppVote` 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 AppVote - * - */ -export type AppVoteModel = runtime.Types.Result.DefaultSelection - -export type AggregateAppVote = { - _count: AppVoteCountAggregateOutputType | null - _avg: AppVoteAvgAggregateOutputType | null - _sum: AppVoteSumAggregateOutputType | null - _min: AppVoteMinAggregateOutputType | null - _max: AppVoteMaxAggregateOutputType | null -} - -export type AppVoteAvgAggregateOutputType = { - reputationScoreAtVote: runtime.Decimal | null -} - -export type AppVoteSumAggregateOutputType = { - reputationScoreAtVote: runtime.Decimal | null -} - -export type AppVoteMinAggregateOutputType = { - id: string | null - proposalId: string | null - voterId: string | null - choice: $Enums.VoteChoice | null - reputationScoreAtVote: runtime.Decimal | null - reputationSnapshotId: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type AppVoteMaxAggregateOutputType = { - id: string | null - proposalId: string | null - voterId: string | null - choice: $Enums.VoteChoice | null - reputationScoreAtVote: runtime.Decimal | null - reputationSnapshotId: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type AppVoteCountAggregateOutputType = { - id: number - proposalId: number - voterId: number - choice: number - reputationScoreAtVote: number - reputationSnapshotId: number - createdAt: number - updatedAt: number - _all: number -} - - -export type AppVoteAvgAggregateInputType = { - reputationScoreAtVote?: true -} - -export type AppVoteSumAggregateInputType = { - reputationScoreAtVote?: true -} - -export type AppVoteMinAggregateInputType = { - id?: true - proposalId?: true - voterId?: true - choice?: true - reputationScoreAtVote?: true - reputationSnapshotId?: true - createdAt?: true - updatedAt?: true -} - -export type AppVoteMaxAggregateInputType = { - id?: true - proposalId?: true - voterId?: true - choice?: true - reputationScoreAtVote?: true - reputationSnapshotId?: true - createdAt?: true - updatedAt?: true -} - -export type AppVoteCountAggregateInputType = { - id?: true - proposalId?: true - voterId?: true - choice?: true - reputationScoreAtVote?: true - reputationSnapshotId?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type AppVoteAggregateArgs = { - /** - * Filter which AppVote to aggregate. - */ - where?: Prisma.AppVoteWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of AppVotes to fetch. - */ - orderBy?: Prisma.AppVoteOrderByWithRelationInput | Prisma.AppVoteOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.AppVoteWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` AppVotes 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` AppVotes. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned AppVotes - **/ - _count?: true | AppVoteCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to average - **/ - _avg?: AppVoteAvgAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to sum - **/ - _sum?: AppVoteSumAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: AppVoteMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: AppVoteMaxAggregateInputType -} - -export type GetAppVoteAggregateType = { - [P in keyof T & keyof AggregateAppVote]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type AppVoteGroupByArgs = { - where?: Prisma.AppVoteWhereInput - orderBy?: Prisma.AppVoteOrderByWithAggregationInput | Prisma.AppVoteOrderByWithAggregationInput[] - by: Prisma.AppVoteScalarFieldEnum[] | Prisma.AppVoteScalarFieldEnum - having?: Prisma.AppVoteScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: AppVoteCountAggregateInputType | true - _avg?: AppVoteAvgAggregateInputType - _sum?: AppVoteSumAggregateInputType - _min?: AppVoteMinAggregateInputType - _max?: AppVoteMaxAggregateInputType -} - -export type AppVoteGroupByOutputType = { - id: string - proposalId: string - voterId: string - choice: $Enums.VoteChoice - reputationScoreAtVote: runtime.Decimal | null - reputationSnapshotId: string | null - createdAt: Date - updatedAt: Date - _count: AppVoteCountAggregateOutputType | null - _avg: AppVoteAvgAggregateOutputType | null - _sum: AppVoteSumAggregateOutputType | null - _min: AppVoteMinAggregateOutputType | null - _max: AppVoteMaxAggregateOutputType | null -} - -export type GetAppVoteGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof AppVoteGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type AppVoteWhereInput = { - AND?: Prisma.AppVoteWhereInput | Prisma.AppVoteWhereInput[] - OR?: Prisma.AppVoteWhereInput[] - NOT?: Prisma.AppVoteWhereInput | Prisma.AppVoteWhereInput[] - id?: Prisma.StringFilter<"AppVote"> | string - proposalId?: Prisma.StringFilter<"AppVote"> | string - voterId?: Prisma.StringFilter<"AppVote"> | string - choice?: Prisma.EnumVoteChoiceFilter<"AppVote"> | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.DecimalNullableFilter<"AppVote"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: Prisma.StringNullableFilter<"AppVote"> | string | null - createdAt?: Prisma.DateTimeFilter<"AppVote"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"AppVote"> | Date | string - proposal?: Prisma.XOR - voter?: Prisma.XOR - reputationSnapshot?: Prisma.XOR | null -} - -export type AppVoteOrderByWithRelationInput = { - id?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - voterId?: Prisma.SortOrder - choice?: Prisma.SortOrder - reputationScoreAtVote?: Prisma.SortOrderInput | Prisma.SortOrder - reputationSnapshotId?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - proposal?: Prisma.ProposalOrderByWithRelationInput - voter?: Prisma.UserOrderByWithRelationInput - reputationSnapshot?: Prisma.UserReputationSnapshotOrderByWithRelationInput -} - -export type AppVoteWhereUniqueInput = Prisma.AtLeast<{ - id?: string - proposalId_voterId?: Prisma.AppVoteProposalIdVoterIdCompoundUniqueInput - AND?: Prisma.AppVoteWhereInput | Prisma.AppVoteWhereInput[] - OR?: Prisma.AppVoteWhereInput[] - NOT?: Prisma.AppVoteWhereInput | Prisma.AppVoteWhereInput[] - proposalId?: Prisma.StringFilter<"AppVote"> | string - voterId?: Prisma.StringFilter<"AppVote"> | string - choice?: Prisma.EnumVoteChoiceFilter<"AppVote"> | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.DecimalNullableFilter<"AppVote"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: Prisma.StringNullableFilter<"AppVote"> | string | null - createdAt?: Prisma.DateTimeFilter<"AppVote"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"AppVote"> | Date | string - proposal?: Prisma.XOR - voter?: Prisma.XOR - reputationSnapshot?: Prisma.XOR | null -}, "id" | "proposalId_voterId"> - -export type AppVoteOrderByWithAggregationInput = { - id?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - voterId?: Prisma.SortOrder - choice?: Prisma.SortOrder - reputationScoreAtVote?: Prisma.SortOrderInput | Prisma.SortOrder - reputationSnapshotId?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.AppVoteCountOrderByAggregateInput - _avg?: Prisma.AppVoteAvgOrderByAggregateInput - _max?: Prisma.AppVoteMaxOrderByAggregateInput - _min?: Prisma.AppVoteMinOrderByAggregateInput - _sum?: Prisma.AppVoteSumOrderByAggregateInput -} - -export type AppVoteScalarWhereWithAggregatesInput = { - AND?: Prisma.AppVoteScalarWhereWithAggregatesInput | Prisma.AppVoteScalarWhereWithAggregatesInput[] - OR?: Prisma.AppVoteScalarWhereWithAggregatesInput[] - NOT?: Prisma.AppVoteScalarWhereWithAggregatesInput | Prisma.AppVoteScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"AppVote"> | string - proposalId?: Prisma.StringWithAggregatesFilter<"AppVote"> | string - voterId?: Prisma.StringWithAggregatesFilter<"AppVote"> | string - choice?: Prisma.EnumVoteChoiceWithAggregatesFilter<"AppVote"> | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.DecimalNullableWithAggregatesFilter<"AppVote"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: Prisma.StringNullableWithAggregatesFilter<"AppVote"> | string | null - createdAt?: Prisma.DateTimeWithAggregatesFilter<"AppVote"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"AppVote"> | Date | string -} - -export type AppVoteCreateInput = { - id?: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Date | string - updatedAt?: Date | string - proposal: Prisma.ProposalCreateNestedOneWithoutVotesInput - voter: Prisma.UserCreateNestedOneWithoutVotesInput - reputationSnapshot?: Prisma.UserReputationSnapshotCreateNestedOneWithoutAppVotesInput -} - -export type AppVoteUncheckedCreateInput = { - id?: string - proposalId: string - voterId: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AppVoteUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - proposal?: Prisma.ProposalUpdateOneRequiredWithoutVotesNestedInput - voter?: Prisma.UserUpdateOneRequiredWithoutVotesNestedInput - reputationSnapshot?: Prisma.UserReputationSnapshotUpdateOneWithoutAppVotesNestedInput -} - -export type AppVoteUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalId?: Prisma.StringFieldUpdateOperationsInput | string - voterId?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AppVoteCreateManyInput = { - id?: string - proposalId: string - voterId: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AppVoteUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AppVoteUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalId?: Prisma.StringFieldUpdateOperationsInput | string - voterId?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AppVoteListRelationFilter = { - every?: Prisma.AppVoteWhereInput - some?: Prisma.AppVoteWhereInput - none?: Prisma.AppVoteWhereInput -} - -export type AppVoteOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type AppVoteProposalIdVoterIdCompoundUniqueInput = { - proposalId: string - voterId: string -} - -export type AppVoteCountOrderByAggregateInput = { - id?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - voterId?: Prisma.SortOrder - choice?: Prisma.SortOrder - reputationScoreAtVote?: Prisma.SortOrder - reputationSnapshotId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type AppVoteAvgOrderByAggregateInput = { - reputationScoreAtVote?: Prisma.SortOrder -} - -export type AppVoteMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - voterId?: Prisma.SortOrder - choice?: Prisma.SortOrder - reputationScoreAtVote?: Prisma.SortOrder - reputationSnapshotId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type AppVoteMinOrderByAggregateInput = { - id?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - voterId?: Prisma.SortOrder - choice?: Prisma.SortOrder - reputationScoreAtVote?: Prisma.SortOrder - reputationSnapshotId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type AppVoteSumOrderByAggregateInput = { - reputationScoreAtVote?: Prisma.SortOrder -} - -export type AppVoteCreateNestedManyWithoutVoterInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutVoterInput[] | Prisma.AppVoteUncheckedCreateWithoutVoterInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutVoterInput | Prisma.AppVoteCreateOrConnectWithoutVoterInput[] - createMany?: Prisma.AppVoteCreateManyVoterInputEnvelope - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] -} - -export type AppVoteUncheckedCreateNestedManyWithoutVoterInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutVoterInput[] | Prisma.AppVoteUncheckedCreateWithoutVoterInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutVoterInput | Prisma.AppVoteCreateOrConnectWithoutVoterInput[] - createMany?: Prisma.AppVoteCreateManyVoterInputEnvelope - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] -} - -export type AppVoteUpdateManyWithoutVoterNestedInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutVoterInput[] | Prisma.AppVoteUncheckedCreateWithoutVoterInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutVoterInput | Prisma.AppVoteCreateOrConnectWithoutVoterInput[] - upsert?: Prisma.AppVoteUpsertWithWhereUniqueWithoutVoterInput | Prisma.AppVoteUpsertWithWhereUniqueWithoutVoterInput[] - createMany?: Prisma.AppVoteCreateManyVoterInputEnvelope - set?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - disconnect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - delete?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - update?: Prisma.AppVoteUpdateWithWhereUniqueWithoutVoterInput | Prisma.AppVoteUpdateWithWhereUniqueWithoutVoterInput[] - updateMany?: Prisma.AppVoteUpdateManyWithWhereWithoutVoterInput | Prisma.AppVoteUpdateManyWithWhereWithoutVoterInput[] - deleteMany?: Prisma.AppVoteScalarWhereInput | Prisma.AppVoteScalarWhereInput[] -} - -export type AppVoteUncheckedUpdateManyWithoutVoterNestedInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutVoterInput[] | Prisma.AppVoteUncheckedCreateWithoutVoterInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutVoterInput | Prisma.AppVoteCreateOrConnectWithoutVoterInput[] - upsert?: Prisma.AppVoteUpsertWithWhereUniqueWithoutVoterInput | Prisma.AppVoteUpsertWithWhereUniqueWithoutVoterInput[] - createMany?: Prisma.AppVoteCreateManyVoterInputEnvelope - set?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - disconnect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - delete?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - update?: Prisma.AppVoteUpdateWithWhereUniqueWithoutVoterInput | Prisma.AppVoteUpdateWithWhereUniqueWithoutVoterInput[] - updateMany?: Prisma.AppVoteUpdateManyWithWhereWithoutVoterInput | Prisma.AppVoteUpdateManyWithWhereWithoutVoterInput[] - deleteMany?: Prisma.AppVoteScalarWhereInput | Prisma.AppVoteScalarWhereInput[] -} - -export type AppVoteCreateNestedManyWithoutProposalInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutProposalInput[] | Prisma.AppVoteUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutProposalInput | Prisma.AppVoteCreateOrConnectWithoutProposalInput[] - createMany?: Prisma.AppVoteCreateManyProposalInputEnvelope - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] -} - -export type AppVoteUncheckedCreateNestedManyWithoutProposalInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutProposalInput[] | Prisma.AppVoteUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutProposalInput | Prisma.AppVoteCreateOrConnectWithoutProposalInput[] - createMany?: Prisma.AppVoteCreateManyProposalInputEnvelope - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] -} - -export type AppVoteUpdateManyWithoutProposalNestedInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutProposalInput[] | Prisma.AppVoteUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutProposalInput | Prisma.AppVoteCreateOrConnectWithoutProposalInput[] - upsert?: Prisma.AppVoteUpsertWithWhereUniqueWithoutProposalInput | Prisma.AppVoteUpsertWithWhereUniqueWithoutProposalInput[] - createMany?: Prisma.AppVoteCreateManyProposalInputEnvelope - set?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - disconnect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - delete?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - update?: Prisma.AppVoteUpdateWithWhereUniqueWithoutProposalInput | Prisma.AppVoteUpdateWithWhereUniqueWithoutProposalInput[] - updateMany?: Prisma.AppVoteUpdateManyWithWhereWithoutProposalInput | Prisma.AppVoteUpdateManyWithWhereWithoutProposalInput[] - deleteMany?: Prisma.AppVoteScalarWhereInput | Prisma.AppVoteScalarWhereInput[] -} - -export type AppVoteUncheckedUpdateManyWithoutProposalNestedInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutProposalInput[] | Prisma.AppVoteUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutProposalInput | Prisma.AppVoteCreateOrConnectWithoutProposalInput[] - upsert?: Prisma.AppVoteUpsertWithWhereUniqueWithoutProposalInput | Prisma.AppVoteUpsertWithWhereUniqueWithoutProposalInput[] - createMany?: Prisma.AppVoteCreateManyProposalInputEnvelope - set?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - disconnect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - delete?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - update?: Prisma.AppVoteUpdateWithWhereUniqueWithoutProposalInput | Prisma.AppVoteUpdateWithWhereUniqueWithoutProposalInput[] - updateMany?: Prisma.AppVoteUpdateManyWithWhereWithoutProposalInput | Prisma.AppVoteUpdateManyWithWhereWithoutProposalInput[] - deleteMany?: Prisma.AppVoteScalarWhereInput | Prisma.AppVoteScalarWhereInput[] -} - -export type EnumVoteChoiceFieldUpdateOperationsInput = { - set?: $Enums.VoteChoice -} - -export type NullableDecimalFieldUpdateOperationsInput = { - set?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - increment?: runtime.Decimal | runtime.DecimalJsLike | number | string - decrement?: runtime.Decimal | runtime.DecimalJsLike | number | string - multiply?: runtime.Decimal | runtime.DecimalJsLike | number | string - divide?: runtime.Decimal | runtime.DecimalJsLike | number | string -} - -export type AppVoteCreateNestedManyWithoutReputationSnapshotInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutReputationSnapshotInput[] | Prisma.AppVoteUncheckedCreateWithoutReputationSnapshotInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutReputationSnapshotInput | Prisma.AppVoteCreateOrConnectWithoutReputationSnapshotInput[] - createMany?: Prisma.AppVoteCreateManyReputationSnapshotInputEnvelope - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] -} - -export type AppVoteUncheckedCreateNestedManyWithoutReputationSnapshotInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutReputationSnapshotInput[] | Prisma.AppVoteUncheckedCreateWithoutReputationSnapshotInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutReputationSnapshotInput | Prisma.AppVoteCreateOrConnectWithoutReputationSnapshotInput[] - createMany?: Prisma.AppVoteCreateManyReputationSnapshotInputEnvelope - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] -} - -export type AppVoteUpdateManyWithoutReputationSnapshotNestedInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutReputationSnapshotInput[] | Prisma.AppVoteUncheckedCreateWithoutReputationSnapshotInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutReputationSnapshotInput | Prisma.AppVoteCreateOrConnectWithoutReputationSnapshotInput[] - upsert?: Prisma.AppVoteUpsertWithWhereUniqueWithoutReputationSnapshotInput | Prisma.AppVoteUpsertWithWhereUniqueWithoutReputationSnapshotInput[] - createMany?: Prisma.AppVoteCreateManyReputationSnapshotInputEnvelope - set?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - disconnect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - delete?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - update?: Prisma.AppVoteUpdateWithWhereUniqueWithoutReputationSnapshotInput | Prisma.AppVoteUpdateWithWhereUniqueWithoutReputationSnapshotInput[] - updateMany?: Prisma.AppVoteUpdateManyWithWhereWithoutReputationSnapshotInput | Prisma.AppVoteUpdateManyWithWhereWithoutReputationSnapshotInput[] - deleteMany?: Prisma.AppVoteScalarWhereInput | Prisma.AppVoteScalarWhereInput[] -} - -export type AppVoteUncheckedUpdateManyWithoutReputationSnapshotNestedInput = { - create?: Prisma.XOR | Prisma.AppVoteCreateWithoutReputationSnapshotInput[] | Prisma.AppVoteUncheckedCreateWithoutReputationSnapshotInput[] - connectOrCreate?: Prisma.AppVoteCreateOrConnectWithoutReputationSnapshotInput | Prisma.AppVoteCreateOrConnectWithoutReputationSnapshotInput[] - upsert?: Prisma.AppVoteUpsertWithWhereUniqueWithoutReputationSnapshotInput | Prisma.AppVoteUpsertWithWhereUniqueWithoutReputationSnapshotInput[] - createMany?: Prisma.AppVoteCreateManyReputationSnapshotInputEnvelope - set?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - disconnect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - delete?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - connect?: Prisma.AppVoteWhereUniqueInput | Prisma.AppVoteWhereUniqueInput[] - update?: Prisma.AppVoteUpdateWithWhereUniqueWithoutReputationSnapshotInput | Prisma.AppVoteUpdateWithWhereUniqueWithoutReputationSnapshotInput[] - updateMany?: Prisma.AppVoteUpdateManyWithWhereWithoutReputationSnapshotInput | Prisma.AppVoteUpdateManyWithWhereWithoutReputationSnapshotInput[] - deleteMany?: Prisma.AppVoteScalarWhereInput | Prisma.AppVoteScalarWhereInput[] -} - -export type AppVoteCreateWithoutVoterInput = { - id?: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Date | string - updatedAt?: Date | string - proposal: Prisma.ProposalCreateNestedOneWithoutVotesInput - reputationSnapshot?: Prisma.UserReputationSnapshotCreateNestedOneWithoutAppVotesInput -} - -export type AppVoteUncheckedCreateWithoutVoterInput = { - id?: string - proposalId: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AppVoteCreateOrConnectWithoutVoterInput = { - where: Prisma.AppVoteWhereUniqueInput - create: Prisma.XOR -} - -export type AppVoteCreateManyVoterInputEnvelope = { - data: Prisma.AppVoteCreateManyVoterInput | Prisma.AppVoteCreateManyVoterInput[] - skipDuplicates?: boolean -} - -export type AppVoteUpsertWithWhereUniqueWithoutVoterInput = { - where: Prisma.AppVoteWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type AppVoteUpdateWithWhereUniqueWithoutVoterInput = { - where: Prisma.AppVoteWhereUniqueInput - data: Prisma.XOR -} - -export type AppVoteUpdateManyWithWhereWithoutVoterInput = { - where: Prisma.AppVoteScalarWhereInput - data: Prisma.XOR -} - -export type AppVoteScalarWhereInput = { - AND?: Prisma.AppVoteScalarWhereInput | Prisma.AppVoteScalarWhereInput[] - OR?: Prisma.AppVoteScalarWhereInput[] - NOT?: Prisma.AppVoteScalarWhereInput | Prisma.AppVoteScalarWhereInput[] - id?: Prisma.StringFilter<"AppVote"> | string - proposalId?: Prisma.StringFilter<"AppVote"> | string - voterId?: Prisma.StringFilter<"AppVote"> | string - choice?: Prisma.EnumVoteChoiceFilter<"AppVote"> | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.DecimalNullableFilter<"AppVote"> | runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: Prisma.StringNullableFilter<"AppVote"> | string | null - createdAt?: Prisma.DateTimeFilter<"AppVote"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"AppVote"> | Date | string -} - -export type AppVoteCreateWithoutProposalInput = { - id?: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Date | string - updatedAt?: Date | string - voter: Prisma.UserCreateNestedOneWithoutVotesInput - reputationSnapshot?: Prisma.UserReputationSnapshotCreateNestedOneWithoutAppVotesInput -} - -export type AppVoteUncheckedCreateWithoutProposalInput = { - id?: string - voterId: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AppVoteCreateOrConnectWithoutProposalInput = { - where: Prisma.AppVoteWhereUniqueInput - create: Prisma.XOR -} - -export type AppVoteCreateManyProposalInputEnvelope = { - data: Prisma.AppVoteCreateManyProposalInput | Prisma.AppVoteCreateManyProposalInput[] - skipDuplicates?: boolean -} - -export type AppVoteUpsertWithWhereUniqueWithoutProposalInput = { - where: Prisma.AppVoteWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type AppVoteUpdateWithWhereUniqueWithoutProposalInput = { - where: Prisma.AppVoteWhereUniqueInput - data: Prisma.XOR -} - -export type AppVoteUpdateManyWithWhereWithoutProposalInput = { - where: Prisma.AppVoteScalarWhereInput - data: Prisma.XOR -} - -export type AppVoteCreateWithoutReputationSnapshotInput = { - id?: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Date | string - updatedAt?: Date | string - proposal: Prisma.ProposalCreateNestedOneWithoutVotesInput - voter: Prisma.UserCreateNestedOneWithoutVotesInput -} - -export type AppVoteUncheckedCreateWithoutReputationSnapshotInput = { - id?: string - proposalId: string - voterId: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AppVoteCreateOrConnectWithoutReputationSnapshotInput = { - where: Prisma.AppVoteWhereUniqueInput - create: Prisma.XOR -} - -export type AppVoteCreateManyReputationSnapshotInputEnvelope = { - data: Prisma.AppVoteCreateManyReputationSnapshotInput | Prisma.AppVoteCreateManyReputationSnapshotInput[] - skipDuplicates?: boolean -} - -export type AppVoteUpsertWithWhereUniqueWithoutReputationSnapshotInput = { - where: Prisma.AppVoteWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type AppVoteUpdateWithWhereUniqueWithoutReputationSnapshotInput = { - where: Prisma.AppVoteWhereUniqueInput - data: Prisma.XOR -} - -export type AppVoteUpdateManyWithWhereWithoutReputationSnapshotInput = { - where: Prisma.AppVoteScalarWhereInput - data: Prisma.XOR -} - -export type AppVoteCreateManyVoterInput = { - id?: string - proposalId: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AppVoteUpdateWithoutVoterInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - proposal?: Prisma.ProposalUpdateOneRequiredWithoutVotesNestedInput - reputationSnapshot?: Prisma.UserReputationSnapshotUpdateOneWithoutAppVotesNestedInput -} - -export type AppVoteUncheckedUpdateWithoutVoterInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalId?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AppVoteUncheckedUpdateManyWithoutVoterInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalId?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AppVoteCreateManyProposalInput = { - id?: string - voterId: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AppVoteUpdateWithoutProposalInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - voter?: Prisma.UserUpdateOneRequiredWithoutVotesNestedInput - reputationSnapshot?: Prisma.UserReputationSnapshotUpdateOneWithoutAppVotesNestedInput -} - -export type AppVoteUncheckedUpdateWithoutProposalInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - voterId?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AppVoteUncheckedUpdateManyWithoutProposalInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - voterId?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - reputationSnapshotId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AppVoteCreateManyReputationSnapshotInput = { - id?: string - proposalId: string - voterId: string - choice: $Enums.VoteChoice - reputationScoreAtVote?: runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type AppVoteUpdateWithoutReputationSnapshotInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - proposal?: Prisma.ProposalUpdateOneRequiredWithoutVotesNestedInput - voter?: Prisma.UserUpdateOneRequiredWithoutVotesNestedInput -} - -export type AppVoteUncheckedUpdateWithoutReputationSnapshotInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalId?: Prisma.StringFieldUpdateOperationsInput | string - voterId?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type AppVoteUncheckedUpdateManyWithoutReputationSnapshotInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalId?: Prisma.StringFieldUpdateOperationsInput | string - voterId?: Prisma.StringFieldUpdateOperationsInput | string - choice?: Prisma.EnumVoteChoiceFieldUpdateOperationsInput | $Enums.VoteChoice - reputationScoreAtVote?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - - -export type AppVoteSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - proposalId?: boolean - voterId?: boolean - choice?: boolean - reputationScoreAtVote?: boolean - reputationSnapshotId?: boolean - createdAt?: boolean - updatedAt?: boolean - proposal?: boolean | Prisma.ProposalDefaultArgs - voter?: boolean | Prisma.UserDefaultArgs - reputationSnapshot?: boolean | Prisma.AppVote$reputationSnapshotArgs -}, ExtArgs["result"]["appVote"]> - -export type AppVoteSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - proposalId?: boolean - voterId?: boolean - choice?: boolean - reputationScoreAtVote?: boolean - reputationSnapshotId?: boolean - createdAt?: boolean - updatedAt?: boolean - proposal?: boolean | Prisma.ProposalDefaultArgs - voter?: boolean | Prisma.UserDefaultArgs - reputationSnapshot?: boolean | Prisma.AppVote$reputationSnapshotArgs -}, ExtArgs["result"]["appVote"]> - -export type AppVoteSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - proposalId?: boolean - voterId?: boolean - choice?: boolean - reputationScoreAtVote?: boolean - reputationSnapshotId?: boolean - createdAt?: boolean - updatedAt?: boolean - proposal?: boolean | Prisma.ProposalDefaultArgs - voter?: boolean | Prisma.UserDefaultArgs - reputationSnapshot?: boolean | Prisma.AppVote$reputationSnapshotArgs -}, ExtArgs["result"]["appVote"]> - -export type AppVoteSelectScalar = { - id?: boolean - proposalId?: boolean - voterId?: boolean - choice?: boolean - reputationScoreAtVote?: boolean - reputationSnapshotId?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type AppVoteOmit = runtime.Types.Extensions.GetOmit<"id" | "proposalId" | "voterId" | "choice" | "reputationScoreAtVote" | "reputationSnapshotId" | "createdAt" | "updatedAt", ExtArgs["result"]["appVote"]> -export type AppVoteInclude = { - proposal?: boolean | Prisma.ProposalDefaultArgs - voter?: boolean | Prisma.UserDefaultArgs - reputationSnapshot?: boolean | Prisma.AppVote$reputationSnapshotArgs -} -export type AppVoteIncludeCreateManyAndReturn = { - proposal?: boolean | Prisma.ProposalDefaultArgs - voter?: boolean | Prisma.UserDefaultArgs - reputationSnapshot?: boolean | Prisma.AppVote$reputationSnapshotArgs -} -export type AppVoteIncludeUpdateManyAndReturn = { - proposal?: boolean | Prisma.ProposalDefaultArgs - voter?: boolean | Prisma.UserDefaultArgs - reputationSnapshot?: boolean | Prisma.AppVote$reputationSnapshotArgs -} - -export type $AppVotePayload = { - name: "AppVote" - objects: { - proposal: Prisma.$ProposalPayload - voter: Prisma.$UserPayload - reputationSnapshot: Prisma.$UserReputationSnapshotPayload | null - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - proposalId: string - voterId: string - choice: $Enums.VoteChoice - reputationScoreAtVote: runtime.Decimal | null - reputationSnapshotId: string | null - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["appVote"]> - composites: {} -} - -export type AppVoteGetPayload = runtime.Types.Result.GetResult - -export type AppVoteCountArgs = - Omit & { - select?: AppVoteCountAggregateInputType | true - } - -export interface AppVoteDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['AppVote'], meta: { name: 'AppVote' } } - /** - * Find zero or one AppVote that matches the filter. - * @param {AppVoteFindUniqueArgs} args - Arguments to find a AppVote - * @example - * // Get one AppVote - * const appVote = await prisma.appVote.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__AppVoteClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one AppVote that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {AppVoteFindUniqueOrThrowArgs} args - Arguments to find a AppVote - * @example - * // Get one AppVote - * const appVote = await prisma.appVote.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__AppVoteClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first AppVote 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 {AppVoteFindFirstArgs} args - Arguments to find a AppVote - * @example - * // Get one AppVote - * const appVote = await prisma.appVote.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__AppVoteClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first AppVote 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 {AppVoteFindFirstOrThrowArgs} args - Arguments to find a AppVote - * @example - * // Get one AppVote - * const appVote = await prisma.appVote.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__AppVoteClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more AppVotes 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 {AppVoteFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all AppVotes - * const appVotes = await prisma.appVote.findMany() - * - * // Get first 10 AppVotes - * const appVotes = await prisma.appVote.findMany({ take: 10 }) - * - * // Only select the `id` - * const appVoteWithIdOnly = await prisma.appVote.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a AppVote. - * @param {AppVoteCreateArgs} args - Arguments to create a AppVote. - * @example - * // Create one AppVote - * const AppVote = await prisma.appVote.create({ - * data: { - * // ... data to create a AppVote - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__AppVoteClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many AppVotes. - * @param {AppVoteCreateManyArgs} args - Arguments to create many AppVotes. - * @example - * // Create many AppVotes - * const appVote = await prisma.appVote.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many AppVotes and returns the data saved in the database. - * @param {AppVoteCreateManyAndReturnArgs} args - Arguments to create many AppVotes. - * @example - * // Create many AppVotes - * const appVote = await prisma.appVote.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many AppVotes and only return the `id` - * const appVoteWithIdOnly = await prisma.appVote.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 AppVote. - * @param {AppVoteDeleteArgs} args - Arguments to delete one AppVote. - * @example - * // Delete one AppVote - * const AppVote = await prisma.appVote.delete({ - * where: { - * // ... filter to delete one AppVote - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__AppVoteClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one AppVote. - * @param {AppVoteUpdateArgs} args - Arguments to update one AppVote. - * @example - * // Update one AppVote - * const appVote = await prisma.appVote.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__AppVoteClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more AppVotes. - * @param {AppVoteDeleteManyArgs} args - Arguments to filter AppVotes to delete. - * @example - * // Delete a few AppVotes - * const { count } = await prisma.appVote.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more AppVotes. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {AppVoteUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many AppVotes - * const appVote = await prisma.appVote.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more AppVotes and returns the data updated in the database. - * @param {AppVoteUpdateManyAndReturnArgs} args - Arguments to update many AppVotes. - * @example - * // Update many AppVotes - * const appVote = await prisma.appVote.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more AppVotes and only return the `id` - * const appVoteWithIdOnly = await prisma.appVote.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 AppVote. - * @param {AppVoteUpsertArgs} args - Arguments to update or create a AppVote. - * @example - * // Update or create a AppVote - * const appVote = await prisma.appVote.upsert({ - * create: { - * // ... data to create a AppVote - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the AppVote we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__AppVoteClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of AppVotes. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {AppVoteCountArgs} args - Arguments to filter AppVotes to count. - * @example - * // Count the number of AppVotes - * const count = await prisma.appVote.count({ - * where: { - * // ... the filter for the AppVotes 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 AppVote. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {AppVoteAggregateArgs} 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 AppVote. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {AppVoteGroupByArgs} 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 AppVoteGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: AppVoteGroupByArgs['orderBy'] } - : { orderBy?: AppVoteGroupByArgs['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 ? GetAppVoteGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the AppVote model - */ -readonly fields: AppVoteFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for AppVote. - * 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__AppVoteClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - proposal = {}>(args?: Prisma.Subset>): Prisma.Prisma__ProposalClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - voter = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - reputationSnapshot = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserReputationSnapshotClient, 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 AppVote model - */ -export interface AppVoteFieldRefs { - readonly id: Prisma.FieldRef<"AppVote", 'String'> - readonly proposalId: Prisma.FieldRef<"AppVote", 'String'> - readonly voterId: Prisma.FieldRef<"AppVote", 'String'> - readonly choice: Prisma.FieldRef<"AppVote", 'VoteChoice'> - readonly reputationScoreAtVote: Prisma.FieldRef<"AppVote", 'Decimal'> - readonly reputationSnapshotId: Prisma.FieldRef<"AppVote", 'String'> - readonly createdAt: Prisma.FieldRef<"AppVote", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"AppVote", 'DateTime'> -} - - -// Custom InputTypes -/** - * AppVote findUnique - */ -export type AppVoteFindUniqueArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - /** - * Filter, which AppVote to fetch. - */ - where: Prisma.AppVoteWhereUniqueInput -} - -/** - * AppVote findUniqueOrThrow - */ -export type AppVoteFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - /** - * Filter, which AppVote to fetch. - */ - where: Prisma.AppVoteWhereUniqueInput -} - -/** - * AppVote findFirst - */ -export type AppVoteFindFirstArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - /** - * Filter, which AppVote to fetch. - */ - where?: Prisma.AppVoteWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of AppVotes to fetch. - */ - orderBy?: Prisma.AppVoteOrderByWithRelationInput | Prisma.AppVoteOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for AppVotes. - */ - cursor?: Prisma.AppVoteWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` AppVotes 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` AppVotes. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of AppVotes. - */ - distinct?: Prisma.AppVoteScalarFieldEnum | Prisma.AppVoteScalarFieldEnum[] -} - -/** - * AppVote findFirstOrThrow - */ -export type AppVoteFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - /** - * Filter, which AppVote to fetch. - */ - where?: Prisma.AppVoteWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of AppVotes to fetch. - */ - orderBy?: Prisma.AppVoteOrderByWithRelationInput | Prisma.AppVoteOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for AppVotes. - */ - cursor?: Prisma.AppVoteWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` AppVotes 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` AppVotes. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of AppVotes. - */ - distinct?: Prisma.AppVoteScalarFieldEnum | Prisma.AppVoteScalarFieldEnum[] -} - -/** - * AppVote findMany - */ -export type AppVoteFindManyArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - /** - * Filter, which AppVotes to fetch. - */ - where?: Prisma.AppVoteWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of AppVotes to fetch. - */ - orderBy?: Prisma.AppVoteOrderByWithRelationInput | Prisma.AppVoteOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing AppVotes. - */ - cursor?: Prisma.AppVoteWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` AppVotes 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` AppVotes. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of AppVotes. - */ - distinct?: Prisma.AppVoteScalarFieldEnum | Prisma.AppVoteScalarFieldEnum[] -} - -/** - * AppVote create - */ -export type AppVoteCreateArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - /** - * The data needed to create a AppVote. - */ - data: Prisma.XOR -} - -/** - * AppVote createMany - */ -export type AppVoteCreateManyArgs = { - /** - * The data used to create many AppVotes. - */ - data: Prisma.AppVoteCreateManyInput | Prisma.AppVoteCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * AppVote createManyAndReturn - */ -export type AppVoteCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelectCreateManyAndReturn | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * The data used to create many AppVotes. - */ - data: Prisma.AppVoteCreateManyInput | Prisma.AppVoteCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteIncludeCreateManyAndReturn | null -} - -/** - * AppVote update - */ -export type AppVoteUpdateArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - /** - * The data needed to update a AppVote. - */ - data: Prisma.XOR - /** - * Choose, which AppVote to update. - */ - where: Prisma.AppVoteWhereUniqueInput -} - -/** - * AppVote updateMany - */ -export type AppVoteUpdateManyArgs = { - /** - * The data used to update AppVotes. - */ - data: Prisma.XOR - /** - * Filter which AppVotes to update - */ - where?: Prisma.AppVoteWhereInput - /** - * Limit how many AppVotes to update. - */ - limit?: number -} - -/** - * AppVote updateManyAndReturn - */ -export type AppVoteUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * The data used to update AppVotes. - */ - data: Prisma.XOR - /** - * Filter which AppVotes to update - */ - where?: Prisma.AppVoteWhereInput - /** - * Limit how many AppVotes to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteIncludeUpdateManyAndReturn | null -} - -/** - * AppVote upsert - */ -export type AppVoteUpsertArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - /** - * The filter to search for the AppVote to update in case it exists. - */ - where: Prisma.AppVoteWhereUniqueInput - /** - * In case the AppVote found by the `where` argument doesn't exist, create a new AppVote with this data. - */ - create: Prisma.XOR - /** - * In case the AppVote was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * AppVote delete - */ -export type AppVoteDeleteArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - /** - * Filter which AppVote to delete. - */ - where: Prisma.AppVoteWhereUniqueInput -} - -/** - * AppVote deleteMany - */ -export type AppVoteDeleteManyArgs = { - /** - * Filter which AppVotes to delete - */ - where?: Prisma.AppVoteWhereInput - /** - * Limit how many AppVotes to delete. - */ - limit?: number -} - -/** - * AppVote.reputationSnapshot - */ -export type AppVote$reputationSnapshotArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - where?: Prisma.UserReputationSnapshotWhereInput -} - -/** - * AppVote without action - */ -export type AppVoteDefaultArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null -} diff --git a/apps/api/src/generated/prisma/models/HiveEvent.ts b/apps/api/src/generated/prisma/models/HiveEvent.ts deleted file mode 100644 index 6f5cc0f..0000000 --- a/apps/api/src/generated/prisma/models/HiveEvent.ts +++ /dev/null @@ -1,1351 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `HiveEvent` 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 HiveEvent - * - */ -export type HiveEventModel = runtime.Types.Result.DefaultSelection - -export type AggregateHiveEvent = { - _count: HiveEventCountAggregateOutputType | null - _avg: HiveEventAvgAggregateOutputType | null - _sum: HiveEventSumAggregateOutputType | null - _min: HiveEventMinAggregateOutputType | null - _max: HiveEventMaxAggregateOutputType | null -} - -export type HiveEventAvgAggregateOutputType = { - blockNumber: number | null - operationIndex: number | null -} - -export type HiveEventSumAggregateOutputType = { - blockNumber: bigint | null - operationIndex: number | null -} - -export type HiveEventMinAggregateOutputType = { - id: string | null - blockNumber: bigint | null - transactionId: string | null - operationIndex: number | null - eventType: $Enums.HiveEventType | null - blockchainTimestamp: Date | null - processedAt: Date | null - createdAt: Date | null - updatedAt: Date | null -} - -export type HiveEventMaxAggregateOutputType = { - id: string | null - blockNumber: bigint | null - transactionId: string | null - operationIndex: number | null - eventType: $Enums.HiveEventType | null - blockchainTimestamp: Date | null - processedAt: Date | null - createdAt: Date | null - updatedAt: Date | null -} - -export type HiveEventCountAggregateOutputType = { - id: number - blockNumber: number - transactionId: number - operationIndex: number - eventType: number - blockchainTimestamp: number - payload: number - processedAt: number - createdAt: number - updatedAt: number - _all: number -} - - -export type HiveEventAvgAggregateInputType = { - blockNumber?: true - operationIndex?: true -} - -export type HiveEventSumAggregateInputType = { - blockNumber?: true - operationIndex?: true -} - -export type HiveEventMinAggregateInputType = { - id?: true - blockNumber?: true - transactionId?: true - operationIndex?: true - eventType?: true - blockchainTimestamp?: true - processedAt?: true - createdAt?: true - updatedAt?: true -} - -export type HiveEventMaxAggregateInputType = { - id?: true - blockNumber?: true - transactionId?: true - operationIndex?: true - eventType?: true - blockchainTimestamp?: true - processedAt?: true - createdAt?: true - updatedAt?: true -} - -export type HiveEventCountAggregateInputType = { - id?: true - blockNumber?: true - transactionId?: true - operationIndex?: true - eventType?: true - blockchainTimestamp?: true - payload?: true - processedAt?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type HiveEventAggregateArgs = { - /** - * Filter which HiveEvent to aggregate. - */ - where?: Prisma.HiveEventWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of HiveEvents to fetch. - */ - orderBy?: Prisma.HiveEventOrderByWithRelationInput | Prisma.HiveEventOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.HiveEventWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` HiveEvents 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` HiveEvents. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned HiveEvents - **/ - _count?: true | HiveEventCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to average - **/ - _avg?: HiveEventAvgAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to sum - **/ - _sum?: HiveEventSumAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: HiveEventMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: HiveEventMaxAggregateInputType -} - -export type GetHiveEventAggregateType = { - [P in keyof T & keyof AggregateHiveEvent]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type HiveEventGroupByArgs = { - where?: Prisma.HiveEventWhereInput - orderBy?: Prisma.HiveEventOrderByWithAggregationInput | Prisma.HiveEventOrderByWithAggregationInput[] - by: Prisma.HiveEventScalarFieldEnum[] | Prisma.HiveEventScalarFieldEnum - having?: Prisma.HiveEventScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: HiveEventCountAggregateInputType | true - _avg?: HiveEventAvgAggregateInputType - _sum?: HiveEventSumAggregateInputType - _min?: HiveEventMinAggregateInputType - _max?: HiveEventMaxAggregateInputType -} - -export type HiveEventGroupByOutputType = { - id: string - blockNumber: bigint - transactionId: string - operationIndex: number - eventType: $Enums.HiveEventType - blockchainTimestamp: Date - payload: runtime.JsonValue - processedAt: Date - createdAt: Date - updatedAt: Date - _count: HiveEventCountAggregateOutputType | null - _avg: HiveEventAvgAggregateOutputType | null - _sum: HiveEventSumAggregateOutputType | null - _min: HiveEventMinAggregateOutputType | null - _max: HiveEventMaxAggregateOutputType | null -} - -export type GetHiveEventGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof HiveEventGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type HiveEventWhereInput = { - AND?: Prisma.HiveEventWhereInput | Prisma.HiveEventWhereInput[] - OR?: Prisma.HiveEventWhereInput[] - NOT?: Prisma.HiveEventWhereInput | Prisma.HiveEventWhereInput[] - id?: Prisma.StringFilter<"HiveEvent"> | string - blockNumber?: Prisma.BigIntFilter<"HiveEvent"> | bigint | number - transactionId?: Prisma.StringFilter<"HiveEvent"> | string - operationIndex?: Prisma.IntFilter<"HiveEvent"> | number - eventType?: Prisma.EnumHiveEventTypeFilter<"HiveEvent"> | $Enums.HiveEventType - blockchainTimestamp?: Prisma.DateTimeFilter<"HiveEvent"> | Date | string - payload?: Prisma.JsonFilter<"HiveEvent"> - processedAt?: Prisma.DateTimeFilter<"HiveEvent"> | Date | string - createdAt?: Prisma.DateTimeFilter<"HiveEvent"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"HiveEvent"> | Date | string -} - -export type HiveEventOrderByWithRelationInput = { - id?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - eventType?: Prisma.SortOrder - blockchainTimestamp?: Prisma.SortOrder - payload?: Prisma.SortOrder - processedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type HiveEventWhereUniqueInput = Prisma.AtLeast<{ - id?: string - transactionId_operationIndex?: Prisma.HiveEventTransactionIdOperationIndexCompoundUniqueInput - AND?: Prisma.HiveEventWhereInput | Prisma.HiveEventWhereInput[] - OR?: Prisma.HiveEventWhereInput[] - NOT?: Prisma.HiveEventWhereInput | Prisma.HiveEventWhereInput[] - blockNumber?: Prisma.BigIntFilter<"HiveEvent"> | bigint | number - transactionId?: Prisma.StringFilter<"HiveEvent"> | string - operationIndex?: Prisma.IntFilter<"HiveEvent"> | number - eventType?: Prisma.EnumHiveEventTypeFilter<"HiveEvent"> | $Enums.HiveEventType - blockchainTimestamp?: Prisma.DateTimeFilter<"HiveEvent"> | Date | string - payload?: Prisma.JsonFilter<"HiveEvent"> - processedAt?: Prisma.DateTimeFilter<"HiveEvent"> | Date | string - createdAt?: Prisma.DateTimeFilter<"HiveEvent"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"HiveEvent"> | Date | string -}, "id" | "transactionId_operationIndex"> - -export type HiveEventOrderByWithAggregationInput = { - id?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - eventType?: Prisma.SortOrder - blockchainTimestamp?: Prisma.SortOrder - payload?: Prisma.SortOrder - processedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.HiveEventCountOrderByAggregateInput - _avg?: Prisma.HiveEventAvgOrderByAggregateInput - _max?: Prisma.HiveEventMaxOrderByAggregateInput - _min?: Prisma.HiveEventMinOrderByAggregateInput - _sum?: Prisma.HiveEventSumOrderByAggregateInput -} - -export type HiveEventScalarWhereWithAggregatesInput = { - AND?: Prisma.HiveEventScalarWhereWithAggregatesInput | Prisma.HiveEventScalarWhereWithAggregatesInput[] - OR?: Prisma.HiveEventScalarWhereWithAggregatesInput[] - NOT?: Prisma.HiveEventScalarWhereWithAggregatesInput | Prisma.HiveEventScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"HiveEvent"> | string - blockNumber?: Prisma.BigIntWithAggregatesFilter<"HiveEvent"> | bigint | number - transactionId?: Prisma.StringWithAggregatesFilter<"HiveEvent"> | string - operationIndex?: Prisma.IntWithAggregatesFilter<"HiveEvent"> | number - eventType?: Prisma.EnumHiveEventTypeWithAggregatesFilter<"HiveEvent"> | $Enums.HiveEventType - blockchainTimestamp?: Prisma.DateTimeWithAggregatesFilter<"HiveEvent"> | Date | string - payload?: Prisma.JsonWithAggregatesFilter<"HiveEvent"> - processedAt?: Prisma.DateTimeWithAggregatesFilter<"HiveEvent"> | Date | string - createdAt?: Prisma.DateTimeWithAggregatesFilter<"HiveEvent"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"HiveEvent"> | Date | string -} - -export type HiveEventCreateInput = { - id?: string - blockNumber: bigint | number - transactionId: string - operationIndex: number - eventType: $Enums.HiveEventType - blockchainTimestamp: Date | string - payload: Prisma.JsonNullValueInput | runtime.InputJsonValue - processedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type HiveEventUncheckedCreateInput = { - id?: string - blockNumber: bigint | number - transactionId: string - operationIndex: number - eventType: $Enums.HiveEventType - blockchainTimestamp: Date | string - payload: Prisma.JsonNullValueInput | runtime.InputJsonValue - processedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type HiveEventUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - eventType?: Prisma.EnumHiveEventTypeFieldUpdateOperationsInput | $Enums.HiveEventType - blockchainTimestamp?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - payload?: Prisma.JsonNullValueInput | runtime.InputJsonValue - processedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type HiveEventUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - eventType?: Prisma.EnumHiveEventTypeFieldUpdateOperationsInput | $Enums.HiveEventType - blockchainTimestamp?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - payload?: Prisma.JsonNullValueInput | runtime.InputJsonValue - processedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type HiveEventCreateManyInput = { - id?: string - blockNumber: bigint | number - transactionId: string - operationIndex: number - eventType: $Enums.HiveEventType - blockchainTimestamp: Date | string - payload: Prisma.JsonNullValueInput | runtime.InputJsonValue - processedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type HiveEventUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - eventType?: Prisma.EnumHiveEventTypeFieldUpdateOperationsInput | $Enums.HiveEventType - blockchainTimestamp?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - payload?: Prisma.JsonNullValueInput | runtime.InputJsonValue - processedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type HiveEventUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - eventType?: Prisma.EnumHiveEventTypeFieldUpdateOperationsInput | $Enums.HiveEventType - blockchainTimestamp?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - payload?: Prisma.JsonNullValueInput | runtime.InputJsonValue - processedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type HiveEventTransactionIdOperationIndexCompoundUniqueInput = { - transactionId: string - operationIndex: number -} - -export type HiveEventCountOrderByAggregateInput = { - id?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - eventType?: Prisma.SortOrder - blockchainTimestamp?: Prisma.SortOrder - payload?: Prisma.SortOrder - processedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type HiveEventAvgOrderByAggregateInput = { - blockNumber?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder -} - -export type HiveEventMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - eventType?: Prisma.SortOrder - blockchainTimestamp?: Prisma.SortOrder - processedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type HiveEventMinOrderByAggregateInput = { - id?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - eventType?: Prisma.SortOrder - blockchainTimestamp?: Prisma.SortOrder - processedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type HiveEventSumOrderByAggregateInput = { - blockNumber?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder -} - -export type BigIntFieldUpdateOperationsInput = { - set?: bigint | number - increment?: bigint | number - decrement?: bigint | number - multiply?: bigint | number - divide?: bigint | number -} - -export type EnumHiveEventTypeFieldUpdateOperationsInput = { - set?: $Enums.HiveEventType -} - - - -export type HiveEventSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - blockNumber?: boolean - transactionId?: boolean - operationIndex?: boolean - eventType?: boolean - blockchainTimestamp?: boolean - payload?: boolean - processedAt?: boolean - createdAt?: boolean - updatedAt?: boolean -}, ExtArgs["result"]["hiveEvent"]> - -export type HiveEventSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - blockNumber?: boolean - transactionId?: boolean - operationIndex?: boolean - eventType?: boolean - blockchainTimestamp?: boolean - payload?: boolean - processedAt?: boolean - createdAt?: boolean - updatedAt?: boolean -}, ExtArgs["result"]["hiveEvent"]> - -export type HiveEventSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - blockNumber?: boolean - transactionId?: boolean - operationIndex?: boolean - eventType?: boolean - blockchainTimestamp?: boolean - payload?: boolean - processedAt?: boolean - createdAt?: boolean - updatedAt?: boolean -}, ExtArgs["result"]["hiveEvent"]> - -export type HiveEventSelectScalar = { - id?: boolean - blockNumber?: boolean - transactionId?: boolean - operationIndex?: boolean - eventType?: boolean - blockchainTimestamp?: boolean - payload?: boolean - processedAt?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type HiveEventOmit = runtime.Types.Extensions.GetOmit<"id" | "blockNumber" | "transactionId" | "operationIndex" | "eventType" | "blockchainTimestamp" | "payload" | "processedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["hiveEvent"]> - -export type $HiveEventPayload = { - name: "HiveEvent" - objects: {} - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - blockNumber: bigint - transactionId: string - operationIndex: number - eventType: $Enums.HiveEventType - blockchainTimestamp: Date - payload: runtime.JsonValue - processedAt: Date - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["hiveEvent"]> - composites: {} -} - -export type HiveEventGetPayload = runtime.Types.Result.GetResult - -export type HiveEventCountArgs = - Omit & { - select?: HiveEventCountAggregateInputType | true - } - -export interface HiveEventDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['HiveEvent'], meta: { name: 'HiveEvent' } } - /** - * Find zero or one HiveEvent that matches the filter. - * @param {HiveEventFindUniqueArgs} args - Arguments to find a HiveEvent - * @example - * // Get one HiveEvent - * const hiveEvent = await prisma.hiveEvent.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__HiveEventClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one HiveEvent that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {HiveEventFindUniqueOrThrowArgs} args - Arguments to find a HiveEvent - * @example - * // Get one HiveEvent - * const hiveEvent = await prisma.hiveEvent.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__HiveEventClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first HiveEvent 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 {HiveEventFindFirstArgs} args - Arguments to find a HiveEvent - * @example - * // Get one HiveEvent - * const hiveEvent = await prisma.hiveEvent.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__HiveEventClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first HiveEvent 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 {HiveEventFindFirstOrThrowArgs} args - Arguments to find a HiveEvent - * @example - * // Get one HiveEvent - * const hiveEvent = await prisma.hiveEvent.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__HiveEventClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more HiveEvents 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 {HiveEventFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all HiveEvents - * const hiveEvents = await prisma.hiveEvent.findMany() - * - * // Get first 10 HiveEvents - * const hiveEvents = await prisma.hiveEvent.findMany({ take: 10 }) - * - * // Only select the `id` - * const hiveEventWithIdOnly = await prisma.hiveEvent.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a HiveEvent. - * @param {HiveEventCreateArgs} args - Arguments to create a HiveEvent. - * @example - * // Create one HiveEvent - * const HiveEvent = await prisma.hiveEvent.create({ - * data: { - * // ... data to create a HiveEvent - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__HiveEventClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many HiveEvents. - * @param {HiveEventCreateManyArgs} args - Arguments to create many HiveEvents. - * @example - * // Create many HiveEvents - * const hiveEvent = await prisma.hiveEvent.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many HiveEvents and returns the data saved in the database. - * @param {HiveEventCreateManyAndReturnArgs} args - Arguments to create many HiveEvents. - * @example - * // Create many HiveEvents - * const hiveEvent = await prisma.hiveEvent.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many HiveEvents and only return the `id` - * const hiveEventWithIdOnly = await prisma.hiveEvent.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 HiveEvent. - * @param {HiveEventDeleteArgs} args - Arguments to delete one HiveEvent. - * @example - * // Delete one HiveEvent - * const HiveEvent = await prisma.hiveEvent.delete({ - * where: { - * // ... filter to delete one HiveEvent - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__HiveEventClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one HiveEvent. - * @param {HiveEventUpdateArgs} args - Arguments to update one HiveEvent. - * @example - * // Update one HiveEvent - * const hiveEvent = await prisma.hiveEvent.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__HiveEventClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more HiveEvents. - * @param {HiveEventDeleteManyArgs} args - Arguments to filter HiveEvents to delete. - * @example - * // Delete a few HiveEvents - * const { count } = await prisma.hiveEvent.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more HiveEvents. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {HiveEventUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many HiveEvents - * const hiveEvent = await prisma.hiveEvent.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more HiveEvents and returns the data updated in the database. - * @param {HiveEventUpdateManyAndReturnArgs} args - Arguments to update many HiveEvents. - * @example - * // Update many HiveEvents - * const hiveEvent = await prisma.hiveEvent.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more HiveEvents and only return the `id` - * const hiveEventWithIdOnly = await prisma.hiveEvent.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 HiveEvent. - * @param {HiveEventUpsertArgs} args - Arguments to update or create a HiveEvent. - * @example - * // Update or create a HiveEvent - * const hiveEvent = await prisma.hiveEvent.upsert({ - * create: { - * // ... data to create a HiveEvent - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the HiveEvent we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__HiveEventClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of HiveEvents. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {HiveEventCountArgs} args - Arguments to filter HiveEvents to count. - * @example - * // Count the number of HiveEvents - * const count = await prisma.hiveEvent.count({ - * where: { - * // ... the filter for the HiveEvents 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 HiveEvent. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {HiveEventAggregateArgs} 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 HiveEvent. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {HiveEventGroupByArgs} 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 HiveEventGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: HiveEventGroupByArgs['orderBy'] } - : { orderBy?: HiveEventGroupByArgs['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 ? GetHiveEventGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the HiveEvent model - */ -readonly fields: HiveEventFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for HiveEvent. - * 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__HiveEventClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - /** - * 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 HiveEvent model - */ -export interface HiveEventFieldRefs { - readonly id: Prisma.FieldRef<"HiveEvent", 'String'> - readonly blockNumber: Prisma.FieldRef<"HiveEvent", 'BigInt'> - readonly transactionId: Prisma.FieldRef<"HiveEvent", 'String'> - readonly operationIndex: Prisma.FieldRef<"HiveEvent", 'Int'> - readonly eventType: Prisma.FieldRef<"HiveEvent", 'HiveEventType'> - readonly blockchainTimestamp: Prisma.FieldRef<"HiveEvent", 'DateTime'> - readonly payload: Prisma.FieldRef<"HiveEvent", 'Json'> - readonly processedAt: Prisma.FieldRef<"HiveEvent", 'DateTime'> - readonly createdAt: Prisma.FieldRef<"HiveEvent", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"HiveEvent", 'DateTime'> -} - - -// Custom InputTypes -/** - * HiveEvent findUnique - */ -export type HiveEventFindUniqueArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelect | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * Filter, which HiveEvent to fetch. - */ - where: Prisma.HiveEventWhereUniqueInput -} - -/** - * HiveEvent findUniqueOrThrow - */ -export type HiveEventFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelect | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * Filter, which HiveEvent to fetch. - */ - where: Prisma.HiveEventWhereUniqueInput -} - -/** - * HiveEvent findFirst - */ -export type HiveEventFindFirstArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelect | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * Filter, which HiveEvent to fetch. - */ - where?: Prisma.HiveEventWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of HiveEvents to fetch. - */ - orderBy?: Prisma.HiveEventOrderByWithRelationInput | Prisma.HiveEventOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for HiveEvents. - */ - cursor?: Prisma.HiveEventWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` HiveEvents 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` HiveEvents. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of HiveEvents. - */ - distinct?: Prisma.HiveEventScalarFieldEnum | Prisma.HiveEventScalarFieldEnum[] -} - -/** - * HiveEvent findFirstOrThrow - */ -export type HiveEventFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelect | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * Filter, which HiveEvent to fetch. - */ - where?: Prisma.HiveEventWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of HiveEvents to fetch. - */ - orderBy?: Prisma.HiveEventOrderByWithRelationInput | Prisma.HiveEventOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for HiveEvents. - */ - cursor?: Prisma.HiveEventWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` HiveEvents 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` HiveEvents. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of HiveEvents. - */ - distinct?: Prisma.HiveEventScalarFieldEnum | Prisma.HiveEventScalarFieldEnum[] -} - -/** - * HiveEvent findMany - */ -export type HiveEventFindManyArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelect | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * Filter, which HiveEvents to fetch. - */ - where?: Prisma.HiveEventWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of HiveEvents to fetch. - */ - orderBy?: Prisma.HiveEventOrderByWithRelationInput | Prisma.HiveEventOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing HiveEvents. - */ - cursor?: Prisma.HiveEventWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` HiveEvents 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` HiveEvents. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of HiveEvents. - */ - distinct?: Prisma.HiveEventScalarFieldEnum | Prisma.HiveEventScalarFieldEnum[] -} - -/** - * HiveEvent create - */ -export type HiveEventCreateArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelect | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * The data needed to create a HiveEvent. - */ - data: Prisma.XOR -} - -/** - * HiveEvent createMany - */ -export type HiveEventCreateManyArgs = { - /** - * The data used to create many HiveEvents. - */ - data: Prisma.HiveEventCreateManyInput | Prisma.HiveEventCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * HiveEvent createManyAndReturn - */ -export type HiveEventCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelectCreateManyAndReturn | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * The data used to create many HiveEvents. - */ - data: Prisma.HiveEventCreateManyInput | Prisma.HiveEventCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * HiveEvent update - */ -export type HiveEventUpdateArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelect | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * The data needed to update a HiveEvent. - */ - data: Prisma.XOR - /** - * Choose, which HiveEvent to update. - */ - where: Prisma.HiveEventWhereUniqueInput -} - -/** - * HiveEvent updateMany - */ -export type HiveEventUpdateManyArgs = { - /** - * The data used to update HiveEvents. - */ - data: Prisma.XOR - /** - * Filter which HiveEvents to update - */ - where?: Prisma.HiveEventWhereInput - /** - * Limit how many HiveEvents to update. - */ - limit?: number -} - -/** - * HiveEvent updateManyAndReturn - */ -export type HiveEventUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * The data used to update HiveEvents. - */ - data: Prisma.XOR - /** - * Filter which HiveEvents to update - */ - where?: Prisma.HiveEventWhereInput - /** - * Limit how many HiveEvents to update. - */ - limit?: number -} - -/** - * HiveEvent upsert - */ -export type HiveEventUpsertArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelect | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * The filter to search for the HiveEvent to update in case it exists. - */ - where: Prisma.HiveEventWhereUniqueInput - /** - * In case the HiveEvent found by the `where` argument doesn't exist, create a new HiveEvent with this data. - */ - create: Prisma.XOR - /** - * In case the HiveEvent was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * HiveEvent delete - */ -export type HiveEventDeleteArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelect | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null - /** - * Filter which HiveEvent to delete. - */ - where: Prisma.HiveEventWhereUniqueInput -} - -/** - * HiveEvent deleteMany - */ -export type HiveEventDeleteManyArgs = { - /** - * Filter which HiveEvents to delete - */ - where?: Prisma.HiveEventWhereInput - /** - * Limit how many HiveEvents to delete. - */ - limit?: number -} - -/** - * HiveEvent without action - */ -export type HiveEventDefaultArgs = { - /** - * Select specific fields to fetch from the HiveEvent - */ - select?: Prisma.HiveEventSelect | null - /** - * Omit specific fields from the HiveEvent - */ - omit?: Prisma.HiveEventOmit | null -} diff --git a/apps/api/src/generated/prisma/models/HiveReference.ts b/apps/api/src/generated/prisma/models/HiveReference.ts deleted file mode 100644 index 5dadedb..0000000 --- a/apps/api/src/generated/prisma/models/HiveReference.ts +++ /dev/null @@ -1,2228 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `HiveReference` 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 HiveReference - * - */ -export type HiveReferenceModel = runtime.Types.Result.DefaultSelection - -export type AggregateHiveReference = { - _count: HiveReferenceCountAggregateOutputType | null - _avg: HiveReferenceAvgAggregateOutputType | null - _sum: HiveReferenceSumAggregateOutputType | null - _min: HiveReferenceMinAggregateOutputType | null - _max: HiveReferenceMaxAggregateOutputType | null -} - -export type HiveReferenceAvgAggregateOutputType = { - blockNumber: number | null - operationIndex: number | null -} - -export type HiveReferenceSumAggregateOutputType = { - blockNumber: bigint | null - operationIndex: number | null -} - -export type HiveReferenceMinAggregateOutputType = { - id: string | null - entityType: $Enums.HiveEntityType | null - entityId: string | null - hiveAuthorUsername: string | null - authorId: string | null - permlink: string | null - transactionId: string | null - blockNumber: bigint | null - operationIndex: number | null - publishedAt: Date | null - indexedAt: Date | null - createdAt: Date | null - updatedAt: Date | null -} - -export type HiveReferenceMaxAggregateOutputType = { - id: string | null - entityType: $Enums.HiveEntityType | null - entityId: string | null - hiveAuthorUsername: string | null - authorId: string | null - permlink: string | null - transactionId: string | null - blockNumber: bigint | null - operationIndex: number | null - publishedAt: Date | null - indexedAt: Date | null - createdAt: Date | null - updatedAt: Date | null -} - -export type HiveReferenceCountAggregateOutputType = { - id: number - entityType: number - entityId: number - hiveAuthorUsername: number - authorId: number - permlink: number - transactionId: number - blockNumber: number - operationIndex: number - publicationMetadata: number - publishedAt: number - indexedAt: number - createdAt: number - updatedAt: number - _all: number -} - - -export type HiveReferenceAvgAggregateInputType = { - blockNumber?: true - operationIndex?: true -} - -export type HiveReferenceSumAggregateInputType = { - blockNumber?: true - operationIndex?: true -} - -export type HiveReferenceMinAggregateInputType = { - id?: true - entityType?: true - entityId?: true - hiveAuthorUsername?: true - authorId?: true - permlink?: true - transactionId?: true - blockNumber?: true - operationIndex?: true - publishedAt?: true - indexedAt?: true - createdAt?: true - updatedAt?: true -} - -export type HiveReferenceMaxAggregateInputType = { - id?: true - entityType?: true - entityId?: true - hiveAuthorUsername?: true - authorId?: true - permlink?: true - transactionId?: true - blockNumber?: true - operationIndex?: true - publishedAt?: true - indexedAt?: true - createdAt?: true - updatedAt?: true -} - -export type HiveReferenceCountAggregateInputType = { - id?: true - entityType?: true - entityId?: true - hiveAuthorUsername?: true - authorId?: true - permlink?: true - transactionId?: true - blockNumber?: true - operationIndex?: true - publicationMetadata?: true - publishedAt?: true - indexedAt?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type HiveReferenceAggregateArgs = { - /** - * Filter which HiveReference to aggregate. - */ - where?: Prisma.HiveReferenceWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of HiveReferences to fetch. - */ - orderBy?: Prisma.HiveReferenceOrderByWithRelationInput | Prisma.HiveReferenceOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.HiveReferenceWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` HiveReferences 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` HiveReferences. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned HiveReferences - **/ - _count?: true | HiveReferenceCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to average - **/ - _avg?: HiveReferenceAvgAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to sum - **/ - _sum?: HiveReferenceSumAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: HiveReferenceMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: HiveReferenceMaxAggregateInputType -} - -export type GetHiveReferenceAggregateType = { - [P in keyof T & keyof AggregateHiveReference]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type HiveReferenceGroupByArgs = { - where?: Prisma.HiveReferenceWhereInput - orderBy?: Prisma.HiveReferenceOrderByWithAggregationInput | Prisma.HiveReferenceOrderByWithAggregationInput[] - by: Prisma.HiveReferenceScalarFieldEnum[] | Prisma.HiveReferenceScalarFieldEnum - having?: Prisma.HiveReferenceScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: HiveReferenceCountAggregateInputType | true - _avg?: HiveReferenceAvgAggregateInputType - _sum?: HiveReferenceSumAggregateInputType - _min?: HiveReferenceMinAggregateInputType - _max?: HiveReferenceMaxAggregateInputType -} - -export type HiveReferenceGroupByOutputType = { - id: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - authorId: string | null - permlink: string - transactionId: string | null - blockNumber: bigint | null - operationIndex: number | null - publicationMetadata: runtime.JsonValue | null - publishedAt: Date - indexedAt: Date - createdAt: Date - updatedAt: Date - _count: HiveReferenceCountAggregateOutputType | null - _avg: HiveReferenceAvgAggregateOutputType | null - _sum: HiveReferenceSumAggregateOutputType | null - _min: HiveReferenceMinAggregateOutputType | null - _max: HiveReferenceMaxAggregateOutputType | null -} - -export type GetHiveReferenceGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof HiveReferenceGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type HiveReferenceWhereInput = { - AND?: Prisma.HiveReferenceWhereInput | Prisma.HiveReferenceWhereInput[] - OR?: Prisma.HiveReferenceWhereInput[] - NOT?: Prisma.HiveReferenceWhereInput | Prisma.HiveReferenceWhereInput[] - id?: Prisma.StringFilter<"HiveReference"> | string - entityType?: Prisma.EnumHiveEntityTypeFilter<"HiveReference"> | $Enums.HiveEntityType - entityId?: Prisma.StringFilter<"HiveReference"> | string - hiveAuthorUsername?: Prisma.StringFilter<"HiveReference"> | string - authorId?: Prisma.StringNullableFilter<"HiveReference"> | string | null - permlink?: Prisma.StringFilter<"HiveReference"> | string - transactionId?: Prisma.StringNullableFilter<"HiveReference"> | string | null - blockNumber?: Prisma.BigIntNullableFilter<"HiveReference"> | bigint | number | null - operationIndex?: Prisma.IntNullableFilter<"HiveReference"> | number | null - publicationMetadata?: Prisma.JsonNullableFilter<"HiveReference"> - publishedAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - indexedAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - createdAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - author?: Prisma.XOR | null - bibleVersion?: Prisma.XOR | null - loreEntry?: Prisma.XOR | null - rewardRecords?: Prisma.RewardRecordListRelationFilter -} - -export type HiveReferenceOrderByWithRelationInput = { - id?: Prisma.SortOrder - entityType?: Prisma.SortOrder - entityId?: Prisma.SortOrder - hiveAuthorUsername?: Prisma.SortOrder - authorId?: Prisma.SortOrderInput | Prisma.SortOrder - permlink?: Prisma.SortOrder - transactionId?: Prisma.SortOrderInput | Prisma.SortOrder - blockNumber?: Prisma.SortOrderInput | Prisma.SortOrder - operationIndex?: Prisma.SortOrderInput | Prisma.SortOrder - publicationMetadata?: Prisma.SortOrderInput | Prisma.SortOrder - publishedAt?: Prisma.SortOrder - indexedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - author?: Prisma.UserOrderByWithRelationInput - bibleVersion?: Prisma.WorldBibleVersionOrderByWithRelationInput - loreEntry?: Prisma.LoreEntryOrderByWithRelationInput - rewardRecords?: Prisma.RewardRecordOrderByRelationAggregateInput -} - -export type HiveReferenceWhereUniqueInput = Prisma.AtLeast<{ - id?: string - entityType_entityId?: Prisma.HiveReferenceEntityTypeEntityIdCompoundUniqueInput - hiveAuthorUsername_permlink?: Prisma.HiveReferenceHiveAuthorUsernamePermlinkCompoundUniqueInput - transactionId_operationIndex?: Prisma.HiveReferenceTransactionIdOperationIndexCompoundUniqueInput - AND?: Prisma.HiveReferenceWhereInput | Prisma.HiveReferenceWhereInput[] - OR?: Prisma.HiveReferenceWhereInput[] - NOT?: Prisma.HiveReferenceWhereInput | Prisma.HiveReferenceWhereInput[] - entityType?: Prisma.EnumHiveEntityTypeFilter<"HiveReference"> | $Enums.HiveEntityType - entityId?: Prisma.StringFilter<"HiveReference"> | string - hiveAuthorUsername?: Prisma.StringFilter<"HiveReference"> | string - authorId?: Prisma.StringNullableFilter<"HiveReference"> | string | null - permlink?: Prisma.StringFilter<"HiveReference"> | string - transactionId?: Prisma.StringNullableFilter<"HiveReference"> | string | null - blockNumber?: Prisma.BigIntNullableFilter<"HiveReference"> | bigint | number | null - operationIndex?: Prisma.IntNullableFilter<"HiveReference"> | number | null - publicationMetadata?: Prisma.JsonNullableFilter<"HiveReference"> - publishedAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - indexedAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - createdAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - author?: Prisma.XOR | null - bibleVersion?: Prisma.XOR | null - loreEntry?: Prisma.XOR | null - rewardRecords?: Prisma.RewardRecordListRelationFilter -}, "id" | "entityType_entityId" | "hiveAuthorUsername_permlink" | "transactionId_operationIndex"> - -export type HiveReferenceOrderByWithAggregationInput = { - id?: Prisma.SortOrder - entityType?: Prisma.SortOrder - entityId?: Prisma.SortOrder - hiveAuthorUsername?: Prisma.SortOrder - authorId?: Prisma.SortOrderInput | Prisma.SortOrder - permlink?: Prisma.SortOrder - transactionId?: Prisma.SortOrderInput | Prisma.SortOrder - blockNumber?: Prisma.SortOrderInput | Prisma.SortOrder - operationIndex?: Prisma.SortOrderInput | Prisma.SortOrder - publicationMetadata?: Prisma.SortOrderInput | Prisma.SortOrder - publishedAt?: Prisma.SortOrder - indexedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.HiveReferenceCountOrderByAggregateInput - _avg?: Prisma.HiveReferenceAvgOrderByAggregateInput - _max?: Prisma.HiveReferenceMaxOrderByAggregateInput - _min?: Prisma.HiveReferenceMinOrderByAggregateInput - _sum?: Prisma.HiveReferenceSumOrderByAggregateInput -} - -export type HiveReferenceScalarWhereWithAggregatesInput = { - AND?: Prisma.HiveReferenceScalarWhereWithAggregatesInput | Prisma.HiveReferenceScalarWhereWithAggregatesInput[] - OR?: Prisma.HiveReferenceScalarWhereWithAggregatesInput[] - NOT?: Prisma.HiveReferenceScalarWhereWithAggregatesInput | Prisma.HiveReferenceScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"HiveReference"> | string - entityType?: Prisma.EnumHiveEntityTypeWithAggregatesFilter<"HiveReference"> | $Enums.HiveEntityType - entityId?: Prisma.StringWithAggregatesFilter<"HiveReference"> | string - hiveAuthorUsername?: Prisma.StringWithAggregatesFilter<"HiveReference"> | string - authorId?: Prisma.StringNullableWithAggregatesFilter<"HiveReference"> | string | null - permlink?: Prisma.StringWithAggregatesFilter<"HiveReference"> | string - transactionId?: Prisma.StringNullableWithAggregatesFilter<"HiveReference"> | string | null - blockNumber?: Prisma.BigIntNullableWithAggregatesFilter<"HiveReference"> | bigint | number | null - operationIndex?: Prisma.IntNullableWithAggregatesFilter<"HiveReference"> | number | null - publicationMetadata?: Prisma.JsonNullableWithAggregatesFilter<"HiveReference"> - publishedAt?: Prisma.DateTimeWithAggregatesFilter<"HiveReference"> | Date | string - indexedAt?: Prisma.DateTimeWithAggregatesFilter<"HiveReference"> | Date | string - createdAt?: Prisma.DateTimeWithAggregatesFilter<"HiveReference"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"HiveReference"> | Date | string -} - -export type HiveReferenceCreateInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - author?: Prisma.UserCreateNestedOneWithoutHiveReferencesInput - bibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutHiveReferenceInput - loreEntry?: Prisma.LoreEntryCreateNestedOneWithoutHiveReferenceInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutHiveReferenceInput -} - -export type HiveReferenceUncheckedCreateInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - authorId?: string | null - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersion?: Prisma.WorldBibleVersionUncheckedCreateNestedOneWithoutHiveReferenceInput - loreEntry?: Prisma.LoreEntryUncheckedCreateNestedOneWithoutHiveReferenceInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutHiveReferenceInput -} - -export type HiveReferenceUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - author?: Prisma.UserUpdateOneWithoutHiveReferencesNestedInput - bibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutHiveReferenceNestedInput - loreEntry?: Prisma.LoreEntryUpdateOneWithoutHiveReferenceNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutHiveReferenceNestedInput -} - -export type HiveReferenceUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersion?: Prisma.WorldBibleVersionUncheckedUpdateOneWithoutHiveReferenceNestedInput - loreEntry?: Prisma.LoreEntryUncheckedUpdateOneWithoutHiveReferenceNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutHiveReferenceNestedInput -} - -export type HiveReferenceCreateManyInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - authorId?: string | null - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type HiveReferenceUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type HiveReferenceUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type HiveReferenceListRelationFilter = { - every?: Prisma.HiveReferenceWhereInput - some?: Prisma.HiveReferenceWhereInput - none?: Prisma.HiveReferenceWhereInput -} - -export type HiveReferenceOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type HiveReferenceNullableScalarRelationFilter = { - is?: Prisma.HiveReferenceWhereInput | null - isNot?: Prisma.HiveReferenceWhereInput | null -} - -export type HiveReferenceEntityTypeEntityIdCompoundUniqueInput = { - entityType: $Enums.HiveEntityType - entityId: string -} - -export type HiveReferenceHiveAuthorUsernamePermlinkCompoundUniqueInput = { - hiveAuthorUsername: string - permlink: string -} - -export type HiveReferenceTransactionIdOperationIndexCompoundUniqueInput = { - transactionId: string - operationIndex: number -} - -export type HiveReferenceCountOrderByAggregateInput = { - id?: Prisma.SortOrder - entityType?: Prisma.SortOrder - entityId?: Prisma.SortOrder - hiveAuthorUsername?: Prisma.SortOrder - authorId?: Prisma.SortOrder - permlink?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - publicationMetadata?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - indexedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type HiveReferenceAvgOrderByAggregateInput = { - blockNumber?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder -} - -export type HiveReferenceMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - entityType?: Prisma.SortOrder - entityId?: Prisma.SortOrder - hiveAuthorUsername?: Prisma.SortOrder - authorId?: Prisma.SortOrder - permlink?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - indexedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type HiveReferenceMinOrderByAggregateInput = { - id?: Prisma.SortOrder - entityType?: Prisma.SortOrder - entityId?: Prisma.SortOrder - hiveAuthorUsername?: Prisma.SortOrder - authorId?: Prisma.SortOrder - permlink?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - indexedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type HiveReferenceSumOrderByAggregateInput = { - blockNumber?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder -} - -export type HiveReferenceCreateNestedManyWithoutAuthorInput = { - create?: Prisma.XOR | Prisma.HiveReferenceCreateWithoutAuthorInput[] | Prisma.HiveReferenceUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.HiveReferenceCreateOrConnectWithoutAuthorInput | Prisma.HiveReferenceCreateOrConnectWithoutAuthorInput[] - createMany?: Prisma.HiveReferenceCreateManyAuthorInputEnvelope - connect?: Prisma.HiveReferenceWhereUniqueInput | Prisma.HiveReferenceWhereUniqueInput[] -} - -export type HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput = { - create?: Prisma.XOR | Prisma.HiveReferenceCreateWithoutAuthorInput[] | Prisma.HiveReferenceUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.HiveReferenceCreateOrConnectWithoutAuthorInput | Prisma.HiveReferenceCreateOrConnectWithoutAuthorInput[] - createMany?: Prisma.HiveReferenceCreateManyAuthorInputEnvelope - connect?: Prisma.HiveReferenceWhereUniqueInput | Prisma.HiveReferenceWhereUniqueInput[] -} - -export type HiveReferenceUpdateManyWithoutAuthorNestedInput = { - create?: Prisma.XOR | Prisma.HiveReferenceCreateWithoutAuthorInput[] | Prisma.HiveReferenceUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.HiveReferenceCreateOrConnectWithoutAuthorInput | Prisma.HiveReferenceCreateOrConnectWithoutAuthorInput[] - upsert?: Prisma.HiveReferenceUpsertWithWhereUniqueWithoutAuthorInput | Prisma.HiveReferenceUpsertWithWhereUniqueWithoutAuthorInput[] - createMany?: Prisma.HiveReferenceCreateManyAuthorInputEnvelope - set?: Prisma.HiveReferenceWhereUniqueInput | Prisma.HiveReferenceWhereUniqueInput[] - disconnect?: Prisma.HiveReferenceWhereUniqueInput | Prisma.HiveReferenceWhereUniqueInput[] - delete?: Prisma.HiveReferenceWhereUniqueInput | Prisma.HiveReferenceWhereUniqueInput[] - connect?: Prisma.HiveReferenceWhereUniqueInput | Prisma.HiveReferenceWhereUniqueInput[] - update?: Prisma.HiveReferenceUpdateWithWhereUniqueWithoutAuthorInput | Prisma.HiveReferenceUpdateWithWhereUniqueWithoutAuthorInput[] - updateMany?: Prisma.HiveReferenceUpdateManyWithWhereWithoutAuthorInput | Prisma.HiveReferenceUpdateManyWithWhereWithoutAuthorInput[] - deleteMany?: Prisma.HiveReferenceScalarWhereInput | Prisma.HiveReferenceScalarWhereInput[] -} - -export type HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput = { - create?: Prisma.XOR | Prisma.HiveReferenceCreateWithoutAuthorInput[] | Prisma.HiveReferenceUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.HiveReferenceCreateOrConnectWithoutAuthorInput | Prisma.HiveReferenceCreateOrConnectWithoutAuthorInput[] - upsert?: Prisma.HiveReferenceUpsertWithWhereUniqueWithoutAuthorInput | Prisma.HiveReferenceUpsertWithWhereUniqueWithoutAuthorInput[] - createMany?: Prisma.HiveReferenceCreateManyAuthorInputEnvelope - set?: Prisma.HiveReferenceWhereUniqueInput | Prisma.HiveReferenceWhereUniqueInput[] - disconnect?: Prisma.HiveReferenceWhereUniqueInput | Prisma.HiveReferenceWhereUniqueInput[] - delete?: Prisma.HiveReferenceWhereUniqueInput | Prisma.HiveReferenceWhereUniqueInput[] - connect?: Prisma.HiveReferenceWhereUniqueInput | Prisma.HiveReferenceWhereUniqueInput[] - update?: Prisma.HiveReferenceUpdateWithWhereUniqueWithoutAuthorInput | Prisma.HiveReferenceUpdateWithWhereUniqueWithoutAuthorInput[] - updateMany?: Prisma.HiveReferenceUpdateManyWithWhereWithoutAuthorInput | Prisma.HiveReferenceUpdateManyWithWhereWithoutAuthorInput[] - deleteMany?: Prisma.HiveReferenceScalarWhereInput | Prisma.HiveReferenceScalarWhereInput[] -} - -export type HiveReferenceCreateNestedOneWithoutBibleVersionInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.HiveReferenceCreateOrConnectWithoutBibleVersionInput - connect?: Prisma.HiveReferenceWhereUniqueInput -} - -export type HiveReferenceUpdateOneWithoutBibleVersionNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.HiveReferenceCreateOrConnectWithoutBibleVersionInput - upsert?: Prisma.HiveReferenceUpsertWithoutBibleVersionInput - disconnect?: Prisma.HiveReferenceWhereInput | boolean - delete?: Prisma.HiveReferenceWhereInput | boolean - connect?: Prisma.HiveReferenceWhereUniqueInput - update?: Prisma.XOR, Prisma.HiveReferenceUncheckedUpdateWithoutBibleVersionInput> -} - -export type HiveReferenceCreateNestedOneWithoutLoreEntryInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.HiveReferenceCreateOrConnectWithoutLoreEntryInput - connect?: Prisma.HiveReferenceWhereUniqueInput -} - -export type HiveReferenceUpdateOneWithoutLoreEntryNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.HiveReferenceCreateOrConnectWithoutLoreEntryInput - upsert?: Prisma.HiveReferenceUpsertWithoutLoreEntryInput - disconnect?: Prisma.HiveReferenceWhereInput | boolean - delete?: Prisma.HiveReferenceWhereInput | boolean - connect?: Prisma.HiveReferenceWhereUniqueInput - update?: Prisma.XOR, Prisma.HiveReferenceUncheckedUpdateWithoutLoreEntryInput> -} - -export type EnumHiveEntityTypeFieldUpdateOperationsInput = { - set?: $Enums.HiveEntityType -} - -export type NullableBigIntFieldUpdateOperationsInput = { - set?: bigint | number | null - increment?: bigint | number - decrement?: bigint | number - multiply?: bigint | number - divide?: bigint | number -} - -export type NullableIntFieldUpdateOperationsInput = { - set?: number | null - increment?: number - decrement?: number - multiply?: number - divide?: number -} - -export type HiveReferenceCreateNestedOneWithoutRewardRecordsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.HiveReferenceCreateOrConnectWithoutRewardRecordsInput - connect?: Prisma.HiveReferenceWhereUniqueInput -} - -export type HiveReferenceUpdateOneWithoutRewardRecordsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.HiveReferenceCreateOrConnectWithoutRewardRecordsInput - upsert?: Prisma.HiveReferenceUpsertWithoutRewardRecordsInput - disconnect?: Prisma.HiveReferenceWhereInput | boolean - delete?: Prisma.HiveReferenceWhereInput | boolean - connect?: Prisma.HiveReferenceWhereUniqueInput - update?: Prisma.XOR, Prisma.HiveReferenceUncheckedUpdateWithoutRewardRecordsInput> -} - -export type HiveReferenceCreateWithoutAuthorInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutHiveReferenceInput - loreEntry?: Prisma.LoreEntryCreateNestedOneWithoutHiveReferenceInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutHiveReferenceInput -} - -export type HiveReferenceUncheckedCreateWithoutAuthorInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersion?: Prisma.WorldBibleVersionUncheckedCreateNestedOneWithoutHiveReferenceInput - loreEntry?: Prisma.LoreEntryUncheckedCreateNestedOneWithoutHiveReferenceInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutHiveReferenceInput -} - -export type HiveReferenceCreateOrConnectWithoutAuthorInput = { - where: Prisma.HiveReferenceWhereUniqueInput - create: Prisma.XOR -} - -export type HiveReferenceCreateManyAuthorInputEnvelope = { - data: Prisma.HiveReferenceCreateManyAuthorInput | Prisma.HiveReferenceCreateManyAuthorInput[] - skipDuplicates?: boolean -} - -export type HiveReferenceUpsertWithWhereUniqueWithoutAuthorInput = { - where: Prisma.HiveReferenceWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type HiveReferenceUpdateWithWhereUniqueWithoutAuthorInput = { - where: Prisma.HiveReferenceWhereUniqueInput - data: Prisma.XOR -} - -export type HiveReferenceUpdateManyWithWhereWithoutAuthorInput = { - where: Prisma.HiveReferenceScalarWhereInput - data: Prisma.XOR -} - -export type HiveReferenceScalarWhereInput = { - AND?: Prisma.HiveReferenceScalarWhereInput | Prisma.HiveReferenceScalarWhereInput[] - OR?: Prisma.HiveReferenceScalarWhereInput[] - NOT?: Prisma.HiveReferenceScalarWhereInput | Prisma.HiveReferenceScalarWhereInput[] - id?: Prisma.StringFilter<"HiveReference"> | string - entityType?: Prisma.EnumHiveEntityTypeFilter<"HiveReference"> | $Enums.HiveEntityType - entityId?: Prisma.StringFilter<"HiveReference"> | string - hiveAuthorUsername?: Prisma.StringFilter<"HiveReference"> | string - authorId?: Prisma.StringNullableFilter<"HiveReference"> | string | null - permlink?: Prisma.StringFilter<"HiveReference"> | string - transactionId?: Prisma.StringNullableFilter<"HiveReference"> | string | null - blockNumber?: Prisma.BigIntNullableFilter<"HiveReference"> | bigint | number | null - operationIndex?: Prisma.IntNullableFilter<"HiveReference"> | number | null - publicationMetadata?: Prisma.JsonNullableFilter<"HiveReference"> - publishedAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - indexedAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - createdAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"HiveReference"> | Date | string -} - -export type HiveReferenceCreateWithoutBibleVersionInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - author?: Prisma.UserCreateNestedOneWithoutHiveReferencesInput - loreEntry?: Prisma.LoreEntryCreateNestedOneWithoutHiveReferenceInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutHiveReferenceInput -} - -export type HiveReferenceUncheckedCreateWithoutBibleVersionInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - authorId?: string | null - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - loreEntry?: Prisma.LoreEntryUncheckedCreateNestedOneWithoutHiveReferenceInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutHiveReferenceInput -} - -export type HiveReferenceCreateOrConnectWithoutBibleVersionInput = { - where: Prisma.HiveReferenceWhereUniqueInput - create: Prisma.XOR -} - -export type HiveReferenceUpsertWithoutBibleVersionInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.HiveReferenceWhereInput -} - -export type HiveReferenceUpdateToOneWithWhereWithoutBibleVersionInput = { - where?: Prisma.HiveReferenceWhereInput - data: Prisma.XOR -} - -export type HiveReferenceUpdateWithoutBibleVersionInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - author?: Prisma.UserUpdateOneWithoutHiveReferencesNestedInput - loreEntry?: Prisma.LoreEntryUpdateOneWithoutHiveReferenceNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutHiveReferenceNestedInput -} - -export type HiveReferenceUncheckedUpdateWithoutBibleVersionInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - loreEntry?: Prisma.LoreEntryUncheckedUpdateOneWithoutHiveReferenceNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutHiveReferenceNestedInput -} - -export type HiveReferenceCreateWithoutLoreEntryInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - author?: Prisma.UserCreateNestedOneWithoutHiveReferencesInput - bibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutHiveReferenceInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutHiveReferenceInput -} - -export type HiveReferenceUncheckedCreateWithoutLoreEntryInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - authorId?: string | null - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersion?: Prisma.WorldBibleVersionUncheckedCreateNestedOneWithoutHiveReferenceInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutHiveReferenceInput -} - -export type HiveReferenceCreateOrConnectWithoutLoreEntryInput = { - where: Prisma.HiveReferenceWhereUniqueInput - create: Prisma.XOR -} - -export type HiveReferenceUpsertWithoutLoreEntryInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.HiveReferenceWhereInput -} - -export type HiveReferenceUpdateToOneWithWhereWithoutLoreEntryInput = { - where?: Prisma.HiveReferenceWhereInput - data: Prisma.XOR -} - -export type HiveReferenceUpdateWithoutLoreEntryInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - author?: Prisma.UserUpdateOneWithoutHiveReferencesNestedInput - bibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutHiveReferenceNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutHiveReferenceNestedInput -} - -export type HiveReferenceUncheckedUpdateWithoutLoreEntryInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersion?: Prisma.WorldBibleVersionUncheckedUpdateOneWithoutHiveReferenceNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutHiveReferenceNestedInput -} - -export type HiveReferenceCreateWithoutRewardRecordsInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - author?: Prisma.UserCreateNestedOneWithoutHiveReferencesInput - bibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutHiveReferenceInput - loreEntry?: Prisma.LoreEntryCreateNestedOneWithoutHiveReferenceInput -} - -export type HiveReferenceUncheckedCreateWithoutRewardRecordsInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - authorId?: string | null - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersion?: Prisma.WorldBibleVersionUncheckedCreateNestedOneWithoutHiveReferenceInput - loreEntry?: Prisma.LoreEntryUncheckedCreateNestedOneWithoutHiveReferenceInput -} - -export type HiveReferenceCreateOrConnectWithoutRewardRecordsInput = { - where: Prisma.HiveReferenceWhereUniqueInput - create: Prisma.XOR -} - -export type HiveReferenceUpsertWithoutRewardRecordsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.HiveReferenceWhereInput -} - -export type HiveReferenceUpdateToOneWithWhereWithoutRewardRecordsInput = { - where?: Prisma.HiveReferenceWhereInput - data: Prisma.XOR -} - -export type HiveReferenceUpdateWithoutRewardRecordsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - author?: Prisma.UserUpdateOneWithoutHiveReferencesNestedInput - bibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutHiveReferenceNestedInput - loreEntry?: Prisma.LoreEntryUpdateOneWithoutHiveReferenceNestedInput -} - -export type HiveReferenceUncheckedUpdateWithoutRewardRecordsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersion?: Prisma.WorldBibleVersionUncheckedUpdateOneWithoutHiveReferenceNestedInput - loreEntry?: Prisma.LoreEntryUncheckedUpdateOneWithoutHiveReferenceNestedInput -} - -export type HiveReferenceCreateManyAuthorInput = { - id?: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - permlink: string - transactionId?: string | null - blockNumber?: bigint | number | null - operationIndex?: number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt: Date | string - indexedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type HiveReferenceUpdateWithoutAuthorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutHiveReferenceNestedInput - loreEntry?: Prisma.LoreEntryUpdateOneWithoutHiveReferenceNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutHiveReferenceNestedInput -} - -export type HiveReferenceUncheckedUpdateWithoutAuthorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersion?: Prisma.WorldBibleVersionUncheckedUpdateOneWithoutHiveReferenceNestedInput - loreEntry?: Prisma.LoreEntryUncheckedUpdateOneWithoutHiveReferenceNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutHiveReferenceNestedInput -} - -export type HiveReferenceUncheckedUpdateManyWithoutAuthorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumHiveEntityTypeFieldUpdateOperationsInput | $Enums.HiveEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - hiveAuthorUsername?: Prisma.StringFieldUpdateOperationsInput | string - permlink?: Prisma.StringFieldUpdateOperationsInput | string - transactionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - blockNumber?: Prisma.NullableBigIntFieldUpdateOperationsInput | bigint | number | null - operationIndex?: Prisma.NullableIntFieldUpdateOperationsInput | number | null - publicationMetadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - publishedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - indexedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - -/** - * Count Type HiveReferenceCountOutputType - */ - -export type HiveReferenceCountOutputType = { - rewardRecords: number -} - -export type HiveReferenceCountOutputTypeSelect = { - rewardRecords?: boolean | HiveReferenceCountOutputTypeCountRewardRecordsArgs -} - -/** - * HiveReferenceCountOutputType without action - */ -export type HiveReferenceCountOutputTypeDefaultArgs = { - /** - * Select specific fields to fetch from the HiveReferenceCountOutputType - */ - select?: Prisma.HiveReferenceCountOutputTypeSelect | null -} - -/** - * HiveReferenceCountOutputType without action - */ -export type HiveReferenceCountOutputTypeCountRewardRecordsArgs = { - where?: Prisma.RewardRecordWhereInput -} - - -export type HiveReferenceSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - entityType?: boolean - entityId?: boolean - hiveAuthorUsername?: boolean - authorId?: boolean - permlink?: boolean - transactionId?: boolean - blockNumber?: boolean - operationIndex?: boolean - publicationMetadata?: boolean - publishedAt?: boolean - indexedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - author?: boolean | Prisma.HiveReference$authorArgs - bibleVersion?: boolean | Prisma.HiveReference$bibleVersionArgs - loreEntry?: boolean | Prisma.HiveReference$loreEntryArgs - rewardRecords?: boolean | Prisma.HiveReference$rewardRecordsArgs - _count?: boolean | Prisma.HiveReferenceCountOutputTypeDefaultArgs -}, ExtArgs["result"]["hiveReference"]> - -export type HiveReferenceSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - entityType?: boolean - entityId?: boolean - hiveAuthorUsername?: boolean - authorId?: boolean - permlink?: boolean - transactionId?: boolean - blockNumber?: boolean - operationIndex?: boolean - publicationMetadata?: boolean - publishedAt?: boolean - indexedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - author?: boolean | Prisma.HiveReference$authorArgs -}, ExtArgs["result"]["hiveReference"]> - -export type HiveReferenceSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - entityType?: boolean - entityId?: boolean - hiveAuthorUsername?: boolean - authorId?: boolean - permlink?: boolean - transactionId?: boolean - blockNumber?: boolean - operationIndex?: boolean - publicationMetadata?: boolean - publishedAt?: boolean - indexedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - author?: boolean | Prisma.HiveReference$authorArgs -}, ExtArgs["result"]["hiveReference"]> - -export type HiveReferenceSelectScalar = { - id?: boolean - entityType?: boolean - entityId?: boolean - hiveAuthorUsername?: boolean - authorId?: boolean - permlink?: boolean - transactionId?: boolean - blockNumber?: boolean - operationIndex?: boolean - publicationMetadata?: boolean - publishedAt?: boolean - indexedAt?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type HiveReferenceOmit = runtime.Types.Extensions.GetOmit<"id" | "entityType" | "entityId" | "hiveAuthorUsername" | "authorId" | "permlink" | "transactionId" | "blockNumber" | "operationIndex" | "publicationMetadata" | "publishedAt" | "indexedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["hiveReference"]> -export type HiveReferenceInclude = { - author?: boolean | Prisma.HiveReference$authorArgs - bibleVersion?: boolean | Prisma.HiveReference$bibleVersionArgs - loreEntry?: boolean | Prisma.HiveReference$loreEntryArgs - rewardRecords?: boolean | Prisma.HiveReference$rewardRecordsArgs - _count?: boolean | Prisma.HiveReferenceCountOutputTypeDefaultArgs -} -export type HiveReferenceIncludeCreateManyAndReturn = { - author?: boolean | Prisma.HiveReference$authorArgs -} -export type HiveReferenceIncludeUpdateManyAndReturn = { - author?: boolean | Prisma.HiveReference$authorArgs -} - -export type $HiveReferencePayload = { - name: "HiveReference" - objects: { - author: Prisma.$UserPayload | null - bibleVersion: Prisma.$WorldBibleVersionPayload | null - loreEntry: Prisma.$LoreEntryPayload | null - rewardRecords: Prisma.$RewardRecordPayload[] - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - entityType: $Enums.HiveEntityType - entityId: string - hiveAuthorUsername: string - authorId: string | null - permlink: string - transactionId: string | null - blockNumber: bigint | null - operationIndex: number | null - publicationMetadata: runtime.JsonValue | null - publishedAt: Date - indexedAt: Date - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["hiveReference"]> - composites: {} -} - -export type HiveReferenceGetPayload = runtime.Types.Result.GetResult - -export type HiveReferenceCountArgs = - Omit & { - select?: HiveReferenceCountAggregateInputType | true - } - -export interface HiveReferenceDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['HiveReference'], meta: { name: 'HiveReference' } } - /** - * Find zero or one HiveReference that matches the filter. - * @param {HiveReferenceFindUniqueArgs} args - Arguments to find a HiveReference - * @example - * // Get one HiveReference - * const hiveReference = await prisma.hiveReference.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__HiveReferenceClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one HiveReference that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {HiveReferenceFindUniqueOrThrowArgs} args - Arguments to find a HiveReference - * @example - * // Get one HiveReference - * const hiveReference = await prisma.hiveReference.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__HiveReferenceClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first HiveReference 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 {HiveReferenceFindFirstArgs} args - Arguments to find a HiveReference - * @example - * // Get one HiveReference - * const hiveReference = await prisma.hiveReference.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__HiveReferenceClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first HiveReference 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 {HiveReferenceFindFirstOrThrowArgs} args - Arguments to find a HiveReference - * @example - * // Get one HiveReference - * const hiveReference = await prisma.hiveReference.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__HiveReferenceClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more HiveReferences 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 {HiveReferenceFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all HiveReferences - * const hiveReferences = await prisma.hiveReference.findMany() - * - * // Get first 10 HiveReferences - * const hiveReferences = await prisma.hiveReference.findMany({ take: 10 }) - * - * // Only select the `id` - * const hiveReferenceWithIdOnly = await prisma.hiveReference.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a HiveReference. - * @param {HiveReferenceCreateArgs} args - Arguments to create a HiveReference. - * @example - * // Create one HiveReference - * const HiveReference = await prisma.hiveReference.create({ - * data: { - * // ... data to create a HiveReference - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__HiveReferenceClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many HiveReferences. - * @param {HiveReferenceCreateManyArgs} args - Arguments to create many HiveReferences. - * @example - * // Create many HiveReferences - * const hiveReference = await prisma.hiveReference.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many HiveReferences and returns the data saved in the database. - * @param {HiveReferenceCreateManyAndReturnArgs} args - Arguments to create many HiveReferences. - * @example - * // Create many HiveReferences - * const hiveReference = await prisma.hiveReference.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many HiveReferences and only return the `id` - * const hiveReferenceWithIdOnly = await prisma.hiveReference.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 HiveReference. - * @param {HiveReferenceDeleteArgs} args - Arguments to delete one HiveReference. - * @example - * // Delete one HiveReference - * const HiveReference = await prisma.hiveReference.delete({ - * where: { - * // ... filter to delete one HiveReference - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__HiveReferenceClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one HiveReference. - * @param {HiveReferenceUpdateArgs} args - Arguments to update one HiveReference. - * @example - * // Update one HiveReference - * const hiveReference = await prisma.hiveReference.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__HiveReferenceClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more HiveReferences. - * @param {HiveReferenceDeleteManyArgs} args - Arguments to filter HiveReferences to delete. - * @example - * // Delete a few HiveReferences - * const { count } = await prisma.hiveReference.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more HiveReferences. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {HiveReferenceUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many HiveReferences - * const hiveReference = await prisma.hiveReference.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more HiveReferences and returns the data updated in the database. - * @param {HiveReferenceUpdateManyAndReturnArgs} args - Arguments to update many HiveReferences. - * @example - * // Update many HiveReferences - * const hiveReference = await prisma.hiveReference.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more HiveReferences and only return the `id` - * const hiveReferenceWithIdOnly = await prisma.hiveReference.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 HiveReference. - * @param {HiveReferenceUpsertArgs} args - Arguments to update or create a HiveReference. - * @example - * // Update or create a HiveReference - * const hiveReference = await prisma.hiveReference.upsert({ - * create: { - * // ... data to create a HiveReference - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the HiveReference we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__HiveReferenceClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of HiveReferences. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {HiveReferenceCountArgs} args - Arguments to filter HiveReferences to count. - * @example - * // Count the number of HiveReferences - * const count = await prisma.hiveReference.count({ - * where: { - * // ... the filter for the HiveReferences 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 HiveReference. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {HiveReferenceAggregateArgs} 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 HiveReference. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {HiveReferenceGroupByArgs} 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 HiveReferenceGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: HiveReferenceGroupByArgs['orderBy'] } - : { orderBy?: HiveReferenceGroupByArgs['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 ? GetHiveReferenceGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the HiveReference model - */ -readonly fields: HiveReferenceFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for HiveReference. - * 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__HiveReferenceClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - author = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - bibleVersion = {}>(args?: Prisma.Subset>): Prisma.Prisma__WorldBibleVersionClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - loreEntry = {}>(args?: Prisma.Subset>): Prisma.Prisma__LoreEntryClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - rewardRecords = {}>(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 HiveReference model - */ -export interface HiveReferenceFieldRefs { - readonly id: Prisma.FieldRef<"HiveReference", 'String'> - readonly entityType: Prisma.FieldRef<"HiveReference", 'HiveEntityType'> - readonly entityId: Prisma.FieldRef<"HiveReference", 'String'> - readonly hiveAuthorUsername: Prisma.FieldRef<"HiveReference", 'String'> - readonly authorId: Prisma.FieldRef<"HiveReference", 'String'> - readonly permlink: Prisma.FieldRef<"HiveReference", 'String'> - readonly transactionId: Prisma.FieldRef<"HiveReference", 'String'> - readonly blockNumber: Prisma.FieldRef<"HiveReference", 'BigInt'> - readonly operationIndex: Prisma.FieldRef<"HiveReference", 'Int'> - readonly publicationMetadata: Prisma.FieldRef<"HiveReference", 'Json'> - readonly publishedAt: Prisma.FieldRef<"HiveReference", 'DateTime'> - readonly indexedAt: Prisma.FieldRef<"HiveReference", 'DateTime'> - readonly createdAt: Prisma.FieldRef<"HiveReference", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"HiveReference", 'DateTime'> -} - - -// Custom InputTypes -/** - * HiveReference findUnique - */ -export type HiveReferenceFindUniqueArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - /** - * Filter, which HiveReference to fetch. - */ - where: Prisma.HiveReferenceWhereUniqueInput -} - -/** - * HiveReference findUniqueOrThrow - */ -export type HiveReferenceFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - /** - * Filter, which HiveReference to fetch. - */ - where: Prisma.HiveReferenceWhereUniqueInput -} - -/** - * HiveReference findFirst - */ -export type HiveReferenceFindFirstArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - /** - * Filter, which HiveReference to fetch. - */ - where?: Prisma.HiveReferenceWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of HiveReferences to fetch. - */ - orderBy?: Prisma.HiveReferenceOrderByWithRelationInput | Prisma.HiveReferenceOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for HiveReferences. - */ - cursor?: Prisma.HiveReferenceWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` HiveReferences 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` HiveReferences. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of HiveReferences. - */ - distinct?: Prisma.HiveReferenceScalarFieldEnum | Prisma.HiveReferenceScalarFieldEnum[] -} - -/** - * HiveReference findFirstOrThrow - */ -export type HiveReferenceFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - /** - * Filter, which HiveReference to fetch. - */ - where?: Prisma.HiveReferenceWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of HiveReferences to fetch. - */ - orderBy?: Prisma.HiveReferenceOrderByWithRelationInput | Prisma.HiveReferenceOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for HiveReferences. - */ - cursor?: Prisma.HiveReferenceWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` HiveReferences 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` HiveReferences. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of HiveReferences. - */ - distinct?: Prisma.HiveReferenceScalarFieldEnum | Prisma.HiveReferenceScalarFieldEnum[] -} - -/** - * HiveReference findMany - */ -export type HiveReferenceFindManyArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - /** - * Filter, which HiveReferences to fetch. - */ - where?: Prisma.HiveReferenceWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of HiveReferences to fetch. - */ - orderBy?: Prisma.HiveReferenceOrderByWithRelationInput | Prisma.HiveReferenceOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing HiveReferences. - */ - cursor?: Prisma.HiveReferenceWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` HiveReferences 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` HiveReferences. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of HiveReferences. - */ - distinct?: Prisma.HiveReferenceScalarFieldEnum | Prisma.HiveReferenceScalarFieldEnum[] -} - -/** - * HiveReference create - */ -export type HiveReferenceCreateArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - /** - * The data needed to create a HiveReference. - */ - data: Prisma.XOR -} - -/** - * HiveReference createMany - */ -export type HiveReferenceCreateManyArgs = { - /** - * The data used to create many HiveReferences. - */ - data: Prisma.HiveReferenceCreateManyInput | Prisma.HiveReferenceCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * HiveReference createManyAndReturn - */ -export type HiveReferenceCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelectCreateManyAndReturn | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * The data used to create many HiveReferences. - */ - data: Prisma.HiveReferenceCreateManyInput | Prisma.HiveReferenceCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceIncludeCreateManyAndReturn | null -} - -/** - * HiveReference update - */ -export type HiveReferenceUpdateArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - /** - * The data needed to update a HiveReference. - */ - data: Prisma.XOR - /** - * Choose, which HiveReference to update. - */ - where: Prisma.HiveReferenceWhereUniqueInput -} - -/** - * HiveReference updateMany - */ -export type HiveReferenceUpdateManyArgs = { - /** - * The data used to update HiveReferences. - */ - data: Prisma.XOR - /** - * Filter which HiveReferences to update - */ - where?: Prisma.HiveReferenceWhereInput - /** - * Limit how many HiveReferences to update. - */ - limit?: number -} - -/** - * HiveReference updateManyAndReturn - */ -export type HiveReferenceUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * The data used to update HiveReferences. - */ - data: Prisma.XOR - /** - * Filter which HiveReferences to update - */ - where?: Prisma.HiveReferenceWhereInput - /** - * Limit how many HiveReferences to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceIncludeUpdateManyAndReturn | null -} - -/** - * HiveReference upsert - */ -export type HiveReferenceUpsertArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - /** - * The filter to search for the HiveReference to update in case it exists. - */ - where: Prisma.HiveReferenceWhereUniqueInput - /** - * In case the HiveReference found by the `where` argument doesn't exist, create a new HiveReference with this data. - */ - create: Prisma.XOR - /** - * In case the HiveReference was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * HiveReference delete - */ -export type HiveReferenceDeleteArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - /** - * Filter which HiveReference to delete. - */ - where: Prisma.HiveReferenceWhereUniqueInput -} - -/** - * HiveReference deleteMany - */ -export type HiveReferenceDeleteManyArgs = { - /** - * Filter which HiveReferences to delete - */ - where?: Prisma.HiveReferenceWhereInput - /** - * Limit how many HiveReferences to delete. - */ - limit?: number -} - -/** - * HiveReference.author - */ -export type HiveReference$authorArgs = { - /** - * 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 -} - -/** - * HiveReference.bibleVersion - */ -export type HiveReference$bibleVersionArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - where?: Prisma.WorldBibleVersionWhereInput -} - -/** - * HiveReference.loreEntry - */ -export type HiveReference$loreEntryArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - where?: Prisma.LoreEntryWhereInput -} - -/** - * HiveReference.rewardRecords - */ -export type HiveReference$rewardRecordsArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - where?: Prisma.RewardRecordWhereInput - orderBy?: Prisma.RewardRecordOrderByWithRelationInput | Prisma.RewardRecordOrderByWithRelationInput[] - cursor?: Prisma.RewardRecordWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.RewardRecordScalarFieldEnum | Prisma.RewardRecordScalarFieldEnum[] -} - -/** - * HiveReference without action - */ -export type HiveReferenceDefaultArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null -} diff --git a/apps/api/src/generated/prisma/models/LoreEntry.ts b/apps/api/src/generated/prisma/models/LoreEntry.ts deleted file mode 100644 index 175c5d9..0000000 --- a/apps/api/src/generated/prisma/models/LoreEntry.ts +++ /dev/null @@ -1,2564 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `LoreEntry` 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 LoreEntry - * - */ -export type LoreEntryModel = runtime.Types.Result.DefaultSelection - -export type AggregateLoreEntry = { - _count: LoreEntryCountAggregateOutputType | null - _min: LoreEntryMinAggregateOutputType | null - _max: LoreEntryMaxAggregateOutputType | null -} - -export type LoreEntryMinAggregateOutputType = { - id: string | null - worldId: string | null - authorId: string | null - title: string | null - slug: string | null - loreType: $Enums.LoreType | null - status: $Enums.LoreStatus | null - publishedAt: Date | null - hiveReferenceId: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type LoreEntryMaxAggregateOutputType = { - id: string | null - worldId: string | null - authorId: string | null - title: string | null - slug: string | null - loreType: $Enums.LoreType | null - status: $Enums.LoreStatus | null - publishedAt: Date | null - hiveReferenceId: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type LoreEntryCountAggregateOutputType = { - id: number - worldId: number - authorId: number - title: number - slug: number - loreType: number - content: number - status: number - publishedAt: number - hiveReferenceId: number - createdAt: number - updatedAt: number - _all: number -} - - -export type LoreEntryMinAggregateInputType = { - id?: true - worldId?: true - authorId?: true - title?: true - slug?: true - loreType?: true - status?: true - publishedAt?: true - hiveReferenceId?: true - createdAt?: true - updatedAt?: true -} - -export type LoreEntryMaxAggregateInputType = { - id?: true - worldId?: true - authorId?: true - title?: true - slug?: true - loreType?: true - status?: true - publishedAt?: true - hiveReferenceId?: true - createdAt?: true - updatedAt?: true -} - -export type LoreEntryCountAggregateInputType = { - id?: true - worldId?: true - authorId?: true - title?: true - slug?: true - loreType?: true - content?: true - status?: true - publishedAt?: true - hiveReferenceId?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type LoreEntryAggregateArgs = { - /** - * Filter which LoreEntry to aggregate. - */ - where?: Prisma.LoreEntryWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of LoreEntries to fetch. - */ - orderBy?: Prisma.LoreEntryOrderByWithRelationInput | Prisma.LoreEntryOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.LoreEntryWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` LoreEntries 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` LoreEntries. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned LoreEntries - **/ - _count?: true | LoreEntryCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: LoreEntryMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: LoreEntryMaxAggregateInputType -} - -export type GetLoreEntryAggregateType = { - [P in keyof T & keyof AggregateLoreEntry]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type LoreEntryGroupByArgs = { - where?: Prisma.LoreEntryWhereInput - orderBy?: Prisma.LoreEntryOrderByWithAggregationInput | Prisma.LoreEntryOrderByWithAggregationInput[] - by: Prisma.LoreEntryScalarFieldEnum[] | Prisma.LoreEntryScalarFieldEnum - having?: Prisma.LoreEntryScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: LoreEntryCountAggregateInputType | true - _min?: LoreEntryMinAggregateInputType - _max?: LoreEntryMaxAggregateInputType -} - -export type LoreEntryGroupByOutputType = { - id: string - worldId: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: runtime.JsonValue - status: $Enums.LoreStatus - publishedAt: Date | null - hiveReferenceId: string | null - createdAt: Date - updatedAt: Date - _count: LoreEntryCountAggregateOutputType | null - _min: LoreEntryMinAggregateOutputType | null - _max: LoreEntryMaxAggregateOutputType | null -} - -export type GetLoreEntryGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof LoreEntryGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type LoreEntryWhereInput = { - AND?: Prisma.LoreEntryWhereInput | Prisma.LoreEntryWhereInput[] - OR?: Prisma.LoreEntryWhereInput[] - NOT?: Prisma.LoreEntryWhereInput | Prisma.LoreEntryWhereInput[] - id?: Prisma.StringFilter<"LoreEntry"> | string - worldId?: Prisma.StringFilter<"LoreEntry"> | string - authorId?: Prisma.StringFilter<"LoreEntry"> | string - title?: Prisma.StringFilter<"LoreEntry"> | string - slug?: Prisma.StringFilter<"LoreEntry"> | string - loreType?: Prisma.EnumLoreTypeFilter<"LoreEntry"> | $Enums.LoreType - content?: Prisma.JsonFilter<"LoreEntry"> - status?: Prisma.EnumLoreStatusFilter<"LoreEntry"> | $Enums.LoreStatus - publishedAt?: Prisma.DateTimeNullableFilter<"LoreEntry"> | Date | string | null - hiveReferenceId?: Prisma.StringNullableFilter<"LoreEntry"> | string | null - createdAt?: Prisma.DateTimeFilter<"LoreEntry"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"LoreEntry"> | Date | string - world?: Prisma.XOR - author?: Prisma.XOR - hiveReference?: Prisma.XOR | null - outgoingRelations?: Prisma.LoreRelationshipListRelationFilter - incomingRelations?: Prisma.LoreRelationshipListRelationFilter - targetProposals?: Prisma.ProposalListRelationFilter - resultingProposals?: Prisma.ProposalListRelationFilter -} - -export type LoreEntryOrderByWithRelationInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - authorId?: Prisma.SortOrder - title?: Prisma.SortOrder - slug?: Prisma.SortOrder - loreType?: Prisma.SortOrder - content?: Prisma.SortOrder - status?: Prisma.SortOrder - publishedAt?: Prisma.SortOrderInput | Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - world?: Prisma.WorldOrderByWithRelationInput - author?: Prisma.UserOrderByWithRelationInput - hiveReference?: Prisma.HiveReferenceOrderByWithRelationInput - outgoingRelations?: Prisma.LoreRelationshipOrderByRelationAggregateInput - incomingRelations?: Prisma.LoreRelationshipOrderByRelationAggregateInput - targetProposals?: Prisma.ProposalOrderByRelationAggregateInput - resultingProposals?: Prisma.ProposalOrderByRelationAggregateInput -} - -export type LoreEntryWhereUniqueInput = Prisma.AtLeast<{ - id?: string - hiveReferenceId?: string - worldId_slug?: Prisma.LoreEntryWorldIdSlugCompoundUniqueInput - AND?: Prisma.LoreEntryWhereInput | Prisma.LoreEntryWhereInput[] - OR?: Prisma.LoreEntryWhereInput[] - NOT?: Prisma.LoreEntryWhereInput | Prisma.LoreEntryWhereInput[] - worldId?: Prisma.StringFilter<"LoreEntry"> | string - authorId?: Prisma.StringFilter<"LoreEntry"> | string - title?: Prisma.StringFilter<"LoreEntry"> | string - slug?: Prisma.StringFilter<"LoreEntry"> | string - loreType?: Prisma.EnumLoreTypeFilter<"LoreEntry"> | $Enums.LoreType - content?: Prisma.JsonFilter<"LoreEntry"> - status?: Prisma.EnumLoreStatusFilter<"LoreEntry"> | $Enums.LoreStatus - publishedAt?: Prisma.DateTimeNullableFilter<"LoreEntry"> | Date | string | null - createdAt?: Prisma.DateTimeFilter<"LoreEntry"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"LoreEntry"> | Date | string - world?: Prisma.XOR - author?: Prisma.XOR - hiveReference?: Prisma.XOR | null - outgoingRelations?: Prisma.LoreRelationshipListRelationFilter - incomingRelations?: Prisma.LoreRelationshipListRelationFilter - targetProposals?: Prisma.ProposalListRelationFilter - resultingProposals?: Prisma.ProposalListRelationFilter -}, "id" | "hiveReferenceId" | "worldId_slug"> - -export type LoreEntryOrderByWithAggregationInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - authorId?: Prisma.SortOrder - title?: Prisma.SortOrder - slug?: Prisma.SortOrder - loreType?: Prisma.SortOrder - content?: Prisma.SortOrder - status?: Prisma.SortOrder - publishedAt?: Prisma.SortOrderInput | Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.LoreEntryCountOrderByAggregateInput - _max?: Prisma.LoreEntryMaxOrderByAggregateInput - _min?: Prisma.LoreEntryMinOrderByAggregateInput -} - -export type LoreEntryScalarWhereWithAggregatesInput = { - AND?: Prisma.LoreEntryScalarWhereWithAggregatesInput | Prisma.LoreEntryScalarWhereWithAggregatesInput[] - OR?: Prisma.LoreEntryScalarWhereWithAggregatesInput[] - NOT?: Prisma.LoreEntryScalarWhereWithAggregatesInput | Prisma.LoreEntryScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"LoreEntry"> | string - worldId?: Prisma.StringWithAggregatesFilter<"LoreEntry"> | string - authorId?: Prisma.StringWithAggregatesFilter<"LoreEntry"> | string - title?: Prisma.StringWithAggregatesFilter<"LoreEntry"> | string - slug?: Prisma.StringWithAggregatesFilter<"LoreEntry"> | string - loreType?: Prisma.EnumLoreTypeWithAggregatesFilter<"LoreEntry"> | $Enums.LoreType - content?: Prisma.JsonWithAggregatesFilter<"LoreEntry"> - status?: Prisma.EnumLoreStatusWithAggregatesFilter<"LoreEntry"> | $Enums.LoreStatus - publishedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"LoreEntry"> | Date | string | null - hiveReferenceId?: Prisma.StringNullableWithAggregatesFilter<"LoreEntry"> | string | null - createdAt?: Prisma.DateTimeWithAggregatesFilter<"LoreEntry"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"LoreEntry"> | Date | string -} - -export type LoreEntryCreateInput = { - id?: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutLoreEntriesInput - author: Prisma.UserCreateNestedOneWithoutLoreEntriesInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutLoreEntryInput - outgoingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryUncheckedCreateInput = { - id?: string - worldId: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutLoreEntriesNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutLoreEntriesNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutLoreEntryNestedInput - outgoingRelations?: Prisma.LoreRelationshipUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUncheckedUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryCreateManyInput = { - id?: string - worldId: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreEntryUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreEntryUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreEntryListRelationFilter = { - every?: Prisma.LoreEntryWhereInput - some?: Prisma.LoreEntryWhereInput - none?: Prisma.LoreEntryWhereInput -} - -export type LoreEntryOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type LoreEntryWorldIdSlugCompoundUniqueInput = { - worldId: string - slug: string -} - -export type LoreEntryCountOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - authorId?: Prisma.SortOrder - title?: Prisma.SortOrder - slug?: Prisma.SortOrder - loreType?: Prisma.SortOrder - content?: Prisma.SortOrder - status?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type LoreEntryMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - authorId?: Prisma.SortOrder - title?: Prisma.SortOrder - slug?: Prisma.SortOrder - loreType?: Prisma.SortOrder - status?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type LoreEntryMinOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - authorId?: Prisma.SortOrder - title?: Prisma.SortOrder - slug?: Prisma.SortOrder - loreType?: Prisma.SortOrder - status?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type LoreEntryScalarRelationFilter = { - is?: Prisma.LoreEntryWhereInput - isNot?: Prisma.LoreEntryWhereInput -} - -export type LoreEntryNullableScalarRelationFilter = { - is?: Prisma.LoreEntryWhereInput | null - isNot?: Prisma.LoreEntryWhereInput | null -} - -export type LoreEntryCreateNestedManyWithoutAuthorInput = { - create?: Prisma.XOR | Prisma.LoreEntryCreateWithoutAuthorInput[] | Prisma.LoreEntryUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutAuthorInput | Prisma.LoreEntryCreateOrConnectWithoutAuthorInput[] - createMany?: Prisma.LoreEntryCreateManyAuthorInputEnvelope - connect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] -} - -export type LoreEntryUncheckedCreateNestedManyWithoutAuthorInput = { - create?: Prisma.XOR | Prisma.LoreEntryCreateWithoutAuthorInput[] | Prisma.LoreEntryUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutAuthorInput | Prisma.LoreEntryCreateOrConnectWithoutAuthorInput[] - createMany?: Prisma.LoreEntryCreateManyAuthorInputEnvelope - connect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] -} - -export type LoreEntryUpdateManyWithoutAuthorNestedInput = { - create?: Prisma.XOR | Prisma.LoreEntryCreateWithoutAuthorInput[] | Prisma.LoreEntryUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutAuthorInput | Prisma.LoreEntryCreateOrConnectWithoutAuthorInput[] - upsert?: Prisma.LoreEntryUpsertWithWhereUniqueWithoutAuthorInput | Prisma.LoreEntryUpsertWithWhereUniqueWithoutAuthorInput[] - createMany?: Prisma.LoreEntryCreateManyAuthorInputEnvelope - set?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - disconnect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - delete?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - connect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - update?: Prisma.LoreEntryUpdateWithWhereUniqueWithoutAuthorInput | Prisma.LoreEntryUpdateWithWhereUniqueWithoutAuthorInput[] - updateMany?: Prisma.LoreEntryUpdateManyWithWhereWithoutAuthorInput | Prisma.LoreEntryUpdateManyWithWhereWithoutAuthorInput[] - deleteMany?: Prisma.LoreEntryScalarWhereInput | Prisma.LoreEntryScalarWhereInput[] -} - -export type LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput = { - create?: Prisma.XOR | Prisma.LoreEntryCreateWithoutAuthorInput[] | Prisma.LoreEntryUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutAuthorInput | Prisma.LoreEntryCreateOrConnectWithoutAuthorInput[] - upsert?: Prisma.LoreEntryUpsertWithWhereUniqueWithoutAuthorInput | Prisma.LoreEntryUpsertWithWhereUniqueWithoutAuthorInput[] - createMany?: Prisma.LoreEntryCreateManyAuthorInputEnvelope - set?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - disconnect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - delete?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - connect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - update?: Prisma.LoreEntryUpdateWithWhereUniqueWithoutAuthorInput | Prisma.LoreEntryUpdateWithWhereUniqueWithoutAuthorInput[] - updateMany?: Prisma.LoreEntryUpdateManyWithWhereWithoutAuthorInput | Prisma.LoreEntryUpdateManyWithWhereWithoutAuthorInput[] - deleteMany?: Prisma.LoreEntryScalarWhereInput | Prisma.LoreEntryScalarWhereInput[] -} - -export type LoreEntryCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.LoreEntryCreateWithoutWorldInput[] | Prisma.LoreEntryUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutWorldInput | Prisma.LoreEntryCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.LoreEntryCreateManyWorldInputEnvelope - connect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] -} - -export type LoreEntryUncheckedCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.LoreEntryCreateWithoutWorldInput[] | Prisma.LoreEntryUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutWorldInput | Prisma.LoreEntryCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.LoreEntryCreateManyWorldInputEnvelope - connect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] -} - -export type LoreEntryUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.LoreEntryCreateWithoutWorldInput[] | Prisma.LoreEntryUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutWorldInput | Prisma.LoreEntryCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.LoreEntryUpsertWithWhereUniqueWithoutWorldInput | Prisma.LoreEntryUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.LoreEntryCreateManyWorldInputEnvelope - set?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - disconnect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - delete?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - connect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - update?: Prisma.LoreEntryUpdateWithWhereUniqueWithoutWorldInput | Prisma.LoreEntryUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.LoreEntryUpdateManyWithWhereWithoutWorldInput | Prisma.LoreEntryUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.LoreEntryScalarWhereInput | Prisma.LoreEntryScalarWhereInput[] -} - -export type LoreEntryUncheckedUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.LoreEntryCreateWithoutWorldInput[] | Prisma.LoreEntryUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutWorldInput | Prisma.LoreEntryCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.LoreEntryUpsertWithWhereUniqueWithoutWorldInput | Prisma.LoreEntryUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.LoreEntryCreateManyWorldInputEnvelope - set?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - disconnect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - delete?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - connect?: Prisma.LoreEntryWhereUniqueInput | Prisma.LoreEntryWhereUniqueInput[] - update?: Prisma.LoreEntryUpdateWithWhereUniqueWithoutWorldInput | Prisma.LoreEntryUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.LoreEntryUpdateManyWithWhereWithoutWorldInput | Prisma.LoreEntryUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.LoreEntryScalarWhereInput | Prisma.LoreEntryScalarWhereInput[] -} - -export type EnumLoreTypeFieldUpdateOperationsInput = { - set?: $Enums.LoreType -} - -export type EnumLoreStatusFieldUpdateOperationsInput = { - set?: $Enums.LoreStatus -} - -export type LoreEntryCreateNestedOneWithoutOutgoingRelationsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutOutgoingRelationsInput - connect?: Prisma.LoreEntryWhereUniqueInput -} - -export type LoreEntryCreateNestedOneWithoutIncomingRelationsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutIncomingRelationsInput - connect?: Prisma.LoreEntryWhereUniqueInput -} - -export type LoreEntryUpdateOneRequiredWithoutOutgoingRelationsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutOutgoingRelationsInput - upsert?: Prisma.LoreEntryUpsertWithoutOutgoingRelationsInput - connect?: Prisma.LoreEntryWhereUniqueInput - update?: Prisma.XOR, Prisma.LoreEntryUncheckedUpdateWithoutOutgoingRelationsInput> -} - -export type LoreEntryUpdateOneRequiredWithoutIncomingRelationsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutIncomingRelationsInput - upsert?: Prisma.LoreEntryUpsertWithoutIncomingRelationsInput - connect?: Prisma.LoreEntryWhereUniqueInput - update?: Prisma.XOR, Prisma.LoreEntryUncheckedUpdateWithoutIncomingRelationsInput> -} - -export type LoreEntryCreateNestedOneWithoutTargetProposalsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutTargetProposalsInput - connect?: Prisma.LoreEntryWhereUniqueInput -} - -export type LoreEntryCreateNestedOneWithoutResultingProposalsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutResultingProposalsInput - connect?: Prisma.LoreEntryWhereUniqueInput -} - -export type LoreEntryUpdateOneWithoutTargetProposalsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutTargetProposalsInput - upsert?: Prisma.LoreEntryUpsertWithoutTargetProposalsInput - disconnect?: Prisma.LoreEntryWhereInput | boolean - delete?: Prisma.LoreEntryWhereInput | boolean - connect?: Prisma.LoreEntryWhereUniqueInput - update?: Prisma.XOR, Prisma.LoreEntryUncheckedUpdateWithoutTargetProposalsInput> -} - -export type LoreEntryUpdateOneWithoutResultingProposalsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutResultingProposalsInput - upsert?: Prisma.LoreEntryUpsertWithoutResultingProposalsInput - disconnect?: Prisma.LoreEntryWhereInput | boolean - delete?: Prisma.LoreEntryWhereInput | boolean - connect?: Prisma.LoreEntryWhereUniqueInput - update?: Prisma.XOR, Prisma.LoreEntryUncheckedUpdateWithoutResultingProposalsInput> -} - -export type LoreEntryCreateNestedOneWithoutHiveReferenceInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutHiveReferenceInput - connect?: Prisma.LoreEntryWhereUniqueInput -} - -export type LoreEntryUncheckedCreateNestedOneWithoutHiveReferenceInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutHiveReferenceInput - connect?: Prisma.LoreEntryWhereUniqueInput -} - -export type LoreEntryUpdateOneWithoutHiveReferenceNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutHiveReferenceInput - upsert?: Prisma.LoreEntryUpsertWithoutHiveReferenceInput - disconnect?: Prisma.LoreEntryWhereInput | boolean - delete?: Prisma.LoreEntryWhereInput | boolean - connect?: Prisma.LoreEntryWhereUniqueInput - update?: Prisma.XOR, Prisma.LoreEntryUncheckedUpdateWithoutHiveReferenceInput> -} - -export type LoreEntryUncheckedUpdateOneWithoutHiveReferenceNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.LoreEntryCreateOrConnectWithoutHiveReferenceInput - upsert?: Prisma.LoreEntryUpsertWithoutHiveReferenceInput - disconnect?: Prisma.LoreEntryWhereInput | boolean - delete?: Prisma.LoreEntryWhereInput | boolean - connect?: Prisma.LoreEntryWhereUniqueInput - update?: Prisma.XOR, Prisma.LoreEntryUncheckedUpdateWithoutHiveReferenceInput> -} - -export type LoreEntryCreateWithoutAuthorInput = { - id?: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutLoreEntriesInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutLoreEntryInput - outgoingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryUncheckedCreateWithoutAuthorInput = { - id?: string - worldId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryCreateOrConnectWithoutAuthorInput = { - where: Prisma.LoreEntryWhereUniqueInput - create: Prisma.XOR -} - -export type LoreEntryCreateManyAuthorInputEnvelope = { - data: Prisma.LoreEntryCreateManyAuthorInput | Prisma.LoreEntryCreateManyAuthorInput[] - skipDuplicates?: boolean -} - -export type LoreEntryUpsertWithWhereUniqueWithoutAuthorInput = { - where: Prisma.LoreEntryWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type LoreEntryUpdateWithWhereUniqueWithoutAuthorInput = { - where: Prisma.LoreEntryWhereUniqueInput - data: Prisma.XOR -} - -export type LoreEntryUpdateManyWithWhereWithoutAuthorInput = { - where: Prisma.LoreEntryScalarWhereInput - data: Prisma.XOR -} - -export type LoreEntryScalarWhereInput = { - AND?: Prisma.LoreEntryScalarWhereInput | Prisma.LoreEntryScalarWhereInput[] - OR?: Prisma.LoreEntryScalarWhereInput[] - NOT?: Prisma.LoreEntryScalarWhereInput | Prisma.LoreEntryScalarWhereInput[] - id?: Prisma.StringFilter<"LoreEntry"> | string - worldId?: Prisma.StringFilter<"LoreEntry"> | string - authorId?: Prisma.StringFilter<"LoreEntry"> | string - title?: Prisma.StringFilter<"LoreEntry"> | string - slug?: Prisma.StringFilter<"LoreEntry"> | string - loreType?: Prisma.EnumLoreTypeFilter<"LoreEntry"> | $Enums.LoreType - content?: Prisma.JsonFilter<"LoreEntry"> - status?: Prisma.EnumLoreStatusFilter<"LoreEntry"> | $Enums.LoreStatus - publishedAt?: Prisma.DateTimeNullableFilter<"LoreEntry"> | Date | string | null - hiveReferenceId?: Prisma.StringNullableFilter<"LoreEntry"> | string | null - createdAt?: Prisma.DateTimeFilter<"LoreEntry"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"LoreEntry"> | Date | string -} - -export type LoreEntryCreateWithoutWorldInput = { - id?: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - author: Prisma.UserCreateNestedOneWithoutLoreEntriesInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutLoreEntryInput - outgoingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryUncheckedCreateWithoutWorldInput = { - id?: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryCreateOrConnectWithoutWorldInput = { - where: Prisma.LoreEntryWhereUniqueInput - create: Prisma.XOR -} - -export type LoreEntryCreateManyWorldInputEnvelope = { - data: Prisma.LoreEntryCreateManyWorldInput | Prisma.LoreEntryCreateManyWorldInput[] - skipDuplicates?: boolean -} - -export type LoreEntryUpsertWithWhereUniqueWithoutWorldInput = { - where: Prisma.LoreEntryWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type LoreEntryUpdateWithWhereUniqueWithoutWorldInput = { - where: Prisma.LoreEntryWhereUniqueInput - data: Prisma.XOR -} - -export type LoreEntryUpdateManyWithWhereWithoutWorldInput = { - where: Prisma.LoreEntryScalarWhereInput - data: Prisma.XOR -} - -export type LoreEntryCreateWithoutOutgoingRelationsInput = { - id?: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutLoreEntriesInput - author: Prisma.UserCreateNestedOneWithoutLoreEntriesInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutLoreEntryInput - incomingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryUncheckedCreateWithoutOutgoingRelationsInput = { - id?: string - worldId: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string - incomingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryCreateOrConnectWithoutOutgoingRelationsInput = { - where: Prisma.LoreEntryWhereUniqueInput - create: Prisma.XOR -} - -export type LoreEntryCreateWithoutIncomingRelationsInput = { - id?: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutLoreEntriesInput - author: Prisma.UserCreateNestedOneWithoutLoreEntriesInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutLoreEntryInput - outgoingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutSourceInput - targetProposals?: Prisma.ProposalCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryUncheckedCreateWithoutIncomingRelationsInput = { - id?: string - worldId: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutSourceInput - targetProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryCreateOrConnectWithoutIncomingRelationsInput = { - where: Prisma.LoreEntryWhereUniqueInput - create: Prisma.XOR -} - -export type LoreEntryUpsertWithoutOutgoingRelationsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.LoreEntryWhereInput -} - -export type LoreEntryUpdateToOneWithWhereWithoutOutgoingRelationsInput = { - where?: Prisma.LoreEntryWhereInput - data: Prisma.XOR -} - -export type LoreEntryUpdateWithoutOutgoingRelationsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutLoreEntriesNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutLoreEntriesNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutLoreEntryNestedInput - incomingRelations?: Prisma.LoreRelationshipUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUncheckedUpdateWithoutOutgoingRelationsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - incomingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUncheckedUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUpsertWithoutIncomingRelationsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.LoreEntryWhereInput -} - -export type LoreEntryUpdateToOneWithWhereWithoutIncomingRelationsInput = { - where?: Prisma.LoreEntryWhereInput - data: Prisma.XOR -} - -export type LoreEntryUpdateWithoutIncomingRelationsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutLoreEntriesNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutLoreEntriesNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutLoreEntryNestedInput - outgoingRelations?: Prisma.LoreRelationshipUpdateManyWithoutSourceNestedInput - targetProposals?: Prisma.ProposalUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUncheckedUpdateWithoutIncomingRelationsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutSourceNestedInput - targetProposals?: Prisma.ProposalUncheckedUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryCreateWithoutTargetProposalsInput = { - id?: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutLoreEntriesInput - author: Prisma.UserCreateNestedOneWithoutLoreEntriesInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutLoreEntryInput - outgoingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutTargetInput - resultingProposals?: Prisma.ProposalCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryUncheckedCreateWithoutTargetProposalsInput = { - id?: string - worldId: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutTargetInput - resultingProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryCreateOrConnectWithoutTargetProposalsInput = { - where: Prisma.LoreEntryWhereUniqueInput - create: Prisma.XOR -} - -export type LoreEntryCreateWithoutResultingProposalsInput = { - id?: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutLoreEntriesInput - author: Prisma.UserCreateNestedOneWithoutLoreEntriesInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutLoreEntryInput - outgoingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalCreateNestedManyWithoutTargetLoreEntryInput -} - -export type LoreEntryUncheckedCreateWithoutResultingProposalsInput = { - id?: string - worldId: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutTargetLoreEntryInput -} - -export type LoreEntryCreateOrConnectWithoutResultingProposalsInput = { - where: Prisma.LoreEntryWhereUniqueInput - create: Prisma.XOR -} - -export type LoreEntryUpsertWithoutTargetProposalsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.LoreEntryWhereInput -} - -export type LoreEntryUpdateToOneWithWhereWithoutTargetProposalsInput = { - where?: Prisma.LoreEntryWhereInput - data: Prisma.XOR -} - -export type LoreEntryUpdateWithoutTargetProposalsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutLoreEntriesNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutLoreEntriesNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutLoreEntryNestedInput - outgoingRelations?: Prisma.LoreRelationshipUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUpdateManyWithoutTargetNestedInput - resultingProposals?: Prisma.ProposalUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUncheckedUpdateWithoutTargetProposalsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutTargetNestedInput - resultingProposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUpsertWithoutResultingProposalsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.LoreEntryWhereInput -} - -export type LoreEntryUpdateToOneWithWhereWithoutResultingProposalsInput = { - where?: Prisma.LoreEntryWhereInput - data: Prisma.XOR -} - -export type LoreEntryUpdateWithoutResultingProposalsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutLoreEntriesNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutLoreEntriesNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutLoreEntryNestedInput - outgoingRelations?: Prisma.LoreRelationshipUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUpdateManyWithoutTargetLoreEntryNestedInput -} - -export type LoreEntryUncheckedUpdateWithoutResultingProposalsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUncheckedUpdateManyWithoutTargetLoreEntryNestedInput -} - -export type LoreEntryCreateWithoutHiveReferenceInput = { - id?: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutLoreEntriesInput - author: Prisma.UserCreateNestedOneWithoutLoreEntriesInput - outgoingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryUncheckedCreateWithoutHiveReferenceInput = { - id?: string - worldId: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutSourceInput - incomingRelations?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutTargetInput - targetProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutTargetLoreEntryInput - resultingProposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingLoreEntryInput -} - -export type LoreEntryCreateOrConnectWithoutHiveReferenceInput = { - where: Prisma.LoreEntryWhereUniqueInput - create: Prisma.XOR -} - -export type LoreEntryUpsertWithoutHiveReferenceInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.LoreEntryWhereInput -} - -export type LoreEntryUpdateToOneWithWhereWithoutHiveReferenceInput = { - where?: Prisma.LoreEntryWhereInput - data: Prisma.XOR -} - -export type LoreEntryUpdateWithoutHiveReferenceInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutLoreEntriesNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutLoreEntriesNestedInput - outgoingRelations?: Prisma.LoreRelationshipUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUncheckedUpdateWithoutHiveReferenceInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUncheckedUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryCreateManyAuthorInput = { - id?: string - worldId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreEntryUpdateWithoutAuthorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutLoreEntriesNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutLoreEntryNestedInput - outgoingRelations?: Prisma.LoreRelationshipUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUncheckedUpdateWithoutAuthorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUncheckedUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUncheckedUpdateManyWithoutAuthorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreEntryCreateManyWorldInput = { - id?: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: $Enums.LoreStatus - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreEntryUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - author?: Prisma.UserUpdateOneRequiredWithoutLoreEntriesNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutLoreEntryNestedInput - outgoingRelations?: Prisma.LoreRelationshipUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUncheckedUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - outgoingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutSourceNestedInput - incomingRelations?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutTargetNestedInput - targetProposals?: Prisma.ProposalUncheckedUpdateManyWithoutTargetLoreEntryNestedInput - resultingProposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingLoreEntryNestedInput -} - -export type LoreEntryUncheckedUpdateManyWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - loreType?: Prisma.EnumLoreTypeFieldUpdateOperationsInput | $Enums.LoreType - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - status?: Prisma.EnumLoreStatusFieldUpdateOperationsInput | $Enums.LoreStatus - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - -/** - * Count Type LoreEntryCountOutputType - */ - -export type LoreEntryCountOutputType = { - outgoingRelations: number - incomingRelations: number - targetProposals: number - resultingProposals: number -} - -export type LoreEntryCountOutputTypeSelect = { - outgoingRelations?: boolean | LoreEntryCountOutputTypeCountOutgoingRelationsArgs - incomingRelations?: boolean | LoreEntryCountOutputTypeCountIncomingRelationsArgs - targetProposals?: boolean | LoreEntryCountOutputTypeCountTargetProposalsArgs - resultingProposals?: boolean | LoreEntryCountOutputTypeCountResultingProposalsArgs -} - -/** - * LoreEntryCountOutputType without action - */ -export type LoreEntryCountOutputTypeDefaultArgs = { - /** - * Select specific fields to fetch from the LoreEntryCountOutputType - */ - select?: Prisma.LoreEntryCountOutputTypeSelect | null -} - -/** - * LoreEntryCountOutputType without action - */ -export type LoreEntryCountOutputTypeCountOutgoingRelationsArgs = { - where?: Prisma.LoreRelationshipWhereInput -} - -/** - * LoreEntryCountOutputType without action - */ -export type LoreEntryCountOutputTypeCountIncomingRelationsArgs = { - where?: Prisma.LoreRelationshipWhereInput -} - -/** - * LoreEntryCountOutputType without action - */ -export type LoreEntryCountOutputTypeCountTargetProposalsArgs = { - where?: Prisma.ProposalWhereInput -} - -/** - * LoreEntryCountOutputType without action - */ -export type LoreEntryCountOutputTypeCountResultingProposalsArgs = { - where?: Prisma.ProposalWhereInput -} - - -export type LoreEntrySelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - authorId?: boolean - title?: boolean - slug?: boolean - loreType?: boolean - content?: boolean - status?: boolean - publishedAt?: boolean - hiveReferenceId?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.LoreEntry$hiveReferenceArgs - outgoingRelations?: boolean | Prisma.LoreEntry$outgoingRelationsArgs - incomingRelations?: boolean | Prisma.LoreEntry$incomingRelationsArgs - targetProposals?: boolean | Prisma.LoreEntry$targetProposalsArgs - resultingProposals?: boolean | Prisma.LoreEntry$resultingProposalsArgs - _count?: boolean | Prisma.LoreEntryCountOutputTypeDefaultArgs -}, ExtArgs["result"]["loreEntry"]> - -export type LoreEntrySelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - authorId?: boolean - title?: boolean - slug?: boolean - loreType?: boolean - content?: boolean - status?: boolean - publishedAt?: boolean - hiveReferenceId?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.LoreEntry$hiveReferenceArgs -}, ExtArgs["result"]["loreEntry"]> - -export type LoreEntrySelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - authorId?: boolean - title?: boolean - slug?: boolean - loreType?: boolean - content?: boolean - status?: boolean - publishedAt?: boolean - hiveReferenceId?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.LoreEntry$hiveReferenceArgs -}, ExtArgs["result"]["loreEntry"]> - -export type LoreEntrySelectScalar = { - id?: boolean - worldId?: boolean - authorId?: boolean - title?: boolean - slug?: boolean - loreType?: boolean - content?: boolean - status?: boolean - publishedAt?: boolean - hiveReferenceId?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type LoreEntryOmit = runtime.Types.Extensions.GetOmit<"id" | "worldId" | "authorId" | "title" | "slug" | "loreType" | "content" | "status" | "publishedAt" | "hiveReferenceId" | "createdAt" | "updatedAt", ExtArgs["result"]["loreEntry"]> -export type LoreEntryInclude = { - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.LoreEntry$hiveReferenceArgs - outgoingRelations?: boolean | Prisma.LoreEntry$outgoingRelationsArgs - incomingRelations?: boolean | Prisma.LoreEntry$incomingRelationsArgs - targetProposals?: boolean | Prisma.LoreEntry$targetProposalsArgs - resultingProposals?: boolean | Prisma.LoreEntry$resultingProposalsArgs - _count?: boolean | Prisma.LoreEntryCountOutputTypeDefaultArgs -} -export type LoreEntryIncludeCreateManyAndReturn = { - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.LoreEntry$hiveReferenceArgs -} -export type LoreEntryIncludeUpdateManyAndReturn = { - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.LoreEntry$hiveReferenceArgs -} - -export type $LoreEntryPayload = { - name: "LoreEntry" - objects: { - world: Prisma.$WorldPayload - author: Prisma.$UserPayload - /** - * Published canon must be confirmed through an indexed HiveReference, not only this mutable row. - */ - hiveReference: Prisma.$HiveReferencePayload | null - outgoingRelations: Prisma.$LoreRelationshipPayload[] - incomingRelations: Prisma.$LoreRelationshipPayload[] - targetProposals: Prisma.$ProposalPayload[] - resultingProposals: Prisma.$ProposalPayload[] - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - worldId: string - authorId: string - title: string - slug: string - loreType: $Enums.LoreType - content: runtime.JsonValue - status: $Enums.LoreStatus - publishedAt: Date | null - hiveReferenceId: string | null - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["loreEntry"]> - composites: {} -} - -export type LoreEntryGetPayload = runtime.Types.Result.GetResult - -export type LoreEntryCountArgs = - Omit & { - select?: LoreEntryCountAggregateInputType | true - } - -export interface LoreEntryDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['LoreEntry'], meta: { name: 'LoreEntry' } } - /** - * Find zero or one LoreEntry that matches the filter. - * @param {LoreEntryFindUniqueArgs} args - Arguments to find a LoreEntry - * @example - * // Get one LoreEntry - * const loreEntry = await prisma.loreEntry.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__LoreEntryClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one LoreEntry that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {LoreEntryFindUniqueOrThrowArgs} args - Arguments to find a LoreEntry - * @example - * // Get one LoreEntry - * const loreEntry = await prisma.loreEntry.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__LoreEntryClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first LoreEntry 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 {LoreEntryFindFirstArgs} args - Arguments to find a LoreEntry - * @example - * // Get one LoreEntry - * const loreEntry = await prisma.loreEntry.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__LoreEntryClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first LoreEntry 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 {LoreEntryFindFirstOrThrowArgs} args - Arguments to find a LoreEntry - * @example - * // Get one LoreEntry - * const loreEntry = await prisma.loreEntry.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__LoreEntryClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more LoreEntries 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 {LoreEntryFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all LoreEntries - * const loreEntries = await prisma.loreEntry.findMany() - * - * // Get first 10 LoreEntries - * const loreEntries = await prisma.loreEntry.findMany({ take: 10 }) - * - * // Only select the `id` - * const loreEntryWithIdOnly = await prisma.loreEntry.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a LoreEntry. - * @param {LoreEntryCreateArgs} args - Arguments to create a LoreEntry. - * @example - * // Create one LoreEntry - * const LoreEntry = await prisma.loreEntry.create({ - * data: { - * // ... data to create a LoreEntry - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__LoreEntryClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many LoreEntries. - * @param {LoreEntryCreateManyArgs} args - Arguments to create many LoreEntries. - * @example - * // Create many LoreEntries - * const loreEntry = await prisma.loreEntry.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many LoreEntries and returns the data saved in the database. - * @param {LoreEntryCreateManyAndReturnArgs} args - Arguments to create many LoreEntries. - * @example - * // Create many LoreEntries - * const loreEntry = await prisma.loreEntry.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many LoreEntries and only return the `id` - * const loreEntryWithIdOnly = await prisma.loreEntry.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 LoreEntry. - * @param {LoreEntryDeleteArgs} args - Arguments to delete one LoreEntry. - * @example - * // Delete one LoreEntry - * const LoreEntry = await prisma.loreEntry.delete({ - * where: { - * // ... filter to delete one LoreEntry - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__LoreEntryClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one LoreEntry. - * @param {LoreEntryUpdateArgs} args - Arguments to update one LoreEntry. - * @example - * // Update one LoreEntry - * const loreEntry = await prisma.loreEntry.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__LoreEntryClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more LoreEntries. - * @param {LoreEntryDeleteManyArgs} args - Arguments to filter LoreEntries to delete. - * @example - * // Delete a few LoreEntries - * const { count } = await prisma.loreEntry.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more LoreEntries. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {LoreEntryUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many LoreEntries - * const loreEntry = await prisma.loreEntry.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more LoreEntries and returns the data updated in the database. - * @param {LoreEntryUpdateManyAndReturnArgs} args - Arguments to update many LoreEntries. - * @example - * // Update many LoreEntries - * const loreEntry = await prisma.loreEntry.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more LoreEntries and only return the `id` - * const loreEntryWithIdOnly = await prisma.loreEntry.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 LoreEntry. - * @param {LoreEntryUpsertArgs} args - Arguments to update or create a LoreEntry. - * @example - * // Update or create a LoreEntry - * const loreEntry = await prisma.loreEntry.upsert({ - * create: { - * // ... data to create a LoreEntry - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the LoreEntry we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__LoreEntryClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of LoreEntries. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {LoreEntryCountArgs} args - Arguments to filter LoreEntries to count. - * @example - * // Count the number of LoreEntries - * const count = await prisma.loreEntry.count({ - * where: { - * // ... the filter for the LoreEntries 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 LoreEntry. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {LoreEntryAggregateArgs} 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 LoreEntry. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {LoreEntryGroupByArgs} 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 LoreEntryGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: LoreEntryGroupByArgs['orderBy'] } - : { orderBy?: LoreEntryGroupByArgs['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 ? GetLoreEntryGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the LoreEntry model - */ -readonly fields: LoreEntryFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for LoreEntry. - * 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__LoreEntryClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - world = {}>(args?: Prisma.Subset>): Prisma.Prisma__WorldClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - author = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - hiveReference = {}>(args?: Prisma.Subset>): Prisma.Prisma__HiveReferenceClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - outgoingRelations = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - incomingRelations = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - targetProposals = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - resultingProposals = {}>(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 LoreEntry model - */ -export interface LoreEntryFieldRefs { - readonly id: Prisma.FieldRef<"LoreEntry", 'String'> - readonly worldId: Prisma.FieldRef<"LoreEntry", 'String'> - readonly authorId: Prisma.FieldRef<"LoreEntry", 'String'> - readonly title: Prisma.FieldRef<"LoreEntry", 'String'> - readonly slug: Prisma.FieldRef<"LoreEntry", 'String'> - readonly loreType: Prisma.FieldRef<"LoreEntry", 'LoreType'> - readonly content: Prisma.FieldRef<"LoreEntry", 'Json'> - readonly status: Prisma.FieldRef<"LoreEntry", 'LoreStatus'> - readonly publishedAt: Prisma.FieldRef<"LoreEntry", 'DateTime'> - readonly hiveReferenceId: Prisma.FieldRef<"LoreEntry", 'String'> - readonly createdAt: Prisma.FieldRef<"LoreEntry", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"LoreEntry", 'DateTime'> -} - - -// Custom InputTypes -/** - * LoreEntry findUnique - */ -export type LoreEntryFindUniqueArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - /** - * Filter, which LoreEntry to fetch. - */ - where: Prisma.LoreEntryWhereUniqueInput -} - -/** - * LoreEntry findUniqueOrThrow - */ -export type LoreEntryFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - /** - * Filter, which LoreEntry to fetch. - */ - where: Prisma.LoreEntryWhereUniqueInput -} - -/** - * LoreEntry findFirst - */ -export type LoreEntryFindFirstArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - /** - * Filter, which LoreEntry to fetch. - */ - where?: Prisma.LoreEntryWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of LoreEntries to fetch. - */ - orderBy?: Prisma.LoreEntryOrderByWithRelationInput | Prisma.LoreEntryOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for LoreEntries. - */ - cursor?: Prisma.LoreEntryWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` LoreEntries 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` LoreEntries. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of LoreEntries. - */ - distinct?: Prisma.LoreEntryScalarFieldEnum | Prisma.LoreEntryScalarFieldEnum[] -} - -/** - * LoreEntry findFirstOrThrow - */ -export type LoreEntryFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - /** - * Filter, which LoreEntry to fetch. - */ - where?: Prisma.LoreEntryWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of LoreEntries to fetch. - */ - orderBy?: Prisma.LoreEntryOrderByWithRelationInput | Prisma.LoreEntryOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for LoreEntries. - */ - cursor?: Prisma.LoreEntryWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` LoreEntries 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` LoreEntries. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of LoreEntries. - */ - distinct?: Prisma.LoreEntryScalarFieldEnum | Prisma.LoreEntryScalarFieldEnum[] -} - -/** - * LoreEntry findMany - */ -export type LoreEntryFindManyArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - /** - * Filter, which LoreEntries to fetch. - */ - where?: Prisma.LoreEntryWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of LoreEntries to fetch. - */ - orderBy?: Prisma.LoreEntryOrderByWithRelationInput | Prisma.LoreEntryOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing LoreEntries. - */ - cursor?: Prisma.LoreEntryWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` LoreEntries 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` LoreEntries. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of LoreEntries. - */ - distinct?: Prisma.LoreEntryScalarFieldEnum | Prisma.LoreEntryScalarFieldEnum[] -} - -/** - * LoreEntry create - */ -export type LoreEntryCreateArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - /** - * The data needed to create a LoreEntry. - */ - data: Prisma.XOR -} - -/** - * LoreEntry createMany - */ -export type LoreEntryCreateManyArgs = { - /** - * The data used to create many LoreEntries. - */ - data: Prisma.LoreEntryCreateManyInput | Prisma.LoreEntryCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * LoreEntry createManyAndReturn - */ -export type LoreEntryCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelectCreateManyAndReturn | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * The data used to create many LoreEntries. - */ - data: Prisma.LoreEntryCreateManyInput | Prisma.LoreEntryCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryIncludeCreateManyAndReturn | null -} - -/** - * LoreEntry update - */ -export type LoreEntryUpdateArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - /** - * The data needed to update a LoreEntry. - */ - data: Prisma.XOR - /** - * Choose, which LoreEntry to update. - */ - where: Prisma.LoreEntryWhereUniqueInput -} - -/** - * LoreEntry updateMany - */ -export type LoreEntryUpdateManyArgs = { - /** - * The data used to update LoreEntries. - */ - data: Prisma.XOR - /** - * Filter which LoreEntries to update - */ - where?: Prisma.LoreEntryWhereInput - /** - * Limit how many LoreEntries to update. - */ - limit?: number -} - -/** - * LoreEntry updateManyAndReturn - */ -export type LoreEntryUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelectUpdateManyAndReturn | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * The data used to update LoreEntries. - */ - data: Prisma.XOR - /** - * Filter which LoreEntries to update - */ - where?: Prisma.LoreEntryWhereInput - /** - * Limit how many LoreEntries to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryIncludeUpdateManyAndReturn | null -} - -/** - * LoreEntry upsert - */ -export type LoreEntryUpsertArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - /** - * The filter to search for the LoreEntry to update in case it exists. - */ - where: Prisma.LoreEntryWhereUniqueInput - /** - * In case the LoreEntry found by the `where` argument doesn't exist, create a new LoreEntry with this data. - */ - create: Prisma.XOR - /** - * In case the LoreEntry was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * LoreEntry delete - */ -export type LoreEntryDeleteArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - /** - * Filter which LoreEntry to delete. - */ - where: Prisma.LoreEntryWhereUniqueInput -} - -/** - * LoreEntry deleteMany - */ -export type LoreEntryDeleteManyArgs = { - /** - * Filter which LoreEntries to delete - */ - where?: Prisma.LoreEntryWhereInput - /** - * Limit how many LoreEntries to delete. - */ - limit?: number -} - -/** - * LoreEntry.hiveReference - */ -export type LoreEntry$hiveReferenceArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - where?: Prisma.HiveReferenceWhereInput -} - -/** - * LoreEntry.outgoingRelations - */ -export type LoreEntry$outgoingRelationsArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - where?: Prisma.LoreRelationshipWhereInput - orderBy?: Prisma.LoreRelationshipOrderByWithRelationInput | Prisma.LoreRelationshipOrderByWithRelationInput[] - cursor?: Prisma.LoreRelationshipWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.LoreRelationshipScalarFieldEnum | Prisma.LoreRelationshipScalarFieldEnum[] -} - -/** - * LoreEntry.incomingRelations - */ -export type LoreEntry$incomingRelationsArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - where?: Prisma.LoreRelationshipWhereInput - orderBy?: Prisma.LoreRelationshipOrderByWithRelationInput | Prisma.LoreRelationshipOrderByWithRelationInput[] - cursor?: Prisma.LoreRelationshipWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.LoreRelationshipScalarFieldEnum | Prisma.LoreRelationshipScalarFieldEnum[] -} - -/** - * LoreEntry.targetProposals - */ -export type LoreEntry$targetProposalsArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - where?: Prisma.ProposalWhereInput - orderBy?: Prisma.ProposalOrderByWithRelationInput | Prisma.ProposalOrderByWithRelationInput[] - cursor?: Prisma.ProposalWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.ProposalScalarFieldEnum | Prisma.ProposalScalarFieldEnum[] -} - -/** - * LoreEntry.resultingProposals - */ -export type LoreEntry$resultingProposalsArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - where?: Prisma.ProposalWhereInput - orderBy?: Prisma.ProposalOrderByWithRelationInput | Prisma.ProposalOrderByWithRelationInput[] - cursor?: Prisma.ProposalWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.ProposalScalarFieldEnum | Prisma.ProposalScalarFieldEnum[] -} - -/** - * LoreEntry without action - */ -export type LoreEntryDefaultArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null -} diff --git a/apps/api/src/generated/prisma/models/LoreRelationship.ts b/apps/api/src/generated/prisma/models/LoreRelationship.ts deleted file mode 100644 index 87762fa..0000000 --- a/apps/api/src/generated/prisma/models/LoreRelationship.ts +++ /dev/null @@ -1,1728 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `LoreRelationship` 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 LoreRelationship - * - */ -export type LoreRelationshipModel = runtime.Types.Result.DefaultSelection - -export type AggregateLoreRelationship = { - _count: LoreRelationshipCountAggregateOutputType | null - _min: LoreRelationshipMinAggregateOutputType | null - _max: LoreRelationshipMaxAggregateOutputType | null -} - -export type LoreRelationshipMinAggregateOutputType = { - id: string | null - worldId: string | null - sourceId: string | null - targetId: string | null - relationType: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type LoreRelationshipMaxAggregateOutputType = { - id: string | null - worldId: string | null - sourceId: string | null - targetId: string | null - relationType: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type LoreRelationshipCountAggregateOutputType = { - id: number - worldId: number - sourceId: number - targetId: number - relationType: number - metadata: number - createdAt: number - updatedAt: number - _all: number -} - - -export type LoreRelationshipMinAggregateInputType = { - id?: true - worldId?: true - sourceId?: true - targetId?: true - relationType?: true - createdAt?: true - updatedAt?: true -} - -export type LoreRelationshipMaxAggregateInputType = { - id?: true - worldId?: true - sourceId?: true - targetId?: true - relationType?: true - createdAt?: true - updatedAt?: true -} - -export type LoreRelationshipCountAggregateInputType = { - id?: true - worldId?: true - sourceId?: true - targetId?: true - relationType?: true - metadata?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type LoreRelationshipAggregateArgs = { - /** - * Filter which LoreRelationship to aggregate. - */ - where?: Prisma.LoreRelationshipWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of LoreRelationships to fetch. - */ - orderBy?: Prisma.LoreRelationshipOrderByWithRelationInput | Prisma.LoreRelationshipOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.LoreRelationshipWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` LoreRelationships 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` LoreRelationships. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned LoreRelationships - **/ - _count?: true | LoreRelationshipCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: LoreRelationshipMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: LoreRelationshipMaxAggregateInputType -} - -export type GetLoreRelationshipAggregateType = { - [P in keyof T & keyof AggregateLoreRelationship]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type LoreRelationshipGroupByArgs = { - where?: Prisma.LoreRelationshipWhereInput - orderBy?: Prisma.LoreRelationshipOrderByWithAggregationInput | Prisma.LoreRelationshipOrderByWithAggregationInput[] - by: Prisma.LoreRelationshipScalarFieldEnum[] | Prisma.LoreRelationshipScalarFieldEnum - having?: Prisma.LoreRelationshipScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: LoreRelationshipCountAggregateInputType | true - _min?: LoreRelationshipMinAggregateInputType - _max?: LoreRelationshipMaxAggregateInputType -} - -export type LoreRelationshipGroupByOutputType = { - id: string - worldId: string - sourceId: string - targetId: string - relationType: string - metadata: runtime.JsonValue | null - createdAt: Date - updatedAt: Date - _count: LoreRelationshipCountAggregateOutputType | null - _min: LoreRelationshipMinAggregateOutputType | null - _max: LoreRelationshipMaxAggregateOutputType | null -} - -export type GetLoreRelationshipGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof LoreRelationshipGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type LoreRelationshipWhereInput = { - AND?: Prisma.LoreRelationshipWhereInput | Prisma.LoreRelationshipWhereInput[] - OR?: Prisma.LoreRelationshipWhereInput[] - NOT?: Prisma.LoreRelationshipWhereInput | Prisma.LoreRelationshipWhereInput[] - id?: Prisma.StringFilter<"LoreRelationship"> | string - worldId?: Prisma.StringFilter<"LoreRelationship"> | string - sourceId?: Prisma.StringFilter<"LoreRelationship"> | string - targetId?: Prisma.StringFilter<"LoreRelationship"> | string - relationType?: Prisma.StringFilter<"LoreRelationship"> | string - metadata?: Prisma.JsonNullableFilter<"LoreRelationship"> - createdAt?: Prisma.DateTimeFilter<"LoreRelationship"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"LoreRelationship"> | Date | string - world?: Prisma.XOR - source?: Prisma.XOR - target?: Prisma.XOR -} - -export type LoreRelationshipOrderByWithRelationInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - sourceId?: Prisma.SortOrder - targetId?: Prisma.SortOrder - relationType?: Prisma.SortOrder - metadata?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - world?: Prisma.WorldOrderByWithRelationInput - source?: Prisma.LoreEntryOrderByWithRelationInput - target?: Prisma.LoreEntryOrderByWithRelationInput -} - -export type LoreRelationshipWhereUniqueInput = Prisma.AtLeast<{ - id?: string - worldId_sourceId_targetId_relationType?: Prisma.LoreRelationshipWorldIdSourceIdTargetIdRelationTypeCompoundUniqueInput - AND?: Prisma.LoreRelationshipWhereInput | Prisma.LoreRelationshipWhereInput[] - OR?: Prisma.LoreRelationshipWhereInput[] - NOT?: Prisma.LoreRelationshipWhereInput | Prisma.LoreRelationshipWhereInput[] - worldId?: Prisma.StringFilter<"LoreRelationship"> | string - sourceId?: Prisma.StringFilter<"LoreRelationship"> | string - targetId?: Prisma.StringFilter<"LoreRelationship"> | string - relationType?: Prisma.StringFilter<"LoreRelationship"> | string - metadata?: Prisma.JsonNullableFilter<"LoreRelationship"> - createdAt?: Prisma.DateTimeFilter<"LoreRelationship"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"LoreRelationship"> | Date | string - world?: Prisma.XOR - source?: Prisma.XOR - target?: Prisma.XOR -}, "id" | "worldId_sourceId_targetId_relationType"> - -export type LoreRelationshipOrderByWithAggregationInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - sourceId?: Prisma.SortOrder - targetId?: Prisma.SortOrder - relationType?: Prisma.SortOrder - metadata?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.LoreRelationshipCountOrderByAggregateInput - _max?: Prisma.LoreRelationshipMaxOrderByAggregateInput - _min?: Prisma.LoreRelationshipMinOrderByAggregateInput -} - -export type LoreRelationshipScalarWhereWithAggregatesInput = { - AND?: Prisma.LoreRelationshipScalarWhereWithAggregatesInput | Prisma.LoreRelationshipScalarWhereWithAggregatesInput[] - OR?: Prisma.LoreRelationshipScalarWhereWithAggregatesInput[] - NOT?: Prisma.LoreRelationshipScalarWhereWithAggregatesInput | Prisma.LoreRelationshipScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"LoreRelationship"> | string - worldId?: Prisma.StringWithAggregatesFilter<"LoreRelationship"> | string - sourceId?: Prisma.StringWithAggregatesFilter<"LoreRelationship"> | string - targetId?: Prisma.StringWithAggregatesFilter<"LoreRelationship"> | string - relationType?: Prisma.StringWithAggregatesFilter<"LoreRelationship"> | string - metadata?: Prisma.JsonNullableWithAggregatesFilter<"LoreRelationship"> - createdAt?: Prisma.DateTimeWithAggregatesFilter<"LoreRelationship"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"LoreRelationship"> | Date | string -} - -export type LoreRelationshipCreateInput = { - id?: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutLoreRelationshipsInput - source: Prisma.LoreEntryCreateNestedOneWithoutOutgoingRelationsInput - target: Prisma.LoreEntryCreateNestedOneWithoutIncomingRelationsInput -} - -export type LoreRelationshipUncheckedCreateInput = { - id?: string - worldId: string - sourceId: string - targetId: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreRelationshipUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutLoreRelationshipsNestedInput - source?: Prisma.LoreEntryUpdateOneRequiredWithoutOutgoingRelationsNestedInput - target?: Prisma.LoreEntryUpdateOneRequiredWithoutIncomingRelationsNestedInput -} - -export type LoreRelationshipUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - sourceId?: Prisma.StringFieldUpdateOperationsInput | string - targetId?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreRelationshipCreateManyInput = { - id?: string - worldId: string - sourceId: string - targetId: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreRelationshipUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreRelationshipUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - sourceId?: Prisma.StringFieldUpdateOperationsInput | string - targetId?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreRelationshipListRelationFilter = { - every?: Prisma.LoreRelationshipWhereInput - some?: Prisma.LoreRelationshipWhereInput - none?: Prisma.LoreRelationshipWhereInput -} - -export type LoreRelationshipOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type LoreRelationshipWorldIdSourceIdTargetIdRelationTypeCompoundUniqueInput = { - worldId: string - sourceId: string - targetId: string - relationType: string -} - -export type LoreRelationshipCountOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - sourceId?: Prisma.SortOrder - targetId?: Prisma.SortOrder - relationType?: Prisma.SortOrder - metadata?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type LoreRelationshipMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - sourceId?: Prisma.SortOrder - targetId?: Prisma.SortOrder - relationType?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type LoreRelationshipMinOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - sourceId?: Prisma.SortOrder - targetId?: Prisma.SortOrder - relationType?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type LoreRelationshipCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutWorldInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutWorldInput | Prisma.LoreRelationshipCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.LoreRelationshipCreateManyWorldInputEnvelope - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] -} - -export type LoreRelationshipUncheckedCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutWorldInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutWorldInput | Prisma.LoreRelationshipCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.LoreRelationshipCreateManyWorldInputEnvelope - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] -} - -export type LoreRelationshipUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutWorldInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutWorldInput | Prisma.LoreRelationshipCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutWorldInput | Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.LoreRelationshipCreateManyWorldInputEnvelope - set?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - disconnect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - delete?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - update?: Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutWorldInput | Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.LoreRelationshipUpdateManyWithWhereWithoutWorldInput | Prisma.LoreRelationshipUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.LoreRelationshipScalarWhereInput | Prisma.LoreRelationshipScalarWhereInput[] -} - -export type LoreRelationshipUncheckedUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutWorldInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutWorldInput | Prisma.LoreRelationshipCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutWorldInput | Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.LoreRelationshipCreateManyWorldInputEnvelope - set?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - disconnect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - delete?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - update?: Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutWorldInput | Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.LoreRelationshipUpdateManyWithWhereWithoutWorldInput | Prisma.LoreRelationshipUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.LoreRelationshipScalarWhereInput | Prisma.LoreRelationshipScalarWhereInput[] -} - -export type LoreRelationshipCreateNestedManyWithoutSourceInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutSourceInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutSourceInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutSourceInput | Prisma.LoreRelationshipCreateOrConnectWithoutSourceInput[] - createMany?: Prisma.LoreRelationshipCreateManySourceInputEnvelope - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] -} - -export type LoreRelationshipCreateNestedManyWithoutTargetInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutTargetInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutTargetInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutTargetInput | Prisma.LoreRelationshipCreateOrConnectWithoutTargetInput[] - createMany?: Prisma.LoreRelationshipCreateManyTargetInputEnvelope - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] -} - -export type LoreRelationshipUncheckedCreateNestedManyWithoutSourceInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutSourceInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutSourceInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutSourceInput | Prisma.LoreRelationshipCreateOrConnectWithoutSourceInput[] - createMany?: Prisma.LoreRelationshipCreateManySourceInputEnvelope - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] -} - -export type LoreRelationshipUncheckedCreateNestedManyWithoutTargetInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutTargetInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutTargetInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutTargetInput | Prisma.LoreRelationshipCreateOrConnectWithoutTargetInput[] - createMany?: Prisma.LoreRelationshipCreateManyTargetInputEnvelope - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] -} - -export type LoreRelationshipUpdateManyWithoutSourceNestedInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutSourceInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutSourceInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutSourceInput | Prisma.LoreRelationshipCreateOrConnectWithoutSourceInput[] - upsert?: Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutSourceInput | Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutSourceInput[] - createMany?: Prisma.LoreRelationshipCreateManySourceInputEnvelope - set?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - disconnect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - delete?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - update?: Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutSourceInput | Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutSourceInput[] - updateMany?: Prisma.LoreRelationshipUpdateManyWithWhereWithoutSourceInput | Prisma.LoreRelationshipUpdateManyWithWhereWithoutSourceInput[] - deleteMany?: Prisma.LoreRelationshipScalarWhereInput | Prisma.LoreRelationshipScalarWhereInput[] -} - -export type LoreRelationshipUpdateManyWithoutTargetNestedInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutTargetInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutTargetInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutTargetInput | Prisma.LoreRelationshipCreateOrConnectWithoutTargetInput[] - upsert?: Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutTargetInput | Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutTargetInput[] - createMany?: Prisma.LoreRelationshipCreateManyTargetInputEnvelope - set?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - disconnect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - delete?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - update?: Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutTargetInput | Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutTargetInput[] - updateMany?: Prisma.LoreRelationshipUpdateManyWithWhereWithoutTargetInput | Prisma.LoreRelationshipUpdateManyWithWhereWithoutTargetInput[] - deleteMany?: Prisma.LoreRelationshipScalarWhereInput | Prisma.LoreRelationshipScalarWhereInput[] -} - -export type LoreRelationshipUncheckedUpdateManyWithoutSourceNestedInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutSourceInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutSourceInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutSourceInput | Prisma.LoreRelationshipCreateOrConnectWithoutSourceInput[] - upsert?: Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutSourceInput | Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutSourceInput[] - createMany?: Prisma.LoreRelationshipCreateManySourceInputEnvelope - set?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - disconnect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - delete?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - update?: Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutSourceInput | Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutSourceInput[] - updateMany?: Prisma.LoreRelationshipUpdateManyWithWhereWithoutSourceInput | Prisma.LoreRelationshipUpdateManyWithWhereWithoutSourceInput[] - deleteMany?: Prisma.LoreRelationshipScalarWhereInput | Prisma.LoreRelationshipScalarWhereInput[] -} - -export type LoreRelationshipUncheckedUpdateManyWithoutTargetNestedInput = { - create?: Prisma.XOR | Prisma.LoreRelationshipCreateWithoutTargetInput[] | Prisma.LoreRelationshipUncheckedCreateWithoutTargetInput[] - connectOrCreate?: Prisma.LoreRelationshipCreateOrConnectWithoutTargetInput | Prisma.LoreRelationshipCreateOrConnectWithoutTargetInput[] - upsert?: Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutTargetInput | Prisma.LoreRelationshipUpsertWithWhereUniqueWithoutTargetInput[] - createMany?: Prisma.LoreRelationshipCreateManyTargetInputEnvelope - set?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - disconnect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - delete?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - connect?: Prisma.LoreRelationshipWhereUniqueInput | Prisma.LoreRelationshipWhereUniqueInput[] - update?: Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutTargetInput | Prisma.LoreRelationshipUpdateWithWhereUniqueWithoutTargetInput[] - updateMany?: Prisma.LoreRelationshipUpdateManyWithWhereWithoutTargetInput | Prisma.LoreRelationshipUpdateManyWithWhereWithoutTargetInput[] - deleteMany?: Prisma.LoreRelationshipScalarWhereInput | Prisma.LoreRelationshipScalarWhereInput[] -} - -export type LoreRelationshipCreateWithoutWorldInput = { - id?: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string - source: Prisma.LoreEntryCreateNestedOneWithoutOutgoingRelationsInput - target: Prisma.LoreEntryCreateNestedOneWithoutIncomingRelationsInput -} - -export type LoreRelationshipUncheckedCreateWithoutWorldInput = { - id?: string - sourceId: string - targetId: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreRelationshipCreateOrConnectWithoutWorldInput = { - where: Prisma.LoreRelationshipWhereUniqueInput - create: Prisma.XOR -} - -export type LoreRelationshipCreateManyWorldInputEnvelope = { - data: Prisma.LoreRelationshipCreateManyWorldInput | Prisma.LoreRelationshipCreateManyWorldInput[] - skipDuplicates?: boolean -} - -export type LoreRelationshipUpsertWithWhereUniqueWithoutWorldInput = { - where: Prisma.LoreRelationshipWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type LoreRelationshipUpdateWithWhereUniqueWithoutWorldInput = { - where: Prisma.LoreRelationshipWhereUniqueInput - data: Prisma.XOR -} - -export type LoreRelationshipUpdateManyWithWhereWithoutWorldInput = { - where: Prisma.LoreRelationshipScalarWhereInput - data: Prisma.XOR -} - -export type LoreRelationshipScalarWhereInput = { - AND?: Prisma.LoreRelationshipScalarWhereInput | Prisma.LoreRelationshipScalarWhereInput[] - OR?: Prisma.LoreRelationshipScalarWhereInput[] - NOT?: Prisma.LoreRelationshipScalarWhereInput | Prisma.LoreRelationshipScalarWhereInput[] - id?: Prisma.StringFilter<"LoreRelationship"> | string - worldId?: Prisma.StringFilter<"LoreRelationship"> | string - sourceId?: Prisma.StringFilter<"LoreRelationship"> | string - targetId?: Prisma.StringFilter<"LoreRelationship"> | string - relationType?: Prisma.StringFilter<"LoreRelationship"> | string - metadata?: Prisma.JsonNullableFilter<"LoreRelationship"> - createdAt?: Prisma.DateTimeFilter<"LoreRelationship"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"LoreRelationship"> | Date | string -} - -export type LoreRelationshipCreateWithoutSourceInput = { - id?: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutLoreRelationshipsInput - target: Prisma.LoreEntryCreateNestedOneWithoutIncomingRelationsInput -} - -export type LoreRelationshipUncheckedCreateWithoutSourceInput = { - id?: string - worldId: string - targetId: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreRelationshipCreateOrConnectWithoutSourceInput = { - where: Prisma.LoreRelationshipWhereUniqueInput - create: Prisma.XOR -} - -export type LoreRelationshipCreateManySourceInputEnvelope = { - data: Prisma.LoreRelationshipCreateManySourceInput | Prisma.LoreRelationshipCreateManySourceInput[] - skipDuplicates?: boolean -} - -export type LoreRelationshipCreateWithoutTargetInput = { - id?: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutLoreRelationshipsInput - source: Prisma.LoreEntryCreateNestedOneWithoutOutgoingRelationsInput -} - -export type LoreRelationshipUncheckedCreateWithoutTargetInput = { - id?: string - worldId: string - sourceId: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreRelationshipCreateOrConnectWithoutTargetInput = { - where: Prisma.LoreRelationshipWhereUniqueInput - create: Prisma.XOR -} - -export type LoreRelationshipCreateManyTargetInputEnvelope = { - data: Prisma.LoreRelationshipCreateManyTargetInput | Prisma.LoreRelationshipCreateManyTargetInput[] - skipDuplicates?: boolean -} - -export type LoreRelationshipUpsertWithWhereUniqueWithoutSourceInput = { - where: Prisma.LoreRelationshipWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type LoreRelationshipUpdateWithWhereUniqueWithoutSourceInput = { - where: Prisma.LoreRelationshipWhereUniqueInput - data: Prisma.XOR -} - -export type LoreRelationshipUpdateManyWithWhereWithoutSourceInput = { - where: Prisma.LoreRelationshipScalarWhereInput - data: Prisma.XOR -} - -export type LoreRelationshipUpsertWithWhereUniqueWithoutTargetInput = { - where: Prisma.LoreRelationshipWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type LoreRelationshipUpdateWithWhereUniqueWithoutTargetInput = { - where: Prisma.LoreRelationshipWhereUniqueInput - data: Prisma.XOR -} - -export type LoreRelationshipUpdateManyWithWhereWithoutTargetInput = { - where: Prisma.LoreRelationshipScalarWhereInput - data: Prisma.XOR -} - -export type LoreRelationshipCreateManyWorldInput = { - id?: string - sourceId: string - targetId: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreRelationshipUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - source?: Prisma.LoreEntryUpdateOneRequiredWithoutOutgoingRelationsNestedInput - target?: Prisma.LoreEntryUpdateOneRequiredWithoutIncomingRelationsNestedInput -} - -export type LoreRelationshipUncheckedUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - sourceId?: Prisma.StringFieldUpdateOperationsInput | string - targetId?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreRelationshipUncheckedUpdateManyWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - sourceId?: Prisma.StringFieldUpdateOperationsInput | string - targetId?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreRelationshipCreateManySourceInput = { - id?: string - worldId: string - targetId: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreRelationshipCreateManyTargetInput = { - id?: string - worldId: string - sourceId: string - relationType: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type LoreRelationshipUpdateWithoutSourceInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutLoreRelationshipsNestedInput - target?: Prisma.LoreEntryUpdateOneRequiredWithoutIncomingRelationsNestedInput -} - -export type LoreRelationshipUncheckedUpdateWithoutSourceInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - targetId?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreRelationshipUncheckedUpdateManyWithoutSourceInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - targetId?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreRelationshipUpdateWithoutTargetInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutLoreRelationshipsNestedInput - source?: Prisma.LoreEntryUpdateOneRequiredWithoutOutgoingRelationsNestedInput -} - -export type LoreRelationshipUncheckedUpdateWithoutTargetInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - sourceId?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type LoreRelationshipUncheckedUpdateManyWithoutTargetInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - sourceId?: Prisma.StringFieldUpdateOperationsInput | string - relationType?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - - -export type LoreRelationshipSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - sourceId?: boolean - targetId?: boolean - relationType?: boolean - metadata?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - source?: boolean | Prisma.LoreEntryDefaultArgs - target?: boolean | Prisma.LoreEntryDefaultArgs -}, ExtArgs["result"]["loreRelationship"]> - -export type LoreRelationshipSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - sourceId?: boolean - targetId?: boolean - relationType?: boolean - metadata?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - source?: boolean | Prisma.LoreEntryDefaultArgs - target?: boolean | Prisma.LoreEntryDefaultArgs -}, ExtArgs["result"]["loreRelationship"]> - -export type LoreRelationshipSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - sourceId?: boolean - targetId?: boolean - relationType?: boolean - metadata?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - source?: boolean | Prisma.LoreEntryDefaultArgs - target?: boolean | Prisma.LoreEntryDefaultArgs -}, ExtArgs["result"]["loreRelationship"]> - -export type LoreRelationshipSelectScalar = { - id?: boolean - worldId?: boolean - sourceId?: boolean - targetId?: boolean - relationType?: boolean - metadata?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type LoreRelationshipOmit = runtime.Types.Extensions.GetOmit<"id" | "worldId" | "sourceId" | "targetId" | "relationType" | "metadata" | "createdAt" | "updatedAt", ExtArgs["result"]["loreRelationship"]> -export type LoreRelationshipInclude = { - world?: boolean | Prisma.WorldDefaultArgs - source?: boolean | Prisma.LoreEntryDefaultArgs - target?: boolean | Prisma.LoreEntryDefaultArgs -} -export type LoreRelationshipIncludeCreateManyAndReturn = { - world?: boolean | Prisma.WorldDefaultArgs - source?: boolean | Prisma.LoreEntryDefaultArgs - target?: boolean | Prisma.LoreEntryDefaultArgs -} -export type LoreRelationshipIncludeUpdateManyAndReturn = { - world?: boolean | Prisma.WorldDefaultArgs - source?: boolean | Prisma.LoreEntryDefaultArgs - target?: boolean | Prisma.LoreEntryDefaultArgs -} - -export type $LoreRelationshipPayload = { - name: "LoreRelationship" - objects: { - world: Prisma.$WorldPayload - source: Prisma.$LoreEntryPayload - target: Prisma.$LoreEntryPayload - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - worldId: string - sourceId: string - targetId: string - relationType: string - metadata: runtime.JsonValue | null - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["loreRelationship"]> - composites: {} -} - -export type LoreRelationshipGetPayload = runtime.Types.Result.GetResult - -export type LoreRelationshipCountArgs = - Omit & { - select?: LoreRelationshipCountAggregateInputType | true - } - -export interface LoreRelationshipDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['LoreRelationship'], meta: { name: 'LoreRelationship' } } - /** - * Find zero or one LoreRelationship that matches the filter. - * @param {LoreRelationshipFindUniqueArgs} args - Arguments to find a LoreRelationship - * @example - * // Get one LoreRelationship - * const loreRelationship = await prisma.loreRelationship.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__LoreRelationshipClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one LoreRelationship that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {LoreRelationshipFindUniqueOrThrowArgs} args - Arguments to find a LoreRelationship - * @example - * // Get one LoreRelationship - * const loreRelationship = await prisma.loreRelationship.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__LoreRelationshipClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first LoreRelationship 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 {LoreRelationshipFindFirstArgs} args - Arguments to find a LoreRelationship - * @example - * // Get one LoreRelationship - * const loreRelationship = await prisma.loreRelationship.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__LoreRelationshipClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first LoreRelationship 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 {LoreRelationshipFindFirstOrThrowArgs} args - Arguments to find a LoreRelationship - * @example - * // Get one LoreRelationship - * const loreRelationship = await prisma.loreRelationship.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__LoreRelationshipClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more LoreRelationships 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 {LoreRelationshipFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all LoreRelationships - * const loreRelationships = await prisma.loreRelationship.findMany() - * - * // Get first 10 LoreRelationships - * const loreRelationships = await prisma.loreRelationship.findMany({ take: 10 }) - * - * // Only select the `id` - * const loreRelationshipWithIdOnly = await prisma.loreRelationship.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a LoreRelationship. - * @param {LoreRelationshipCreateArgs} args - Arguments to create a LoreRelationship. - * @example - * // Create one LoreRelationship - * const LoreRelationship = await prisma.loreRelationship.create({ - * data: { - * // ... data to create a LoreRelationship - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__LoreRelationshipClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many LoreRelationships. - * @param {LoreRelationshipCreateManyArgs} args - Arguments to create many LoreRelationships. - * @example - * // Create many LoreRelationships - * const loreRelationship = await prisma.loreRelationship.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many LoreRelationships and returns the data saved in the database. - * @param {LoreRelationshipCreateManyAndReturnArgs} args - Arguments to create many LoreRelationships. - * @example - * // Create many LoreRelationships - * const loreRelationship = await prisma.loreRelationship.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many LoreRelationships and only return the `id` - * const loreRelationshipWithIdOnly = await prisma.loreRelationship.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 LoreRelationship. - * @param {LoreRelationshipDeleteArgs} args - Arguments to delete one LoreRelationship. - * @example - * // Delete one LoreRelationship - * const LoreRelationship = await prisma.loreRelationship.delete({ - * where: { - * // ... filter to delete one LoreRelationship - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__LoreRelationshipClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one LoreRelationship. - * @param {LoreRelationshipUpdateArgs} args - Arguments to update one LoreRelationship. - * @example - * // Update one LoreRelationship - * const loreRelationship = await prisma.loreRelationship.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__LoreRelationshipClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more LoreRelationships. - * @param {LoreRelationshipDeleteManyArgs} args - Arguments to filter LoreRelationships to delete. - * @example - * // Delete a few LoreRelationships - * const { count } = await prisma.loreRelationship.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more LoreRelationships. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {LoreRelationshipUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many LoreRelationships - * const loreRelationship = await prisma.loreRelationship.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more LoreRelationships and returns the data updated in the database. - * @param {LoreRelationshipUpdateManyAndReturnArgs} args - Arguments to update many LoreRelationships. - * @example - * // Update many LoreRelationships - * const loreRelationship = await prisma.loreRelationship.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more LoreRelationships and only return the `id` - * const loreRelationshipWithIdOnly = await prisma.loreRelationship.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 LoreRelationship. - * @param {LoreRelationshipUpsertArgs} args - Arguments to update or create a LoreRelationship. - * @example - * // Update or create a LoreRelationship - * const loreRelationship = await prisma.loreRelationship.upsert({ - * create: { - * // ... data to create a LoreRelationship - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the LoreRelationship we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__LoreRelationshipClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of LoreRelationships. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {LoreRelationshipCountArgs} args - Arguments to filter LoreRelationships to count. - * @example - * // Count the number of LoreRelationships - * const count = await prisma.loreRelationship.count({ - * where: { - * // ... the filter for the LoreRelationships 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 LoreRelationship. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {LoreRelationshipAggregateArgs} 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 LoreRelationship. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {LoreRelationshipGroupByArgs} 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 LoreRelationshipGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: LoreRelationshipGroupByArgs['orderBy'] } - : { orderBy?: LoreRelationshipGroupByArgs['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 ? GetLoreRelationshipGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the LoreRelationship model - */ -readonly fields: LoreRelationshipFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for LoreRelationship. - * 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__LoreRelationshipClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - world = {}>(args?: Prisma.Subset>): Prisma.Prisma__WorldClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - source = {}>(args?: Prisma.Subset>): Prisma.Prisma__LoreEntryClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - target = {}>(args?: Prisma.Subset>): Prisma.Prisma__LoreEntryClient, 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 LoreRelationship model - */ -export interface LoreRelationshipFieldRefs { - readonly id: Prisma.FieldRef<"LoreRelationship", 'String'> - readonly worldId: Prisma.FieldRef<"LoreRelationship", 'String'> - readonly sourceId: Prisma.FieldRef<"LoreRelationship", 'String'> - readonly targetId: Prisma.FieldRef<"LoreRelationship", 'String'> - readonly relationType: Prisma.FieldRef<"LoreRelationship", 'String'> - readonly metadata: Prisma.FieldRef<"LoreRelationship", 'Json'> - readonly createdAt: Prisma.FieldRef<"LoreRelationship", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"LoreRelationship", 'DateTime'> -} - - -// Custom InputTypes -/** - * LoreRelationship findUnique - */ -export type LoreRelationshipFindUniqueArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - /** - * Filter, which LoreRelationship to fetch. - */ - where: Prisma.LoreRelationshipWhereUniqueInput -} - -/** - * LoreRelationship findUniqueOrThrow - */ -export type LoreRelationshipFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - /** - * Filter, which LoreRelationship to fetch. - */ - where: Prisma.LoreRelationshipWhereUniqueInput -} - -/** - * LoreRelationship findFirst - */ -export type LoreRelationshipFindFirstArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - /** - * Filter, which LoreRelationship to fetch. - */ - where?: Prisma.LoreRelationshipWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of LoreRelationships to fetch. - */ - orderBy?: Prisma.LoreRelationshipOrderByWithRelationInput | Prisma.LoreRelationshipOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for LoreRelationships. - */ - cursor?: Prisma.LoreRelationshipWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` LoreRelationships 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` LoreRelationships. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of LoreRelationships. - */ - distinct?: Prisma.LoreRelationshipScalarFieldEnum | Prisma.LoreRelationshipScalarFieldEnum[] -} - -/** - * LoreRelationship findFirstOrThrow - */ -export type LoreRelationshipFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - /** - * Filter, which LoreRelationship to fetch. - */ - where?: Prisma.LoreRelationshipWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of LoreRelationships to fetch. - */ - orderBy?: Prisma.LoreRelationshipOrderByWithRelationInput | Prisma.LoreRelationshipOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for LoreRelationships. - */ - cursor?: Prisma.LoreRelationshipWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` LoreRelationships 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` LoreRelationships. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of LoreRelationships. - */ - distinct?: Prisma.LoreRelationshipScalarFieldEnum | Prisma.LoreRelationshipScalarFieldEnum[] -} - -/** - * LoreRelationship findMany - */ -export type LoreRelationshipFindManyArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - /** - * Filter, which LoreRelationships to fetch. - */ - where?: Prisma.LoreRelationshipWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of LoreRelationships to fetch. - */ - orderBy?: Prisma.LoreRelationshipOrderByWithRelationInput | Prisma.LoreRelationshipOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing LoreRelationships. - */ - cursor?: Prisma.LoreRelationshipWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` LoreRelationships 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` LoreRelationships. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of LoreRelationships. - */ - distinct?: Prisma.LoreRelationshipScalarFieldEnum | Prisma.LoreRelationshipScalarFieldEnum[] -} - -/** - * LoreRelationship create - */ -export type LoreRelationshipCreateArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - /** - * The data needed to create a LoreRelationship. - */ - data: Prisma.XOR -} - -/** - * LoreRelationship createMany - */ -export type LoreRelationshipCreateManyArgs = { - /** - * The data used to create many LoreRelationships. - */ - data: Prisma.LoreRelationshipCreateManyInput | Prisma.LoreRelationshipCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * LoreRelationship createManyAndReturn - */ -export type LoreRelationshipCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelectCreateManyAndReturn | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * The data used to create many LoreRelationships. - */ - data: Prisma.LoreRelationshipCreateManyInput | Prisma.LoreRelationshipCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipIncludeCreateManyAndReturn | null -} - -/** - * LoreRelationship update - */ -export type LoreRelationshipUpdateArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - /** - * The data needed to update a LoreRelationship. - */ - data: Prisma.XOR - /** - * Choose, which LoreRelationship to update. - */ - where: Prisma.LoreRelationshipWhereUniqueInput -} - -/** - * LoreRelationship updateMany - */ -export type LoreRelationshipUpdateManyArgs = { - /** - * The data used to update LoreRelationships. - */ - data: Prisma.XOR - /** - * Filter which LoreRelationships to update - */ - where?: Prisma.LoreRelationshipWhereInput - /** - * Limit how many LoreRelationships to update. - */ - limit?: number -} - -/** - * LoreRelationship updateManyAndReturn - */ -export type LoreRelationshipUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * The data used to update LoreRelationships. - */ - data: Prisma.XOR - /** - * Filter which LoreRelationships to update - */ - where?: Prisma.LoreRelationshipWhereInput - /** - * Limit how many LoreRelationships to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipIncludeUpdateManyAndReturn | null -} - -/** - * LoreRelationship upsert - */ -export type LoreRelationshipUpsertArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - /** - * The filter to search for the LoreRelationship to update in case it exists. - */ - where: Prisma.LoreRelationshipWhereUniqueInput - /** - * In case the LoreRelationship found by the `where` argument doesn't exist, create a new LoreRelationship with this data. - */ - create: Prisma.XOR - /** - * In case the LoreRelationship was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * LoreRelationship delete - */ -export type LoreRelationshipDeleteArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - /** - * Filter which LoreRelationship to delete. - */ - where: Prisma.LoreRelationshipWhereUniqueInput -} - -/** - * LoreRelationship deleteMany - */ -export type LoreRelationshipDeleteManyArgs = { - /** - * Filter which LoreRelationships to delete - */ - where?: Prisma.LoreRelationshipWhereInput - /** - * Limit how many LoreRelationships to delete. - */ - limit?: number -} - -/** - * LoreRelationship without action - */ -export type LoreRelationshipDefaultArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null -} diff --git a/apps/api/src/generated/prisma/models/ModerationReport.ts b/apps/api/src/generated/prisma/models/ModerationReport.ts deleted file mode 100644 index bdc6e4d..0000000 --- a/apps/api/src/generated/prisma/models/ModerationReport.ts +++ /dev/null @@ -1,2194 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `ModerationReport` 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 ModerationReport - * - */ -export type ModerationReportModel = runtime.Types.Result.DefaultSelection - -export type AggregateModerationReport = { - _count: ModerationReportCountAggregateOutputType | null - _min: ModerationReportMinAggregateOutputType | null - _max: ModerationReportMaxAggregateOutputType | null -} - -export type ModerationReportMinAggregateOutputType = { - id: string | null - reporterId: string | null - reviewerId: string | null - worldId: string | null - proposalId: string | null - targetType: $Enums.ModerationTargetType | null - targetId: string | null - reason: string | null - details: string | null - status: $Enums.ModerationStatus | null - reviewedAt: Date | null - createdAt: Date | null - updatedAt: Date | null -} - -export type ModerationReportMaxAggregateOutputType = { - id: string | null - reporterId: string | null - reviewerId: string | null - worldId: string | null - proposalId: string | null - targetType: $Enums.ModerationTargetType | null - targetId: string | null - reason: string | null - details: string | null - status: $Enums.ModerationStatus | null - reviewedAt: Date | null - createdAt: Date | null - updatedAt: Date | null -} - -export type ModerationReportCountAggregateOutputType = { - id: number - reporterId: number - reviewerId: number - worldId: number - proposalId: number - targetType: number - targetId: number - reason: number - details: number - status: number - reviewedAt: number - createdAt: number - updatedAt: number - _all: number -} - - -export type ModerationReportMinAggregateInputType = { - id?: true - reporterId?: true - reviewerId?: true - worldId?: true - proposalId?: true - targetType?: true - targetId?: true - reason?: true - details?: true - status?: true - reviewedAt?: true - createdAt?: true - updatedAt?: true -} - -export type ModerationReportMaxAggregateInputType = { - id?: true - reporterId?: true - reviewerId?: true - worldId?: true - proposalId?: true - targetType?: true - targetId?: true - reason?: true - details?: true - status?: true - reviewedAt?: true - createdAt?: true - updatedAt?: true -} - -export type ModerationReportCountAggregateInputType = { - id?: true - reporterId?: true - reviewerId?: true - worldId?: true - proposalId?: true - targetType?: true - targetId?: true - reason?: true - details?: true - status?: true - reviewedAt?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type ModerationReportAggregateArgs = { - /** - * Filter which ModerationReport to aggregate. - */ - where?: Prisma.ModerationReportWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of ModerationReports to fetch. - */ - orderBy?: Prisma.ModerationReportOrderByWithRelationInput | Prisma.ModerationReportOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.ModerationReportWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` ModerationReports 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` ModerationReports. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned ModerationReports - **/ - _count?: true | ModerationReportCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: ModerationReportMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: ModerationReportMaxAggregateInputType -} - -export type GetModerationReportAggregateType = { - [P in keyof T & keyof AggregateModerationReport]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type ModerationReportGroupByArgs = { - where?: Prisma.ModerationReportWhereInput - orderBy?: Prisma.ModerationReportOrderByWithAggregationInput | Prisma.ModerationReportOrderByWithAggregationInput[] - by: Prisma.ModerationReportScalarFieldEnum[] | Prisma.ModerationReportScalarFieldEnum - having?: Prisma.ModerationReportScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: ModerationReportCountAggregateInputType | true - _min?: ModerationReportMinAggregateInputType - _max?: ModerationReportMaxAggregateInputType -} - -export type ModerationReportGroupByOutputType = { - id: string - reporterId: string - reviewerId: string | null - worldId: string | null - proposalId: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details: string | null - status: $Enums.ModerationStatus - reviewedAt: Date | null - createdAt: Date - updatedAt: Date - _count: ModerationReportCountAggregateOutputType | null - _min: ModerationReportMinAggregateOutputType | null - _max: ModerationReportMaxAggregateOutputType | null -} - -export type GetModerationReportGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof ModerationReportGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type ModerationReportWhereInput = { - AND?: Prisma.ModerationReportWhereInput | Prisma.ModerationReportWhereInput[] - OR?: Prisma.ModerationReportWhereInput[] - NOT?: Prisma.ModerationReportWhereInput | Prisma.ModerationReportWhereInput[] - id?: Prisma.StringFilter<"ModerationReport"> | string - reporterId?: Prisma.StringFilter<"ModerationReport"> | string - reviewerId?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - worldId?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - proposalId?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - targetType?: Prisma.EnumModerationTargetTypeFilter<"ModerationReport"> | $Enums.ModerationTargetType - targetId?: Prisma.StringFilter<"ModerationReport"> | string - reason?: Prisma.StringFilter<"ModerationReport"> | string - details?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - status?: Prisma.EnumModerationStatusFilter<"ModerationReport"> | $Enums.ModerationStatus - reviewedAt?: Prisma.DateTimeNullableFilter<"ModerationReport"> | Date | string | null - createdAt?: Prisma.DateTimeFilter<"ModerationReport"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"ModerationReport"> | Date | string - reporter?: Prisma.XOR - reviewer?: Prisma.XOR | null - world?: Prisma.XOR | null - proposal?: Prisma.XOR | null -} - -export type ModerationReportOrderByWithRelationInput = { - id?: Prisma.SortOrder - reporterId?: Prisma.SortOrder - reviewerId?: Prisma.SortOrderInput | Prisma.SortOrder - worldId?: Prisma.SortOrderInput | Prisma.SortOrder - proposalId?: Prisma.SortOrderInput | Prisma.SortOrder - targetType?: Prisma.SortOrder - targetId?: Prisma.SortOrder - reason?: Prisma.SortOrder - details?: Prisma.SortOrderInput | Prisma.SortOrder - status?: Prisma.SortOrder - reviewedAt?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - reporter?: Prisma.UserOrderByWithRelationInput - reviewer?: Prisma.UserOrderByWithRelationInput - world?: Prisma.WorldOrderByWithRelationInput - proposal?: Prisma.ProposalOrderByWithRelationInput -} - -export type ModerationReportWhereUniqueInput = Prisma.AtLeast<{ - id?: string - AND?: Prisma.ModerationReportWhereInput | Prisma.ModerationReportWhereInput[] - OR?: Prisma.ModerationReportWhereInput[] - NOT?: Prisma.ModerationReportWhereInput | Prisma.ModerationReportWhereInput[] - reporterId?: Prisma.StringFilter<"ModerationReport"> | string - reviewerId?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - worldId?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - proposalId?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - targetType?: Prisma.EnumModerationTargetTypeFilter<"ModerationReport"> | $Enums.ModerationTargetType - targetId?: Prisma.StringFilter<"ModerationReport"> | string - reason?: Prisma.StringFilter<"ModerationReport"> | string - details?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - status?: Prisma.EnumModerationStatusFilter<"ModerationReport"> | $Enums.ModerationStatus - reviewedAt?: Prisma.DateTimeNullableFilter<"ModerationReport"> | Date | string | null - createdAt?: Prisma.DateTimeFilter<"ModerationReport"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"ModerationReport"> | Date | string - reporter?: Prisma.XOR - reviewer?: Prisma.XOR | null - world?: Prisma.XOR | null - proposal?: Prisma.XOR | null -}, "id"> - -export type ModerationReportOrderByWithAggregationInput = { - id?: Prisma.SortOrder - reporterId?: Prisma.SortOrder - reviewerId?: Prisma.SortOrderInput | Prisma.SortOrder - worldId?: Prisma.SortOrderInput | Prisma.SortOrder - proposalId?: Prisma.SortOrderInput | Prisma.SortOrder - targetType?: Prisma.SortOrder - targetId?: Prisma.SortOrder - reason?: Prisma.SortOrder - details?: Prisma.SortOrderInput | Prisma.SortOrder - status?: Prisma.SortOrder - reviewedAt?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.ModerationReportCountOrderByAggregateInput - _max?: Prisma.ModerationReportMaxOrderByAggregateInput - _min?: Prisma.ModerationReportMinOrderByAggregateInput -} - -export type ModerationReportScalarWhereWithAggregatesInput = { - AND?: Prisma.ModerationReportScalarWhereWithAggregatesInput | Prisma.ModerationReportScalarWhereWithAggregatesInput[] - OR?: Prisma.ModerationReportScalarWhereWithAggregatesInput[] - NOT?: Prisma.ModerationReportScalarWhereWithAggregatesInput | Prisma.ModerationReportScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"ModerationReport"> | string - reporterId?: Prisma.StringWithAggregatesFilter<"ModerationReport"> | string - reviewerId?: Prisma.StringNullableWithAggregatesFilter<"ModerationReport"> | string | null - worldId?: Prisma.StringNullableWithAggregatesFilter<"ModerationReport"> | string | null - proposalId?: Prisma.StringNullableWithAggregatesFilter<"ModerationReport"> | string | null - targetType?: Prisma.EnumModerationTargetTypeWithAggregatesFilter<"ModerationReport"> | $Enums.ModerationTargetType - targetId?: Prisma.StringWithAggregatesFilter<"ModerationReport"> | string - reason?: Prisma.StringWithAggregatesFilter<"ModerationReport"> | string - details?: Prisma.StringNullableWithAggregatesFilter<"ModerationReport"> | string | null - status?: Prisma.EnumModerationStatusWithAggregatesFilter<"ModerationReport"> | $Enums.ModerationStatus - reviewedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"ModerationReport"> | Date | string | null - createdAt?: Prisma.DateTimeWithAggregatesFilter<"ModerationReport"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"ModerationReport"> | Date | string -} - -export type ModerationReportCreateInput = { - id?: string - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - reporter: Prisma.UserCreateNestedOneWithoutModerationReportsInput - reviewer?: Prisma.UserCreateNestedOneWithoutModerationReviewsInput - world?: Prisma.WorldCreateNestedOneWithoutModerationReportsInput - proposal?: Prisma.ProposalCreateNestedOneWithoutModerationReportsInput -} - -export type ModerationReportUncheckedCreateInput = { - id?: string - reporterId: string - reviewerId?: string | null - worldId?: string | null - proposalId?: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ModerationReportUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - reporter?: Prisma.UserUpdateOneRequiredWithoutModerationReportsNestedInput - reviewer?: Prisma.UserUpdateOneWithoutModerationReviewsNestedInput - world?: Prisma.WorldUpdateOneWithoutModerationReportsNestedInput - proposal?: Prisma.ProposalUpdateOneWithoutModerationReportsNestedInput -} - -export type ModerationReportUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - reporterId?: Prisma.StringFieldUpdateOperationsInput | string - reviewerId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - worldId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - proposalId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ModerationReportCreateManyInput = { - id?: string - reporterId: string - reviewerId?: string | null - worldId?: string | null - proposalId?: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ModerationReportUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ModerationReportUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - reporterId?: Prisma.StringFieldUpdateOperationsInput | string - reviewerId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - worldId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - proposalId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ModerationReportListRelationFilter = { - every?: Prisma.ModerationReportWhereInput - some?: Prisma.ModerationReportWhereInput - none?: Prisma.ModerationReportWhereInput -} - -export type ModerationReportOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type ModerationReportCountOrderByAggregateInput = { - id?: Prisma.SortOrder - reporterId?: Prisma.SortOrder - reviewerId?: Prisma.SortOrder - worldId?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - targetType?: Prisma.SortOrder - targetId?: Prisma.SortOrder - reason?: Prisma.SortOrder - details?: Prisma.SortOrder - status?: Prisma.SortOrder - reviewedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type ModerationReportMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - reporterId?: Prisma.SortOrder - reviewerId?: Prisma.SortOrder - worldId?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - targetType?: Prisma.SortOrder - targetId?: Prisma.SortOrder - reason?: Prisma.SortOrder - details?: Prisma.SortOrder - status?: Prisma.SortOrder - reviewedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type ModerationReportMinOrderByAggregateInput = { - id?: Prisma.SortOrder - reporterId?: Prisma.SortOrder - reviewerId?: Prisma.SortOrder - worldId?: Prisma.SortOrder - proposalId?: Prisma.SortOrder - targetType?: Prisma.SortOrder - targetId?: Prisma.SortOrder - reason?: Prisma.SortOrder - details?: Prisma.SortOrder - status?: Prisma.SortOrder - reviewedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type ModerationReportCreateNestedManyWithoutReporterInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutReporterInput[] | Prisma.ModerationReportUncheckedCreateWithoutReporterInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutReporterInput | Prisma.ModerationReportCreateOrConnectWithoutReporterInput[] - createMany?: Prisma.ModerationReportCreateManyReporterInputEnvelope - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] -} - -export type ModerationReportCreateNestedManyWithoutReviewerInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutReviewerInput[] | Prisma.ModerationReportUncheckedCreateWithoutReviewerInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutReviewerInput | Prisma.ModerationReportCreateOrConnectWithoutReviewerInput[] - createMany?: Prisma.ModerationReportCreateManyReviewerInputEnvelope - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] -} - -export type ModerationReportUncheckedCreateNestedManyWithoutReporterInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutReporterInput[] | Prisma.ModerationReportUncheckedCreateWithoutReporterInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutReporterInput | Prisma.ModerationReportCreateOrConnectWithoutReporterInput[] - createMany?: Prisma.ModerationReportCreateManyReporterInputEnvelope - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] -} - -export type ModerationReportUncheckedCreateNestedManyWithoutReviewerInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutReviewerInput[] | Prisma.ModerationReportUncheckedCreateWithoutReviewerInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutReviewerInput | Prisma.ModerationReportCreateOrConnectWithoutReviewerInput[] - createMany?: Prisma.ModerationReportCreateManyReviewerInputEnvelope - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] -} - -export type ModerationReportUpdateManyWithoutReporterNestedInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutReporterInput[] | Prisma.ModerationReportUncheckedCreateWithoutReporterInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutReporterInput | Prisma.ModerationReportCreateOrConnectWithoutReporterInput[] - upsert?: Prisma.ModerationReportUpsertWithWhereUniqueWithoutReporterInput | Prisma.ModerationReportUpsertWithWhereUniqueWithoutReporterInput[] - createMany?: Prisma.ModerationReportCreateManyReporterInputEnvelope - set?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - disconnect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - delete?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - update?: Prisma.ModerationReportUpdateWithWhereUniqueWithoutReporterInput | Prisma.ModerationReportUpdateWithWhereUniqueWithoutReporterInput[] - updateMany?: Prisma.ModerationReportUpdateManyWithWhereWithoutReporterInput | Prisma.ModerationReportUpdateManyWithWhereWithoutReporterInput[] - deleteMany?: Prisma.ModerationReportScalarWhereInput | Prisma.ModerationReportScalarWhereInput[] -} - -export type ModerationReportUpdateManyWithoutReviewerNestedInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutReviewerInput[] | Prisma.ModerationReportUncheckedCreateWithoutReviewerInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutReviewerInput | Prisma.ModerationReportCreateOrConnectWithoutReviewerInput[] - upsert?: Prisma.ModerationReportUpsertWithWhereUniqueWithoutReviewerInput | Prisma.ModerationReportUpsertWithWhereUniqueWithoutReviewerInput[] - createMany?: Prisma.ModerationReportCreateManyReviewerInputEnvelope - set?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - disconnect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - delete?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - update?: Prisma.ModerationReportUpdateWithWhereUniqueWithoutReviewerInput | Prisma.ModerationReportUpdateWithWhereUniqueWithoutReviewerInput[] - updateMany?: Prisma.ModerationReportUpdateManyWithWhereWithoutReviewerInput | Prisma.ModerationReportUpdateManyWithWhereWithoutReviewerInput[] - deleteMany?: Prisma.ModerationReportScalarWhereInput | Prisma.ModerationReportScalarWhereInput[] -} - -export type ModerationReportUncheckedUpdateManyWithoutReporterNestedInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutReporterInput[] | Prisma.ModerationReportUncheckedCreateWithoutReporterInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutReporterInput | Prisma.ModerationReportCreateOrConnectWithoutReporterInput[] - upsert?: Prisma.ModerationReportUpsertWithWhereUniqueWithoutReporterInput | Prisma.ModerationReportUpsertWithWhereUniqueWithoutReporterInput[] - createMany?: Prisma.ModerationReportCreateManyReporterInputEnvelope - set?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - disconnect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - delete?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - update?: Prisma.ModerationReportUpdateWithWhereUniqueWithoutReporterInput | Prisma.ModerationReportUpdateWithWhereUniqueWithoutReporterInput[] - updateMany?: Prisma.ModerationReportUpdateManyWithWhereWithoutReporterInput | Prisma.ModerationReportUpdateManyWithWhereWithoutReporterInput[] - deleteMany?: Prisma.ModerationReportScalarWhereInput | Prisma.ModerationReportScalarWhereInput[] -} - -export type ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutReviewerInput[] | Prisma.ModerationReportUncheckedCreateWithoutReviewerInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutReviewerInput | Prisma.ModerationReportCreateOrConnectWithoutReviewerInput[] - upsert?: Prisma.ModerationReportUpsertWithWhereUniqueWithoutReviewerInput | Prisma.ModerationReportUpsertWithWhereUniqueWithoutReviewerInput[] - createMany?: Prisma.ModerationReportCreateManyReviewerInputEnvelope - set?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - disconnect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - delete?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - update?: Prisma.ModerationReportUpdateWithWhereUniqueWithoutReviewerInput | Prisma.ModerationReportUpdateWithWhereUniqueWithoutReviewerInput[] - updateMany?: Prisma.ModerationReportUpdateManyWithWhereWithoutReviewerInput | Prisma.ModerationReportUpdateManyWithWhereWithoutReviewerInput[] - deleteMany?: Prisma.ModerationReportScalarWhereInput | Prisma.ModerationReportScalarWhereInput[] -} - -export type ModerationReportCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutWorldInput[] | Prisma.ModerationReportUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutWorldInput | Prisma.ModerationReportCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.ModerationReportCreateManyWorldInputEnvelope - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] -} - -export type ModerationReportUncheckedCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutWorldInput[] | Prisma.ModerationReportUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutWorldInput | Prisma.ModerationReportCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.ModerationReportCreateManyWorldInputEnvelope - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] -} - -export type ModerationReportUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutWorldInput[] | Prisma.ModerationReportUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutWorldInput | Prisma.ModerationReportCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.ModerationReportUpsertWithWhereUniqueWithoutWorldInput | Prisma.ModerationReportUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.ModerationReportCreateManyWorldInputEnvelope - set?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - disconnect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - delete?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - update?: Prisma.ModerationReportUpdateWithWhereUniqueWithoutWorldInput | Prisma.ModerationReportUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.ModerationReportUpdateManyWithWhereWithoutWorldInput | Prisma.ModerationReportUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.ModerationReportScalarWhereInput | Prisma.ModerationReportScalarWhereInput[] -} - -export type ModerationReportUncheckedUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutWorldInput[] | Prisma.ModerationReportUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutWorldInput | Prisma.ModerationReportCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.ModerationReportUpsertWithWhereUniqueWithoutWorldInput | Prisma.ModerationReportUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.ModerationReportCreateManyWorldInputEnvelope - set?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - disconnect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - delete?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - update?: Prisma.ModerationReportUpdateWithWhereUniqueWithoutWorldInput | Prisma.ModerationReportUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.ModerationReportUpdateManyWithWhereWithoutWorldInput | Prisma.ModerationReportUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.ModerationReportScalarWhereInput | Prisma.ModerationReportScalarWhereInput[] -} - -export type ModerationReportCreateNestedManyWithoutProposalInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutProposalInput[] | Prisma.ModerationReportUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutProposalInput | Prisma.ModerationReportCreateOrConnectWithoutProposalInput[] - createMany?: Prisma.ModerationReportCreateManyProposalInputEnvelope - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] -} - -export type ModerationReportUncheckedCreateNestedManyWithoutProposalInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutProposalInput[] | Prisma.ModerationReportUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutProposalInput | Prisma.ModerationReportCreateOrConnectWithoutProposalInput[] - createMany?: Prisma.ModerationReportCreateManyProposalInputEnvelope - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] -} - -export type ModerationReportUpdateManyWithoutProposalNestedInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutProposalInput[] | Prisma.ModerationReportUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutProposalInput | Prisma.ModerationReportCreateOrConnectWithoutProposalInput[] - upsert?: Prisma.ModerationReportUpsertWithWhereUniqueWithoutProposalInput | Prisma.ModerationReportUpsertWithWhereUniqueWithoutProposalInput[] - createMany?: Prisma.ModerationReportCreateManyProposalInputEnvelope - set?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - disconnect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - delete?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - update?: Prisma.ModerationReportUpdateWithWhereUniqueWithoutProposalInput | Prisma.ModerationReportUpdateWithWhereUniqueWithoutProposalInput[] - updateMany?: Prisma.ModerationReportUpdateManyWithWhereWithoutProposalInput | Prisma.ModerationReportUpdateManyWithWhereWithoutProposalInput[] - deleteMany?: Prisma.ModerationReportScalarWhereInput | Prisma.ModerationReportScalarWhereInput[] -} - -export type ModerationReportUncheckedUpdateManyWithoutProposalNestedInput = { - create?: Prisma.XOR | Prisma.ModerationReportCreateWithoutProposalInput[] | Prisma.ModerationReportUncheckedCreateWithoutProposalInput[] - connectOrCreate?: Prisma.ModerationReportCreateOrConnectWithoutProposalInput | Prisma.ModerationReportCreateOrConnectWithoutProposalInput[] - upsert?: Prisma.ModerationReportUpsertWithWhereUniqueWithoutProposalInput | Prisma.ModerationReportUpsertWithWhereUniqueWithoutProposalInput[] - createMany?: Prisma.ModerationReportCreateManyProposalInputEnvelope - set?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - disconnect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - delete?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - connect?: Prisma.ModerationReportWhereUniqueInput | Prisma.ModerationReportWhereUniqueInput[] - update?: Prisma.ModerationReportUpdateWithWhereUniqueWithoutProposalInput | Prisma.ModerationReportUpdateWithWhereUniqueWithoutProposalInput[] - updateMany?: Prisma.ModerationReportUpdateManyWithWhereWithoutProposalInput | Prisma.ModerationReportUpdateManyWithWhereWithoutProposalInput[] - deleteMany?: Prisma.ModerationReportScalarWhereInput | Prisma.ModerationReportScalarWhereInput[] -} - -export type EnumModerationTargetTypeFieldUpdateOperationsInput = { - set?: $Enums.ModerationTargetType -} - -export type EnumModerationStatusFieldUpdateOperationsInput = { - set?: $Enums.ModerationStatus -} - -export type ModerationReportCreateWithoutReporterInput = { - id?: string - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - reviewer?: Prisma.UserCreateNestedOneWithoutModerationReviewsInput - world?: Prisma.WorldCreateNestedOneWithoutModerationReportsInput - proposal?: Prisma.ProposalCreateNestedOneWithoutModerationReportsInput -} - -export type ModerationReportUncheckedCreateWithoutReporterInput = { - id?: string - reviewerId?: string | null - worldId?: string | null - proposalId?: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ModerationReportCreateOrConnectWithoutReporterInput = { - where: Prisma.ModerationReportWhereUniqueInput - create: Prisma.XOR -} - -export type ModerationReportCreateManyReporterInputEnvelope = { - data: Prisma.ModerationReportCreateManyReporterInput | Prisma.ModerationReportCreateManyReporterInput[] - skipDuplicates?: boolean -} - -export type ModerationReportCreateWithoutReviewerInput = { - id?: string - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - reporter: Prisma.UserCreateNestedOneWithoutModerationReportsInput - world?: Prisma.WorldCreateNestedOneWithoutModerationReportsInput - proposal?: Prisma.ProposalCreateNestedOneWithoutModerationReportsInput -} - -export type ModerationReportUncheckedCreateWithoutReviewerInput = { - id?: string - reporterId: string - worldId?: string | null - proposalId?: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ModerationReportCreateOrConnectWithoutReviewerInput = { - where: Prisma.ModerationReportWhereUniqueInput - create: Prisma.XOR -} - -export type ModerationReportCreateManyReviewerInputEnvelope = { - data: Prisma.ModerationReportCreateManyReviewerInput | Prisma.ModerationReportCreateManyReviewerInput[] - skipDuplicates?: boolean -} - -export type ModerationReportUpsertWithWhereUniqueWithoutReporterInput = { - where: Prisma.ModerationReportWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type ModerationReportUpdateWithWhereUniqueWithoutReporterInput = { - where: Prisma.ModerationReportWhereUniqueInput - data: Prisma.XOR -} - -export type ModerationReportUpdateManyWithWhereWithoutReporterInput = { - where: Prisma.ModerationReportScalarWhereInput - data: Prisma.XOR -} - -export type ModerationReportScalarWhereInput = { - AND?: Prisma.ModerationReportScalarWhereInput | Prisma.ModerationReportScalarWhereInput[] - OR?: Prisma.ModerationReportScalarWhereInput[] - NOT?: Prisma.ModerationReportScalarWhereInput | Prisma.ModerationReportScalarWhereInput[] - id?: Prisma.StringFilter<"ModerationReport"> | string - reporterId?: Prisma.StringFilter<"ModerationReport"> | string - reviewerId?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - worldId?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - proposalId?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - targetType?: Prisma.EnumModerationTargetTypeFilter<"ModerationReport"> | $Enums.ModerationTargetType - targetId?: Prisma.StringFilter<"ModerationReport"> | string - reason?: Prisma.StringFilter<"ModerationReport"> | string - details?: Prisma.StringNullableFilter<"ModerationReport"> | string | null - status?: Prisma.EnumModerationStatusFilter<"ModerationReport"> | $Enums.ModerationStatus - reviewedAt?: Prisma.DateTimeNullableFilter<"ModerationReport"> | Date | string | null - createdAt?: Prisma.DateTimeFilter<"ModerationReport"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"ModerationReport"> | Date | string -} - -export type ModerationReportUpsertWithWhereUniqueWithoutReviewerInput = { - where: Prisma.ModerationReportWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type ModerationReportUpdateWithWhereUniqueWithoutReviewerInput = { - where: Prisma.ModerationReportWhereUniqueInput - data: Prisma.XOR -} - -export type ModerationReportUpdateManyWithWhereWithoutReviewerInput = { - where: Prisma.ModerationReportScalarWhereInput - data: Prisma.XOR -} - -export type ModerationReportCreateWithoutWorldInput = { - id?: string - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - reporter: Prisma.UserCreateNestedOneWithoutModerationReportsInput - reviewer?: Prisma.UserCreateNestedOneWithoutModerationReviewsInput - proposal?: Prisma.ProposalCreateNestedOneWithoutModerationReportsInput -} - -export type ModerationReportUncheckedCreateWithoutWorldInput = { - id?: string - reporterId: string - reviewerId?: string | null - proposalId?: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ModerationReportCreateOrConnectWithoutWorldInput = { - where: Prisma.ModerationReportWhereUniqueInput - create: Prisma.XOR -} - -export type ModerationReportCreateManyWorldInputEnvelope = { - data: Prisma.ModerationReportCreateManyWorldInput | Prisma.ModerationReportCreateManyWorldInput[] - skipDuplicates?: boolean -} - -export type ModerationReportUpsertWithWhereUniqueWithoutWorldInput = { - where: Prisma.ModerationReportWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type ModerationReportUpdateWithWhereUniqueWithoutWorldInput = { - where: Prisma.ModerationReportWhereUniqueInput - data: Prisma.XOR -} - -export type ModerationReportUpdateManyWithWhereWithoutWorldInput = { - where: Prisma.ModerationReportScalarWhereInput - data: Prisma.XOR -} - -export type ModerationReportCreateWithoutProposalInput = { - id?: string - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - reporter: Prisma.UserCreateNestedOneWithoutModerationReportsInput - reviewer?: Prisma.UserCreateNestedOneWithoutModerationReviewsInput - world?: Prisma.WorldCreateNestedOneWithoutModerationReportsInput -} - -export type ModerationReportUncheckedCreateWithoutProposalInput = { - id?: string - reporterId: string - reviewerId?: string | null - worldId?: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ModerationReportCreateOrConnectWithoutProposalInput = { - where: Prisma.ModerationReportWhereUniqueInput - create: Prisma.XOR -} - -export type ModerationReportCreateManyProposalInputEnvelope = { - data: Prisma.ModerationReportCreateManyProposalInput | Prisma.ModerationReportCreateManyProposalInput[] - skipDuplicates?: boolean -} - -export type ModerationReportUpsertWithWhereUniqueWithoutProposalInput = { - where: Prisma.ModerationReportWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type ModerationReportUpdateWithWhereUniqueWithoutProposalInput = { - where: Prisma.ModerationReportWhereUniqueInput - data: Prisma.XOR -} - -export type ModerationReportUpdateManyWithWhereWithoutProposalInput = { - where: Prisma.ModerationReportScalarWhereInput - data: Prisma.XOR -} - -export type ModerationReportCreateManyReporterInput = { - id?: string - reviewerId?: string | null - worldId?: string | null - proposalId?: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ModerationReportCreateManyReviewerInput = { - id?: string - reporterId: string - worldId?: string | null - proposalId?: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ModerationReportUpdateWithoutReporterInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - reviewer?: Prisma.UserUpdateOneWithoutModerationReviewsNestedInput - world?: Prisma.WorldUpdateOneWithoutModerationReportsNestedInput - proposal?: Prisma.ProposalUpdateOneWithoutModerationReportsNestedInput -} - -export type ModerationReportUncheckedUpdateWithoutReporterInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - reviewerId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - worldId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - proposalId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ModerationReportUncheckedUpdateManyWithoutReporterInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - reviewerId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - worldId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - proposalId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ModerationReportUpdateWithoutReviewerInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - reporter?: Prisma.UserUpdateOneRequiredWithoutModerationReportsNestedInput - world?: Prisma.WorldUpdateOneWithoutModerationReportsNestedInput - proposal?: Prisma.ProposalUpdateOneWithoutModerationReportsNestedInput -} - -export type ModerationReportUncheckedUpdateWithoutReviewerInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - reporterId?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - proposalId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ModerationReportUncheckedUpdateManyWithoutReviewerInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - reporterId?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - proposalId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ModerationReportCreateManyWorldInput = { - id?: string - reporterId: string - reviewerId?: string | null - proposalId?: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ModerationReportUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - reporter?: Prisma.UserUpdateOneRequiredWithoutModerationReportsNestedInput - reviewer?: Prisma.UserUpdateOneWithoutModerationReviewsNestedInput - proposal?: Prisma.ProposalUpdateOneWithoutModerationReportsNestedInput -} - -export type ModerationReportUncheckedUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - reporterId?: Prisma.StringFieldUpdateOperationsInput | string - reviewerId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - proposalId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ModerationReportUncheckedUpdateManyWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - reporterId?: Prisma.StringFieldUpdateOperationsInput | string - reviewerId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - proposalId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ModerationReportCreateManyProposalInput = { - id?: string - reporterId: string - reviewerId?: string | null - worldId?: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details?: string | null - status?: $Enums.ModerationStatus - reviewedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ModerationReportUpdateWithoutProposalInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - reporter?: Prisma.UserUpdateOneRequiredWithoutModerationReportsNestedInput - reviewer?: Prisma.UserUpdateOneWithoutModerationReviewsNestedInput - world?: Prisma.WorldUpdateOneWithoutModerationReportsNestedInput -} - -export type ModerationReportUncheckedUpdateWithoutProposalInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - reporterId?: Prisma.StringFieldUpdateOperationsInput | string - reviewerId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - worldId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ModerationReportUncheckedUpdateManyWithoutProposalInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - reporterId?: Prisma.StringFieldUpdateOperationsInput | string - reviewerId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - worldId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - targetType?: Prisma.EnumModerationTargetTypeFieldUpdateOperationsInput | $Enums.ModerationTargetType - targetId?: Prisma.StringFieldUpdateOperationsInput | string - reason?: Prisma.StringFieldUpdateOperationsInput | string - details?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - status?: Prisma.EnumModerationStatusFieldUpdateOperationsInput | $Enums.ModerationStatus - reviewedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - - -export type ModerationReportSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - reporterId?: boolean - reviewerId?: boolean - worldId?: boolean - proposalId?: boolean - targetType?: boolean - targetId?: boolean - reason?: boolean - details?: boolean - status?: boolean - reviewedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - reporter?: boolean | Prisma.UserDefaultArgs - reviewer?: boolean | Prisma.ModerationReport$reviewerArgs - world?: boolean | Prisma.ModerationReport$worldArgs - proposal?: boolean | Prisma.ModerationReport$proposalArgs -}, ExtArgs["result"]["moderationReport"]> - -export type ModerationReportSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - reporterId?: boolean - reviewerId?: boolean - worldId?: boolean - proposalId?: boolean - targetType?: boolean - targetId?: boolean - reason?: boolean - details?: boolean - status?: boolean - reviewedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - reporter?: boolean | Prisma.UserDefaultArgs - reviewer?: boolean | Prisma.ModerationReport$reviewerArgs - world?: boolean | Prisma.ModerationReport$worldArgs - proposal?: boolean | Prisma.ModerationReport$proposalArgs -}, ExtArgs["result"]["moderationReport"]> - -export type ModerationReportSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - reporterId?: boolean - reviewerId?: boolean - worldId?: boolean - proposalId?: boolean - targetType?: boolean - targetId?: boolean - reason?: boolean - details?: boolean - status?: boolean - reviewedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - reporter?: boolean | Prisma.UserDefaultArgs - reviewer?: boolean | Prisma.ModerationReport$reviewerArgs - world?: boolean | Prisma.ModerationReport$worldArgs - proposal?: boolean | Prisma.ModerationReport$proposalArgs -}, ExtArgs["result"]["moderationReport"]> - -export type ModerationReportSelectScalar = { - id?: boolean - reporterId?: boolean - reviewerId?: boolean - worldId?: boolean - proposalId?: boolean - targetType?: boolean - targetId?: boolean - reason?: boolean - details?: boolean - status?: boolean - reviewedAt?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type ModerationReportOmit = runtime.Types.Extensions.GetOmit<"id" | "reporterId" | "reviewerId" | "worldId" | "proposalId" | "targetType" | "targetId" | "reason" | "details" | "status" | "reviewedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["moderationReport"]> -export type ModerationReportInclude = { - reporter?: boolean | Prisma.UserDefaultArgs - reviewer?: boolean | Prisma.ModerationReport$reviewerArgs - world?: boolean | Prisma.ModerationReport$worldArgs - proposal?: boolean | Prisma.ModerationReport$proposalArgs -} -export type ModerationReportIncludeCreateManyAndReturn = { - reporter?: boolean | Prisma.UserDefaultArgs - reviewer?: boolean | Prisma.ModerationReport$reviewerArgs - world?: boolean | Prisma.ModerationReport$worldArgs - proposal?: boolean | Prisma.ModerationReport$proposalArgs -} -export type ModerationReportIncludeUpdateManyAndReturn = { - reporter?: boolean | Prisma.UserDefaultArgs - reviewer?: boolean | Prisma.ModerationReport$reviewerArgs - world?: boolean | Prisma.ModerationReport$worldArgs - proposal?: boolean | Prisma.ModerationReport$proposalArgs -} - -export type $ModerationReportPayload = { - name: "ModerationReport" - objects: { - reporter: Prisma.$UserPayload - reviewer: Prisma.$UserPayload | null - world: Prisma.$WorldPayload | null - proposal: Prisma.$ProposalPayload | null - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - reporterId: string - reviewerId: string | null - worldId: string | null - proposalId: string | null - targetType: $Enums.ModerationTargetType - targetId: string - reason: string - details: string | null - status: $Enums.ModerationStatus - reviewedAt: Date | null - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["moderationReport"]> - composites: {} -} - -export type ModerationReportGetPayload = runtime.Types.Result.GetResult - -export type ModerationReportCountArgs = - Omit & { - select?: ModerationReportCountAggregateInputType | true - } - -export interface ModerationReportDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['ModerationReport'], meta: { name: 'ModerationReport' } } - /** - * Find zero or one ModerationReport that matches the filter. - * @param {ModerationReportFindUniqueArgs} args - Arguments to find a ModerationReport - * @example - * // Get one ModerationReport - * const moderationReport = await prisma.moderationReport.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__ModerationReportClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one ModerationReport that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {ModerationReportFindUniqueOrThrowArgs} args - Arguments to find a ModerationReport - * @example - * // Get one ModerationReport - * const moderationReport = await prisma.moderationReport.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__ModerationReportClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first ModerationReport 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 {ModerationReportFindFirstArgs} args - Arguments to find a ModerationReport - * @example - * // Get one ModerationReport - * const moderationReport = await prisma.moderationReport.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__ModerationReportClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first ModerationReport 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 {ModerationReportFindFirstOrThrowArgs} args - Arguments to find a ModerationReport - * @example - * // Get one ModerationReport - * const moderationReport = await prisma.moderationReport.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__ModerationReportClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more ModerationReports 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 {ModerationReportFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all ModerationReports - * const moderationReports = await prisma.moderationReport.findMany() - * - * // Get first 10 ModerationReports - * const moderationReports = await prisma.moderationReport.findMany({ take: 10 }) - * - * // Only select the `id` - * const moderationReportWithIdOnly = await prisma.moderationReport.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a ModerationReport. - * @param {ModerationReportCreateArgs} args - Arguments to create a ModerationReport. - * @example - * // Create one ModerationReport - * const ModerationReport = await prisma.moderationReport.create({ - * data: { - * // ... data to create a ModerationReport - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__ModerationReportClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many ModerationReports. - * @param {ModerationReportCreateManyArgs} args - Arguments to create many ModerationReports. - * @example - * // Create many ModerationReports - * const moderationReport = await prisma.moderationReport.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many ModerationReports and returns the data saved in the database. - * @param {ModerationReportCreateManyAndReturnArgs} args - Arguments to create many ModerationReports. - * @example - * // Create many ModerationReports - * const moderationReport = await prisma.moderationReport.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many ModerationReports and only return the `id` - * const moderationReportWithIdOnly = await prisma.moderationReport.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 ModerationReport. - * @param {ModerationReportDeleteArgs} args - Arguments to delete one ModerationReport. - * @example - * // Delete one ModerationReport - * const ModerationReport = await prisma.moderationReport.delete({ - * where: { - * // ... filter to delete one ModerationReport - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__ModerationReportClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one ModerationReport. - * @param {ModerationReportUpdateArgs} args - Arguments to update one ModerationReport. - * @example - * // Update one ModerationReport - * const moderationReport = await prisma.moderationReport.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__ModerationReportClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more ModerationReports. - * @param {ModerationReportDeleteManyArgs} args - Arguments to filter ModerationReports to delete. - * @example - * // Delete a few ModerationReports - * const { count } = await prisma.moderationReport.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more ModerationReports. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {ModerationReportUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many ModerationReports - * const moderationReport = await prisma.moderationReport.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more ModerationReports and returns the data updated in the database. - * @param {ModerationReportUpdateManyAndReturnArgs} args - Arguments to update many ModerationReports. - * @example - * // Update many ModerationReports - * const moderationReport = await prisma.moderationReport.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more ModerationReports and only return the `id` - * const moderationReportWithIdOnly = await prisma.moderationReport.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 ModerationReport. - * @param {ModerationReportUpsertArgs} args - Arguments to update or create a ModerationReport. - * @example - * // Update or create a ModerationReport - * const moderationReport = await prisma.moderationReport.upsert({ - * create: { - * // ... data to create a ModerationReport - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the ModerationReport we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__ModerationReportClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of ModerationReports. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {ModerationReportCountArgs} args - Arguments to filter ModerationReports to count. - * @example - * // Count the number of ModerationReports - * const count = await prisma.moderationReport.count({ - * where: { - * // ... the filter for the ModerationReports 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 ModerationReport. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {ModerationReportAggregateArgs} 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 ModerationReport. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {ModerationReportGroupByArgs} 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 ModerationReportGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: ModerationReportGroupByArgs['orderBy'] } - : { orderBy?: ModerationReportGroupByArgs['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 ? GetModerationReportGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the ModerationReport model - */ -readonly fields: ModerationReportFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for ModerationReport. - * 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__ModerationReportClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - reporter = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - reviewer = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - world = {}>(args?: Prisma.Subset>): Prisma.Prisma__WorldClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - proposal = {}>(args?: Prisma.Subset>): Prisma.Prisma__ProposalClient, 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 ModerationReport model - */ -export interface ModerationReportFieldRefs { - readonly id: Prisma.FieldRef<"ModerationReport", 'String'> - readonly reporterId: Prisma.FieldRef<"ModerationReport", 'String'> - readonly reviewerId: Prisma.FieldRef<"ModerationReport", 'String'> - readonly worldId: Prisma.FieldRef<"ModerationReport", 'String'> - readonly proposalId: Prisma.FieldRef<"ModerationReport", 'String'> - readonly targetType: Prisma.FieldRef<"ModerationReport", 'ModerationTargetType'> - readonly targetId: Prisma.FieldRef<"ModerationReport", 'String'> - readonly reason: Prisma.FieldRef<"ModerationReport", 'String'> - readonly details: Prisma.FieldRef<"ModerationReport", 'String'> - readonly status: Prisma.FieldRef<"ModerationReport", 'ModerationStatus'> - readonly reviewedAt: Prisma.FieldRef<"ModerationReport", 'DateTime'> - readonly createdAt: Prisma.FieldRef<"ModerationReport", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"ModerationReport", 'DateTime'> -} - - -// Custom InputTypes -/** - * ModerationReport findUnique - */ -export type ModerationReportFindUniqueArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - /** - * Filter, which ModerationReport to fetch. - */ - where: Prisma.ModerationReportWhereUniqueInput -} - -/** - * ModerationReport findUniqueOrThrow - */ -export type ModerationReportFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - /** - * Filter, which ModerationReport to fetch. - */ - where: Prisma.ModerationReportWhereUniqueInput -} - -/** - * ModerationReport findFirst - */ -export type ModerationReportFindFirstArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - /** - * Filter, which ModerationReport to fetch. - */ - where?: Prisma.ModerationReportWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of ModerationReports to fetch. - */ - orderBy?: Prisma.ModerationReportOrderByWithRelationInput | Prisma.ModerationReportOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for ModerationReports. - */ - cursor?: Prisma.ModerationReportWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` ModerationReports 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` ModerationReports. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of ModerationReports. - */ - distinct?: Prisma.ModerationReportScalarFieldEnum | Prisma.ModerationReportScalarFieldEnum[] -} - -/** - * ModerationReport findFirstOrThrow - */ -export type ModerationReportFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - /** - * Filter, which ModerationReport to fetch. - */ - where?: Prisma.ModerationReportWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of ModerationReports to fetch. - */ - orderBy?: Prisma.ModerationReportOrderByWithRelationInput | Prisma.ModerationReportOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for ModerationReports. - */ - cursor?: Prisma.ModerationReportWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` ModerationReports 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` ModerationReports. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of ModerationReports. - */ - distinct?: Prisma.ModerationReportScalarFieldEnum | Prisma.ModerationReportScalarFieldEnum[] -} - -/** - * ModerationReport findMany - */ -export type ModerationReportFindManyArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - /** - * Filter, which ModerationReports to fetch. - */ - where?: Prisma.ModerationReportWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of ModerationReports to fetch. - */ - orderBy?: Prisma.ModerationReportOrderByWithRelationInput | Prisma.ModerationReportOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing ModerationReports. - */ - cursor?: Prisma.ModerationReportWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` ModerationReports 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` ModerationReports. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of ModerationReports. - */ - distinct?: Prisma.ModerationReportScalarFieldEnum | Prisma.ModerationReportScalarFieldEnum[] -} - -/** - * ModerationReport create - */ -export type ModerationReportCreateArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - /** - * The data needed to create a ModerationReport. - */ - data: Prisma.XOR -} - -/** - * ModerationReport createMany - */ -export type ModerationReportCreateManyArgs = { - /** - * The data used to create many ModerationReports. - */ - data: Prisma.ModerationReportCreateManyInput | Prisma.ModerationReportCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * ModerationReport createManyAndReturn - */ -export type ModerationReportCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelectCreateManyAndReturn | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * The data used to create many ModerationReports. - */ - data: Prisma.ModerationReportCreateManyInput | Prisma.ModerationReportCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportIncludeCreateManyAndReturn | null -} - -/** - * ModerationReport update - */ -export type ModerationReportUpdateArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - /** - * The data needed to update a ModerationReport. - */ - data: Prisma.XOR - /** - * Choose, which ModerationReport to update. - */ - where: Prisma.ModerationReportWhereUniqueInput -} - -/** - * ModerationReport updateMany - */ -export type ModerationReportUpdateManyArgs = { - /** - * The data used to update ModerationReports. - */ - data: Prisma.XOR - /** - * Filter which ModerationReports to update - */ - where?: Prisma.ModerationReportWhereInput - /** - * Limit how many ModerationReports to update. - */ - limit?: number -} - -/** - * ModerationReport updateManyAndReturn - */ -export type ModerationReportUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * The data used to update ModerationReports. - */ - data: Prisma.XOR - /** - * Filter which ModerationReports to update - */ - where?: Prisma.ModerationReportWhereInput - /** - * Limit how many ModerationReports to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportIncludeUpdateManyAndReturn | null -} - -/** - * ModerationReport upsert - */ -export type ModerationReportUpsertArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - /** - * The filter to search for the ModerationReport to update in case it exists. - */ - where: Prisma.ModerationReportWhereUniqueInput - /** - * In case the ModerationReport found by the `where` argument doesn't exist, create a new ModerationReport with this data. - */ - create: Prisma.XOR - /** - * In case the ModerationReport was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * ModerationReport delete - */ -export type ModerationReportDeleteArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - /** - * Filter which ModerationReport to delete. - */ - where: Prisma.ModerationReportWhereUniqueInput -} - -/** - * ModerationReport deleteMany - */ -export type ModerationReportDeleteManyArgs = { - /** - * Filter which ModerationReports to delete - */ - where?: Prisma.ModerationReportWhereInput - /** - * Limit how many ModerationReports to delete. - */ - limit?: number -} - -/** - * ModerationReport.reviewer - */ -export type ModerationReport$reviewerArgs = { - /** - * 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 -} - -/** - * ModerationReport.world - */ -export type ModerationReport$worldArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - where?: Prisma.WorldWhereInput -} - -/** - * ModerationReport.proposal - */ -export type ModerationReport$proposalArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - where?: Prisma.ProposalWhereInput -} - -/** - * ModerationReport without action - */ -export type ModerationReportDefaultArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null -} diff --git a/apps/api/src/generated/prisma/models/Proposal.ts b/apps/api/src/generated/prisma/models/Proposal.ts deleted file mode 100644 index 307bccc..0000000 --- a/apps/api/src/generated/prisma/models/Proposal.ts +++ /dev/null @@ -1,3243 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `Proposal` 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 Proposal - * - */ -export type ProposalModel = runtime.Types.Result.DefaultSelection - -export type AggregateProposal = { - _count: ProposalCountAggregateOutputType | null - _min: ProposalMinAggregateOutputType | null - _max: ProposalMaxAggregateOutputType | null -} - -export type ProposalMinAggregateOutputType = { - id: string | null - worldId: string | null - authorId: string | null - proposalType: $Enums.ProposalType | null - status: $Enums.ProposalStatus | null - title: string | null - summary: string | null - targetLoreEntryId: string | null - resultingLoreEntryId: string | null - resultingBibleVersionId: string | null - submittedAt: Date | null - votingStartedAt: Date | null - approvedAt: Date | null - rejectedAt: Date | null - publishedAt: Date | null - createdAt: Date | null - updatedAt: Date | null -} - -export type ProposalMaxAggregateOutputType = { - id: string | null - worldId: string | null - authorId: string | null - proposalType: $Enums.ProposalType | null - status: $Enums.ProposalStatus | null - title: string | null - summary: string | null - targetLoreEntryId: string | null - resultingLoreEntryId: string | null - resultingBibleVersionId: string | null - submittedAt: Date | null - votingStartedAt: Date | null - approvedAt: Date | null - rejectedAt: Date | null - publishedAt: Date | null - createdAt: Date | null - updatedAt: Date | null -} - -export type ProposalCountAggregateOutputType = { - id: number - worldId: number - authorId: number - proposalType: number - status: number - title: number - summary: number - proposedContent: number - targetLoreEntryId: number - resultingLoreEntryId: number - resultingBibleVersionId: number - submittedAt: number - votingStartedAt: number - approvedAt: number - rejectedAt: number - publishedAt: number - createdAt: number - updatedAt: number - _all: number -} - - -export type ProposalMinAggregateInputType = { - id?: true - worldId?: true - authorId?: true - proposalType?: true - status?: true - title?: true - summary?: true - targetLoreEntryId?: true - resultingLoreEntryId?: true - resultingBibleVersionId?: true - submittedAt?: true - votingStartedAt?: true - approvedAt?: true - rejectedAt?: true - publishedAt?: true - createdAt?: true - updatedAt?: true -} - -export type ProposalMaxAggregateInputType = { - id?: true - worldId?: true - authorId?: true - proposalType?: true - status?: true - title?: true - summary?: true - targetLoreEntryId?: true - resultingLoreEntryId?: true - resultingBibleVersionId?: true - submittedAt?: true - votingStartedAt?: true - approvedAt?: true - rejectedAt?: true - publishedAt?: true - createdAt?: true - updatedAt?: true -} - -export type ProposalCountAggregateInputType = { - id?: true - worldId?: true - authorId?: true - proposalType?: true - status?: true - title?: true - summary?: true - proposedContent?: true - targetLoreEntryId?: true - resultingLoreEntryId?: true - resultingBibleVersionId?: true - submittedAt?: true - votingStartedAt?: true - approvedAt?: true - rejectedAt?: true - publishedAt?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type ProposalAggregateArgs = { - /** - * Filter which Proposal to aggregate. - */ - where?: Prisma.ProposalWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of Proposals to fetch. - */ - orderBy?: Prisma.ProposalOrderByWithRelationInput | Prisma.ProposalOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.ProposalWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` Proposals 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` Proposals. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned Proposals - **/ - _count?: true | ProposalCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: ProposalMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: ProposalMaxAggregateInputType -} - -export type GetProposalAggregateType = { - [P in keyof T & keyof AggregateProposal]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type ProposalGroupByArgs = { - where?: Prisma.ProposalWhereInput - orderBy?: Prisma.ProposalOrderByWithAggregationInput | Prisma.ProposalOrderByWithAggregationInput[] - by: Prisma.ProposalScalarFieldEnum[] | Prisma.ProposalScalarFieldEnum - having?: Prisma.ProposalScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: ProposalCountAggregateInputType | true - _min?: ProposalMinAggregateInputType - _max?: ProposalMaxAggregateInputType -} - -export type ProposalGroupByOutputType = { - id: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status: $Enums.ProposalStatus - title: string - summary: string - proposedContent: runtime.JsonValue - targetLoreEntryId: string | null - resultingLoreEntryId: string | null - resultingBibleVersionId: string | null - submittedAt: Date | null - votingStartedAt: Date | null - approvedAt: Date | null - rejectedAt: Date | null - publishedAt: Date | null - createdAt: Date - updatedAt: Date - _count: ProposalCountAggregateOutputType | null - _min: ProposalMinAggregateOutputType | null - _max: ProposalMaxAggregateOutputType | null -} - -export type GetProposalGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof ProposalGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type ProposalWhereInput = { - AND?: Prisma.ProposalWhereInput | Prisma.ProposalWhereInput[] - OR?: Prisma.ProposalWhereInput[] - NOT?: Prisma.ProposalWhereInput | Prisma.ProposalWhereInput[] - id?: Prisma.StringFilter<"Proposal"> | string - worldId?: Prisma.StringFilter<"Proposal"> | string - authorId?: Prisma.StringFilter<"Proposal"> | string - proposalType?: Prisma.EnumProposalTypeFilter<"Proposal"> | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFilter<"Proposal"> | $Enums.ProposalStatus - title?: Prisma.StringFilter<"Proposal"> | string - summary?: Prisma.StringFilter<"Proposal"> | string - proposedContent?: Prisma.JsonFilter<"Proposal"> - targetLoreEntryId?: Prisma.StringNullableFilter<"Proposal"> | string | null - resultingLoreEntryId?: Prisma.StringNullableFilter<"Proposal"> | string | null - resultingBibleVersionId?: Prisma.StringNullableFilter<"Proposal"> | string | null - submittedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - votingStartedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - approvedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - rejectedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - publishedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - createdAt?: Prisma.DateTimeFilter<"Proposal"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"Proposal"> | Date | string - world?: Prisma.XOR - author?: Prisma.XOR - targetLoreEntry?: Prisma.XOR | null - resultingLoreEntry?: Prisma.XOR | null - resultingBibleVersion?: Prisma.XOR | null - votes?: Prisma.AppVoteListRelationFilter - aiReports?: Prisma.AIReportListRelationFilter - moderationReports?: Prisma.ModerationReportListRelationFilter -} - -export type ProposalOrderByWithRelationInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - authorId?: Prisma.SortOrder - proposalType?: Prisma.SortOrder - status?: Prisma.SortOrder - title?: Prisma.SortOrder - summary?: Prisma.SortOrder - proposedContent?: Prisma.SortOrder - targetLoreEntryId?: Prisma.SortOrderInput | Prisma.SortOrder - resultingLoreEntryId?: Prisma.SortOrderInput | Prisma.SortOrder - resultingBibleVersionId?: Prisma.SortOrderInput | Prisma.SortOrder - submittedAt?: Prisma.SortOrderInput | Prisma.SortOrder - votingStartedAt?: Prisma.SortOrderInput | Prisma.SortOrder - approvedAt?: Prisma.SortOrderInput | Prisma.SortOrder - rejectedAt?: Prisma.SortOrderInput | Prisma.SortOrder - publishedAt?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - world?: Prisma.WorldOrderByWithRelationInput - author?: Prisma.UserOrderByWithRelationInput - targetLoreEntry?: Prisma.LoreEntryOrderByWithRelationInput - resultingLoreEntry?: Prisma.LoreEntryOrderByWithRelationInput - resultingBibleVersion?: Prisma.WorldBibleVersionOrderByWithRelationInput - votes?: Prisma.AppVoteOrderByRelationAggregateInput - aiReports?: Prisma.AIReportOrderByRelationAggregateInput - moderationReports?: Prisma.ModerationReportOrderByRelationAggregateInput -} - -export type ProposalWhereUniqueInput = Prisma.AtLeast<{ - id?: string - resultingBibleVersionId?: string - AND?: Prisma.ProposalWhereInput | Prisma.ProposalWhereInput[] - OR?: Prisma.ProposalWhereInput[] - NOT?: Prisma.ProposalWhereInput | Prisma.ProposalWhereInput[] - worldId?: Prisma.StringFilter<"Proposal"> | string - authorId?: Prisma.StringFilter<"Proposal"> | string - proposalType?: Prisma.EnumProposalTypeFilter<"Proposal"> | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFilter<"Proposal"> | $Enums.ProposalStatus - title?: Prisma.StringFilter<"Proposal"> | string - summary?: Prisma.StringFilter<"Proposal"> | string - proposedContent?: Prisma.JsonFilter<"Proposal"> - targetLoreEntryId?: Prisma.StringNullableFilter<"Proposal"> | string | null - resultingLoreEntryId?: Prisma.StringNullableFilter<"Proposal"> | string | null - submittedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - votingStartedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - approvedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - rejectedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - publishedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - createdAt?: Prisma.DateTimeFilter<"Proposal"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"Proposal"> | Date | string - world?: Prisma.XOR - author?: Prisma.XOR - targetLoreEntry?: Prisma.XOR | null - resultingLoreEntry?: Prisma.XOR | null - resultingBibleVersion?: Prisma.XOR | null - votes?: Prisma.AppVoteListRelationFilter - aiReports?: Prisma.AIReportListRelationFilter - moderationReports?: Prisma.ModerationReportListRelationFilter -}, "id" | "resultingBibleVersionId"> - -export type ProposalOrderByWithAggregationInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - authorId?: Prisma.SortOrder - proposalType?: Prisma.SortOrder - status?: Prisma.SortOrder - title?: Prisma.SortOrder - summary?: Prisma.SortOrder - proposedContent?: Prisma.SortOrder - targetLoreEntryId?: Prisma.SortOrderInput | Prisma.SortOrder - resultingLoreEntryId?: Prisma.SortOrderInput | Prisma.SortOrder - resultingBibleVersionId?: Prisma.SortOrderInput | Prisma.SortOrder - submittedAt?: Prisma.SortOrderInput | Prisma.SortOrder - votingStartedAt?: Prisma.SortOrderInput | Prisma.SortOrder - approvedAt?: Prisma.SortOrderInput | Prisma.SortOrder - rejectedAt?: Prisma.SortOrderInput | Prisma.SortOrder - publishedAt?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.ProposalCountOrderByAggregateInput - _max?: Prisma.ProposalMaxOrderByAggregateInput - _min?: Prisma.ProposalMinOrderByAggregateInput -} - -export type ProposalScalarWhereWithAggregatesInput = { - AND?: Prisma.ProposalScalarWhereWithAggregatesInput | Prisma.ProposalScalarWhereWithAggregatesInput[] - OR?: Prisma.ProposalScalarWhereWithAggregatesInput[] - NOT?: Prisma.ProposalScalarWhereWithAggregatesInput | Prisma.ProposalScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"Proposal"> | string - worldId?: Prisma.StringWithAggregatesFilter<"Proposal"> | string - authorId?: Prisma.StringWithAggregatesFilter<"Proposal"> | string - proposalType?: Prisma.EnumProposalTypeWithAggregatesFilter<"Proposal"> | $Enums.ProposalType - status?: Prisma.EnumProposalStatusWithAggregatesFilter<"Proposal"> | $Enums.ProposalStatus - title?: Prisma.StringWithAggregatesFilter<"Proposal"> | string - summary?: Prisma.StringWithAggregatesFilter<"Proposal"> | string - proposedContent?: Prisma.JsonWithAggregatesFilter<"Proposal"> - targetLoreEntryId?: Prisma.StringNullableWithAggregatesFilter<"Proposal"> | string | null - resultingLoreEntryId?: Prisma.StringNullableWithAggregatesFilter<"Proposal"> | string | null - resultingBibleVersionId?: Prisma.StringNullableWithAggregatesFilter<"Proposal"> | string | null - submittedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Proposal"> | Date | string | null - votingStartedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Proposal"> | Date | string | null - approvedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Proposal"> | Date | string | null - rejectedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Proposal"> | Date | string | null - publishedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Proposal"> | Date | string | null - createdAt?: Prisma.DateTimeWithAggregatesFilter<"Proposal"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Proposal"> | Date | string -} - -export type ProposalCreateInput = { - id?: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutProposalsInput - author: Prisma.UserCreateNestedOneWithoutProposalsInput - targetLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutTargetProposalsInput - resultingLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutResultingProposalsInput - resultingBibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutProposalsInput - votes?: Prisma.AppVoteCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutProposalInput -} - -export type ProposalUncheckedCreateInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportUncheckedCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutProposalInput -} - -export type ProposalUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutProposalsNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutProposalsNestedInput - targetLoreEntry?: Prisma.LoreEntryUpdateOneWithoutTargetProposalsNestedInput - resultingLoreEntry?: Prisma.LoreEntryUpdateOneWithoutResultingProposalsNestedInput - resultingBibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutProposalsNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUncheckedUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutProposalNestedInput -} - -export type ProposalCreateManyInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ProposalUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ProposalUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ProposalListRelationFilter = { - every?: Prisma.ProposalWhereInput - some?: Prisma.ProposalWhereInput - none?: Prisma.ProposalWhereInput -} - -export type ProposalOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type ProposalCountOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - authorId?: Prisma.SortOrder - proposalType?: Prisma.SortOrder - status?: Prisma.SortOrder - title?: Prisma.SortOrder - summary?: Prisma.SortOrder - proposedContent?: Prisma.SortOrder - targetLoreEntryId?: Prisma.SortOrder - resultingLoreEntryId?: Prisma.SortOrder - resultingBibleVersionId?: Prisma.SortOrder - submittedAt?: Prisma.SortOrder - votingStartedAt?: Prisma.SortOrder - approvedAt?: Prisma.SortOrder - rejectedAt?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type ProposalMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - authorId?: Prisma.SortOrder - proposalType?: Prisma.SortOrder - status?: Prisma.SortOrder - title?: Prisma.SortOrder - summary?: Prisma.SortOrder - targetLoreEntryId?: Prisma.SortOrder - resultingLoreEntryId?: Prisma.SortOrder - resultingBibleVersionId?: Prisma.SortOrder - submittedAt?: Prisma.SortOrder - votingStartedAt?: Prisma.SortOrder - approvedAt?: Prisma.SortOrder - rejectedAt?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type ProposalMinOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - authorId?: Prisma.SortOrder - proposalType?: Prisma.SortOrder - status?: Prisma.SortOrder - title?: Prisma.SortOrder - summary?: Prisma.SortOrder - targetLoreEntryId?: Prisma.SortOrder - resultingLoreEntryId?: Prisma.SortOrder - resultingBibleVersionId?: Prisma.SortOrder - submittedAt?: Prisma.SortOrder - votingStartedAt?: Prisma.SortOrder - approvedAt?: Prisma.SortOrder - rejectedAt?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type ProposalScalarRelationFilter = { - is?: Prisma.ProposalWhereInput - isNot?: Prisma.ProposalWhereInput -} - -export type ProposalNullableScalarRelationFilter = { - is?: Prisma.ProposalWhereInput | null - isNot?: Prisma.ProposalWhereInput | null -} - -export type ProposalCreateNestedManyWithoutAuthorInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutAuthorInput[] | Prisma.ProposalUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutAuthorInput | Prisma.ProposalCreateOrConnectWithoutAuthorInput[] - createMany?: Prisma.ProposalCreateManyAuthorInputEnvelope - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] -} - -export type ProposalUncheckedCreateNestedManyWithoutAuthorInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutAuthorInput[] | Prisma.ProposalUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutAuthorInput | Prisma.ProposalCreateOrConnectWithoutAuthorInput[] - createMany?: Prisma.ProposalCreateManyAuthorInputEnvelope - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] -} - -export type ProposalUpdateManyWithoutAuthorNestedInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutAuthorInput[] | Prisma.ProposalUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutAuthorInput | Prisma.ProposalCreateOrConnectWithoutAuthorInput[] - upsert?: Prisma.ProposalUpsertWithWhereUniqueWithoutAuthorInput | Prisma.ProposalUpsertWithWhereUniqueWithoutAuthorInput[] - createMany?: Prisma.ProposalCreateManyAuthorInputEnvelope - set?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - disconnect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - delete?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - update?: Prisma.ProposalUpdateWithWhereUniqueWithoutAuthorInput | Prisma.ProposalUpdateWithWhereUniqueWithoutAuthorInput[] - updateMany?: Prisma.ProposalUpdateManyWithWhereWithoutAuthorInput | Prisma.ProposalUpdateManyWithWhereWithoutAuthorInput[] - deleteMany?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] -} - -export type ProposalUncheckedUpdateManyWithoutAuthorNestedInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutAuthorInput[] | Prisma.ProposalUncheckedCreateWithoutAuthorInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutAuthorInput | Prisma.ProposalCreateOrConnectWithoutAuthorInput[] - upsert?: Prisma.ProposalUpsertWithWhereUniqueWithoutAuthorInput | Prisma.ProposalUpsertWithWhereUniqueWithoutAuthorInput[] - createMany?: Prisma.ProposalCreateManyAuthorInputEnvelope - set?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - disconnect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - delete?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - update?: Prisma.ProposalUpdateWithWhereUniqueWithoutAuthorInput | Prisma.ProposalUpdateWithWhereUniqueWithoutAuthorInput[] - updateMany?: Prisma.ProposalUpdateManyWithWhereWithoutAuthorInput | Prisma.ProposalUpdateManyWithWhereWithoutAuthorInput[] - deleteMany?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] -} - -export type ProposalCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutWorldInput[] | Prisma.ProposalUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutWorldInput | Prisma.ProposalCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.ProposalCreateManyWorldInputEnvelope - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] -} - -export type ProposalUncheckedCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutWorldInput[] | Prisma.ProposalUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutWorldInput | Prisma.ProposalCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.ProposalCreateManyWorldInputEnvelope - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] -} - -export type ProposalUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutWorldInput[] | Prisma.ProposalUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutWorldInput | Prisma.ProposalCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.ProposalUpsertWithWhereUniqueWithoutWorldInput | Prisma.ProposalUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.ProposalCreateManyWorldInputEnvelope - set?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - disconnect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - delete?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - update?: Prisma.ProposalUpdateWithWhereUniqueWithoutWorldInput | Prisma.ProposalUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.ProposalUpdateManyWithWhereWithoutWorldInput | Prisma.ProposalUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] -} - -export type ProposalUncheckedUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutWorldInput[] | Prisma.ProposalUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutWorldInput | Prisma.ProposalCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.ProposalUpsertWithWhereUniqueWithoutWorldInput | Prisma.ProposalUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.ProposalCreateManyWorldInputEnvelope - set?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - disconnect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - delete?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - update?: Prisma.ProposalUpdateWithWhereUniqueWithoutWorldInput | Prisma.ProposalUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.ProposalUpdateManyWithWhereWithoutWorldInput | Prisma.ProposalUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] -} - -export type ProposalCreateNestedManyWithoutResultingBibleVersionInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutResultingBibleVersionInput[] | Prisma.ProposalUncheckedCreateWithoutResultingBibleVersionInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutResultingBibleVersionInput | Prisma.ProposalCreateOrConnectWithoutResultingBibleVersionInput[] - createMany?: Prisma.ProposalCreateManyResultingBibleVersionInputEnvelope - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] -} - -export type ProposalUncheckedCreateNestedManyWithoutResultingBibleVersionInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutResultingBibleVersionInput[] | Prisma.ProposalUncheckedCreateWithoutResultingBibleVersionInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutResultingBibleVersionInput | Prisma.ProposalCreateOrConnectWithoutResultingBibleVersionInput[] - createMany?: Prisma.ProposalCreateManyResultingBibleVersionInputEnvelope - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] -} - -export type ProposalUpdateManyWithoutResultingBibleVersionNestedInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutResultingBibleVersionInput[] | Prisma.ProposalUncheckedCreateWithoutResultingBibleVersionInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutResultingBibleVersionInput | Prisma.ProposalCreateOrConnectWithoutResultingBibleVersionInput[] - upsert?: Prisma.ProposalUpsertWithWhereUniqueWithoutResultingBibleVersionInput | Prisma.ProposalUpsertWithWhereUniqueWithoutResultingBibleVersionInput[] - createMany?: Prisma.ProposalCreateManyResultingBibleVersionInputEnvelope - set?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - disconnect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - delete?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - update?: Prisma.ProposalUpdateWithWhereUniqueWithoutResultingBibleVersionInput | Prisma.ProposalUpdateWithWhereUniqueWithoutResultingBibleVersionInput[] - updateMany?: Prisma.ProposalUpdateManyWithWhereWithoutResultingBibleVersionInput | Prisma.ProposalUpdateManyWithWhereWithoutResultingBibleVersionInput[] - deleteMany?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] -} - -export type ProposalUncheckedUpdateManyWithoutResultingBibleVersionNestedInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutResultingBibleVersionInput[] | Prisma.ProposalUncheckedCreateWithoutResultingBibleVersionInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutResultingBibleVersionInput | Prisma.ProposalCreateOrConnectWithoutResultingBibleVersionInput[] - upsert?: Prisma.ProposalUpsertWithWhereUniqueWithoutResultingBibleVersionInput | Prisma.ProposalUpsertWithWhereUniqueWithoutResultingBibleVersionInput[] - createMany?: Prisma.ProposalCreateManyResultingBibleVersionInputEnvelope - set?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - disconnect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - delete?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - update?: Prisma.ProposalUpdateWithWhereUniqueWithoutResultingBibleVersionInput | Prisma.ProposalUpdateWithWhereUniqueWithoutResultingBibleVersionInput[] - updateMany?: Prisma.ProposalUpdateManyWithWhereWithoutResultingBibleVersionInput | Prisma.ProposalUpdateManyWithWhereWithoutResultingBibleVersionInput[] - deleteMany?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] -} - -export type ProposalCreateNestedManyWithoutTargetLoreEntryInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutTargetLoreEntryInput[] | Prisma.ProposalUncheckedCreateWithoutTargetLoreEntryInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutTargetLoreEntryInput | Prisma.ProposalCreateOrConnectWithoutTargetLoreEntryInput[] - createMany?: Prisma.ProposalCreateManyTargetLoreEntryInputEnvelope - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] -} - -export type ProposalCreateNestedManyWithoutResultingLoreEntryInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutResultingLoreEntryInput[] | Prisma.ProposalUncheckedCreateWithoutResultingLoreEntryInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutResultingLoreEntryInput | Prisma.ProposalCreateOrConnectWithoutResultingLoreEntryInput[] - createMany?: Prisma.ProposalCreateManyResultingLoreEntryInputEnvelope - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] -} - -export type ProposalUncheckedCreateNestedManyWithoutTargetLoreEntryInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutTargetLoreEntryInput[] | Prisma.ProposalUncheckedCreateWithoutTargetLoreEntryInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutTargetLoreEntryInput | Prisma.ProposalCreateOrConnectWithoutTargetLoreEntryInput[] - createMany?: Prisma.ProposalCreateManyTargetLoreEntryInputEnvelope - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] -} - -export type ProposalUncheckedCreateNestedManyWithoutResultingLoreEntryInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutResultingLoreEntryInput[] | Prisma.ProposalUncheckedCreateWithoutResultingLoreEntryInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutResultingLoreEntryInput | Prisma.ProposalCreateOrConnectWithoutResultingLoreEntryInput[] - createMany?: Prisma.ProposalCreateManyResultingLoreEntryInputEnvelope - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] -} - -export type ProposalUpdateManyWithoutTargetLoreEntryNestedInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutTargetLoreEntryInput[] | Prisma.ProposalUncheckedCreateWithoutTargetLoreEntryInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutTargetLoreEntryInput | Prisma.ProposalCreateOrConnectWithoutTargetLoreEntryInput[] - upsert?: Prisma.ProposalUpsertWithWhereUniqueWithoutTargetLoreEntryInput | Prisma.ProposalUpsertWithWhereUniqueWithoutTargetLoreEntryInput[] - createMany?: Prisma.ProposalCreateManyTargetLoreEntryInputEnvelope - set?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - disconnect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - delete?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - update?: Prisma.ProposalUpdateWithWhereUniqueWithoutTargetLoreEntryInput | Prisma.ProposalUpdateWithWhereUniqueWithoutTargetLoreEntryInput[] - updateMany?: Prisma.ProposalUpdateManyWithWhereWithoutTargetLoreEntryInput | Prisma.ProposalUpdateManyWithWhereWithoutTargetLoreEntryInput[] - deleteMany?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] -} - -export type ProposalUpdateManyWithoutResultingLoreEntryNestedInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutResultingLoreEntryInput[] | Prisma.ProposalUncheckedCreateWithoutResultingLoreEntryInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutResultingLoreEntryInput | Prisma.ProposalCreateOrConnectWithoutResultingLoreEntryInput[] - upsert?: Prisma.ProposalUpsertWithWhereUniqueWithoutResultingLoreEntryInput | Prisma.ProposalUpsertWithWhereUniqueWithoutResultingLoreEntryInput[] - createMany?: Prisma.ProposalCreateManyResultingLoreEntryInputEnvelope - set?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - disconnect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - delete?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - update?: Prisma.ProposalUpdateWithWhereUniqueWithoutResultingLoreEntryInput | Prisma.ProposalUpdateWithWhereUniqueWithoutResultingLoreEntryInput[] - updateMany?: Prisma.ProposalUpdateManyWithWhereWithoutResultingLoreEntryInput | Prisma.ProposalUpdateManyWithWhereWithoutResultingLoreEntryInput[] - deleteMany?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] -} - -export type ProposalUncheckedUpdateManyWithoutTargetLoreEntryNestedInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutTargetLoreEntryInput[] | Prisma.ProposalUncheckedCreateWithoutTargetLoreEntryInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutTargetLoreEntryInput | Prisma.ProposalCreateOrConnectWithoutTargetLoreEntryInput[] - upsert?: Prisma.ProposalUpsertWithWhereUniqueWithoutTargetLoreEntryInput | Prisma.ProposalUpsertWithWhereUniqueWithoutTargetLoreEntryInput[] - createMany?: Prisma.ProposalCreateManyTargetLoreEntryInputEnvelope - set?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - disconnect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - delete?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - update?: Prisma.ProposalUpdateWithWhereUniqueWithoutTargetLoreEntryInput | Prisma.ProposalUpdateWithWhereUniqueWithoutTargetLoreEntryInput[] - updateMany?: Prisma.ProposalUpdateManyWithWhereWithoutTargetLoreEntryInput | Prisma.ProposalUpdateManyWithWhereWithoutTargetLoreEntryInput[] - deleteMany?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] -} - -export type ProposalUncheckedUpdateManyWithoutResultingLoreEntryNestedInput = { - create?: Prisma.XOR | Prisma.ProposalCreateWithoutResultingLoreEntryInput[] | Prisma.ProposalUncheckedCreateWithoutResultingLoreEntryInput[] - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutResultingLoreEntryInput | Prisma.ProposalCreateOrConnectWithoutResultingLoreEntryInput[] - upsert?: Prisma.ProposalUpsertWithWhereUniqueWithoutResultingLoreEntryInput | Prisma.ProposalUpsertWithWhereUniqueWithoutResultingLoreEntryInput[] - createMany?: Prisma.ProposalCreateManyResultingLoreEntryInputEnvelope - set?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - disconnect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - delete?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - connect?: Prisma.ProposalWhereUniqueInput | Prisma.ProposalWhereUniqueInput[] - update?: Prisma.ProposalUpdateWithWhereUniqueWithoutResultingLoreEntryInput | Prisma.ProposalUpdateWithWhereUniqueWithoutResultingLoreEntryInput[] - updateMany?: Prisma.ProposalUpdateManyWithWhereWithoutResultingLoreEntryInput | Prisma.ProposalUpdateManyWithWhereWithoutResultingLoreEntryInput[] - deleteMany?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] -} - -export type EnumProposalTypeFieldUpdateOperationsInput = { - set?: $Enums.ProposalType -} - -export type EnumProposalStatusFieldUpdateOperationsInput = { - set?: $Enums.ProposalStatus -} - -export type ProposalCreateNestedOneWithoutVotesInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutVotesInput - connect?: Prisma.ProposalWhereUniqueInput -} - -export type ProposalUpdateOneRequiredWithoutVotesNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutVotesInput - upsert?: Prisma.ProposalUpsertWithoutVotesInput - connect?: Prisma.ProposalWhereUniqueInput - update?: Prisma.XOR, Prisma.ProposalUncheckedUpdateWithoutVotesInput> -} - -export type ProposalCreateNestedOneWithoutAiReportsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutAiReportsInput - connect?: Prisma.ProposalWhereUniqueInput -} - -export type ProposalUpdateOneRequiredWithoutAiReportsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutAiReportsInput - upsert?: Prisma.ProposalUpsertWithoutAiReportsInput - connect?: Prisma.ProposalWhereUniqueInput - update?: Prisma.XOR, Prisma.ProposalUncheckedUpdateWithoutAiReportsInput> -} - -export type ProposalCreateNestedOneWithoutModerationReportsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutModerationReportsInput - connect?: Prisma.ProposalWhereUniqueInput -} - -export type ProposalUpdateOneWithoutModerationReportsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.ProposalCreateOrConnectWithoutModerationReportsInput - upsert?: Prisma.ProposalUpsertWithoutModerationReportsInput - disconnect?: Prisma.ProposalWhereInput | boolean - delete?: Prisma.ProposalWhereInput | boolean - connect?: Prisma.ProposalWhereUniqueInput - update?: Prisma.XOR, Prisma.ProposalUncheckedUpdateWithoutModerationReportsInput> -} - -export type ProposalCreateWithoutAuthorInput = { - id?: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutProposalsInput - targetLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutTargetProposalsInput - resultingLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutResultingProposalsInput - resultingBibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutProposalsInput - votes?: Prisma.AppVoteCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutProposalInput -} - -export type ProposalUncheckedCreateWithoutAuthorInput = { - id?: string - worldId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportUncheckedCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutProposalInput -} - -export type ProposalCreateOrConnectWithoutAuthorInput = { - where: Prisma.ProposalWhereUniqueInput - create: Prisma.XOR -} - -export type ProposalCreateManyAuthorInputEnvelope = { - data: Prisma.ProposalCreateManyAuthorInput | Prisma.ProposalCreateManyAuthorInput[] - skipDuplicates?: boolean -} - -export type ProposalUpsertWithWhereUniqueWithoutAuthorInput = { - where: Prisma.ProposalWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type ProposalUpdateWithWhereUniqueWithoutAuthorInput = { - where: Prisma.ProposalWhereUniqueInput - data: Prisma.XOR -} - -export type ProposalUpdateManyWithWhereWithoutAuthorInput = { - where: Prisma.ProposalScalarWhereInput - data: Prisma.XOR -} - -export type ProposalScalarWhereInput = { - AND?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] - OR?: Prisma.ProposalScalarWhereInput[] - NOT?: Prisma.ProposalScalarWhereInput | Prisma.ProposalScalarWhereInput[] - id?: Prisma.StringFilter<"Proposal"> | string - worldId?: Prisma.StringFilter<"Proposal"> | string - authorId?: Prisma.StringFilter<"Proposal"> | string - proposalType?: Prisma.EnumProposalTypeFilter<"Proposal"> | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFilter<"Proposal"> | $Enums.ProposalStatus - title?: Prisma.StringFilter<"Proposal"> | string - summary?: Prisma.StringFilter<"Proposal"> | string - proposedContent?: Prisma.JsonFilter<"Proposal"> - targetLoreEntryId?: Prisma.StringNullableFilter<"Proposal"> | string | null - resultingLoreEntryId?: Prisma.StringNullableFilter<"Proposal"> | string | null - resultingBibleVersionId?: Prisma.StringNullableFilter<"Proposal"> | string | null - submittedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - votingStartedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - approvedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - rejectedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - publishedAt?: Prisma.DateTimeNullableFilter<"Proposal"> | Date | string | null - createdAt?: Prisma.DateTimeFilter<"Proposal"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"Proposal"> | Date | string -} - -export type ProposalCreateWithoutWorldInput = { - id?: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - author: Prisma.UserCreateNestedOneWithoutProposalsInput - targetLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutTargetProposalsInput - resultingLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutResultingProposalsInput - resultingBibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutProposalsInput - votes?: Prisma.AppVoteCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutProposalInput -} - -export type ProposalUncheckedCreateWithoutWorldInput = { - id?: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportUncheckedCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutProposalInput -} - -export type ProposalCreateOrConnectWithoutWorldInput = { - where: Prisma.ProposalWhereUniqueInput - create: Prisma.XOR -} - -export type ProposalCreateManyWorldInputEnvelope = { - data: Prisma.ProposalCreateManyWorldInput | Prisma.ProposalCreateManyWorldInput[] - skipDuplicates?: boolean -} - -export type ProposalUpsertWithWhereUniqueWithoutWorldInput = { - where: Prisma.ProposalWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type ProposalUpdateWithWhereUniqueWithoutWorldInput = { - where: Prisma.ProposalWhereUniqueInput - data: Prisma.XOR -} - -export type ProposalUpdateManyWithWhereWithoutWorldInput = { - where: Prisma.ProposalScalarWhereInput - data: Prisma.XOR -} - -export type ProposalCreateWithoutResultingBibleVersionInput = { - id?: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutProposalsInput - author: Prisma.UserCreateNestedOneWithoutProposalsInput - targetLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutTargetProposalsInput - resultingLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutResultingProposalsInput - votes?: Prisma.AppVoteCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutProposalInput -} - -export type ProposalUncheckedCreateWithoutResultingBibleVersionInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportUncheckedCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutProposalInput -} - -export type ProposalCreateOrConnectWithoutResultingBibleVersionInput = { - where: Prisma.ProposalWhereUniqueInput - create: Prisma.XOR -} - -export type ProposalCreateManyResultingBibleVersionInputEnvelope = { - data: Prisma.ProposalCreateManyResultingBibleVersionInput | Prisma.ProposalCreateManyResultingBibleVersionInput[] - skipDuplicates?: boolean -} - -export type ProposalUpsertWithWhereUniqueWithoutResultingBibleVersionInput = { - where: Prisma.ProposalWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type ProposalUpdateWithWhereUniqueWithoutResultingBibleVersionInput = { - where: Prisma.ProposalWhereUniqueInput - data: Prisma.XOR -} - -export type ProposalUpdateManyWithWhereWithoutResultingBibleVersionInput = { - where: Prisma.ProposalScalarWhereInput - data: Prisma.XOR -} - -export type ProposalCreateWithoutTargetLoreEntryInput = { - id?: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutProposalsInput - author: Prisma.UserCreateNestedOneWithoutProposalsInput - resultingLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutResultingProposalsInput - resultingBibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutProposalsInput - votes?: Prisma.AppVoteCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutProposalInput -} - -export type ProposalUncheckedCreateWithoutTargetLoreEntryInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportUncheckedCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutProposalInput -} - -export type ProposalCreateOrConnectWithoutTargetLoreEntryInput = { - where: Prisma.ProposalWhereUniqueInput - create: Prisma.XOR -} - -export type ProposalCreateManyTargetLoreEntryInputEnvelope = { - data: Prisma.ProposalCreateManyTargetLoreEntryInput | Prisma.ProposalCreateManyTargetLoreEntryInput[] - skipDuplicates?: boolean -} - -export type ProposalCreateWithoutResultingLoreEntryInput = { - id?: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutProposalsInput - author: Prisma.UserCreateNestedOneWithoutProposalsInput - targetLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutTargetProposalsInput - resultingBibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutProposalsInput - votes?: Prisma.AppVoteCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutProposalInput -} - -export type ProposalUncheckedCreateWithoutResultingLoreEntryInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportUncheckedCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutProposalInput -} - -export type ProposalCreateOrConnectWithoutResultingLoreEntryInput = { - where: Prisma.ProposalWhereUniqueInput - create: Prisma.XOR -} - -export type ProposalCreateManyResultingLoreEntryInputEnvelope = { - data: Prisma.ProposalCreateManyResultingLoreEntryInput | Prisma.ProposalCreateManyResultingLoreEntryInput[] - skipDuplicates?: boolean -} - -export type ProposalUpsertWithWhereUniqueWithoutTargetLoreEntryInput = { - where: Prisma.ProposalWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type ProposalUpdateWithWhereUniqueWithoutTargetLoreEntryInput = { - where: Prisma.ProposalWhereUniqueInput - data: Prisma.XOR -} - -export type ProposalUpdateManyWithWhereWithoutTargetLoreEntryInput = { - where: Prisma.ProposalScalarWhereInput - data: Prisma.XOR -} - -export type ProposalUpsertWithWhereUniqueWithoutResultingLoreEntryInput = { - where: Prisma.ProposalWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type ProposalUpdateWithWhereUniqueWithoutResultingLoreEntryInput = { - where: Prisma.ProposalWhereUniqueInput - data: Prisma.XOR -} - -export type ProposalUpdateManyWithWhereWithoutResultingLoreEntryInput = { - where: Prisma.ProposalScalarWhereInput - data: Prisma.XOR -} - -export type ProposalCreateWithoutVotesInput = { - id?: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutProposalsInput - author: Prisma.UserCreateNestedOneWithoutProposalsInput - targetLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutTargetProposalsInput - resultingLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutResultingProposalsInput - resultingBibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutProposalsInput - aiReports?: Prisma.AIReportCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutProposalInput -} - -export type ProposalUncheckedCreateWithoutVotesInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - aiReports?: Prisma.AIReportUncheckedCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutProposalInput -} - -export type ProposalCreateOrConnectWithoutVotesInput = { - where: Prisma.ProposalWhereUniqueInput - create: Prisma.XOR -} - -export type ProposalUpsertWithoutVotesInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.ProposalWhereInput -} - -export type ProposalUpdateToOneWithWhereWithoutVotesInput = { - where?: Prisma.ProposalWhereInput - data: Prisma.XOR -} - -export type ProposalUpdateWithoutVotesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutProposalsNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutProposalsNestedInput - targetLoreEntry?: Prisma.LoreEntryUpdateOneWithoutTargetProposalsNestedInput - resultingLoreEntry?: Prisma.LoreEntryUpdateOneWithoutResultingProposalsNestedInput - resultingBibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutProposalsNestedInput - aiReports?: Prisma.AIReportUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateWithoutVotesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - aiReports?: Prisma.AIReportUncheckedUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutProposalNestedInput -} - -export type ProposalCreateWithoutAiReportsInput = { - id?: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutProposalsInput - author: Prisma.UserCreateNestedOneWithoutProposalsInput - targetLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutTargetProposalsInput - resultingLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutResultingProposalsInput - resultingBibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutProposalsInput - votes?: Prisma.AppVoteCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutProposalInput -} - -export type ProposalUncheckedCreateWithoutAiReportsInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutProposalInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutProposalInput -} - -export type ProposalCreateOrConnectWithoutAiReportsInput = { - where: Prisma.ProposalWhereUniqueInput - create: Prisma.XOR -} - -export type ProposalUpsertWithoutAiReportsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.ProposalWhereInput -} - -export type ProposalUpdateToOneWithWhereWithoutAiReportsInput = { - where?: Prisma.ProposalWhereInput - data: Prisma.XOR -} - -export type ProposalUpdateWithoutAiReportsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutProposalsNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutProposalsNestedInput - targetLoreEntry?: Prisma.LoreEntryUpdateOneWithoutTargetProposalsNestedInput - resultingLoreEntry?: Prisma.LoreEntryUpdateOneWithoutResultingProposalsNestedInput - resultingBibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutProposalsNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateWithoutAiReportsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutProposalNestedInput -} - -export type ProposalCreateWithoutModerationReportsInput = { - id?: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutProposalsInput - author: Prisma.UserCreateNestedOneWithoutProposalsInput - targetLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutTargetProposalsInput - resultingLoreEntry?: Prisma.LoreEntryCreateNestedOneWithoutResultingProposalsInput - resultingBibleVersion?: Prisma.WorldBibleVersionCreateNestedOneWithoutProposalsInput - votes?: Prisma.AppVoteCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportCreateNestedManyWithoutProposalInput -} - -export type ProposalUncheckedCreateWithoutModerationReportsInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutProposalInput - aiReports?: Prisma.AIReportUncheckedCreateNestedManyWithoutProposalInput -} - -export type ProposalCreateOrConnectWithoutModerationReportsInput = { - where: Prisma.ProposalWhereUniqueInput - create: Prisma.XOR -} - -export type ProposalUpsertWithoutModerationReportsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.ProposalWhereInput -} - -export type ProposalUpdateToOneWithWhereWithoutModerationReportsInput = { - where?: Prisma.ProposalWhereInput - data: Prisma.XOR -} - -export type ProposalUpdateWithoutModerationReportsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutProposalsNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutProposalsNestedInput - targetLoreEntry?: Prisma.LoreEntryUpdateOneWithoutTargetProposalsNestedInput - resultingLoreEntry?: Prisma.LoreEntryUpdateOneWithoutResultingProposalsNestedInput - resultingBibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutProposalsNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateWithoutModerationReportsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUncheckedUpdateManyWithoutProposalNestedInput -} - -export type ProposalCreateManyAuthorInput = { - id?: string - worldId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ProposalUpdateWithoutAuthorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutProposalsNestedInput - targetLoreEntry?: Prisma.LoreEntryUpdateOneWithoutTargetProposalsNestedInput - resultingLoreEntry?: Prisma.LoreEntryUpdateOneWithoutResultingProposalsNestedInput - resultingBibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutProposalsNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateWithoutAuthorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUncheckedUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateManyWithoutAuthorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ProposalCreateManyWorldInput = { - id?: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ProposalUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - author?: Prisma.UserUpdateOneRequiredWithoutProposalsNestedInput - targetLoreEntry?: Prisma.LoreEntryUpdateOneWithoutTargetProposalsNestedInput - resultingLoreEntry?: Prisma.LoreEntryUpdateOneWithoutResultingProposalsNestedInput - resultingBibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutProposalsNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUncheckedUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateManyWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ProposalCreateManyResultingBibleVersionInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingLoreEntryId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ProposalUpdateWithoutResultingBibleVersionInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutProposalsNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutProposalsNestedInput - targetLoreEntry?: Prisma.LoreEntryUpdateOneWithoutTargetProposalsNestedInput - resultingLoreEntry?: Prisma.LoreEntryUpdateOneWithoutResultingProposalsNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateWithoutResultingBibleVersionInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUncheckedUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateManyWithoutResultingBibleVersionInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ProposalCreateManyTargetLoreEntryInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - resultingLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ProposalCreateManyResultingLoreEntryInput = { - id?: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status?: $Enums.ProposalStatus - title: string - summary: string - proposedContent: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: string | null - resultingBibleVersionId?: string | null - submittedAt?: Date | string | null - votingStartedAt?: Date | string | null - approvedAt?: Date | string | null - rejectedAt?: Date | string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type ProposalUpdateWithoutTargetLoreEntryInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutProposalsNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutProposalsNestedInput - resultingLoreEntry?: Prisma.LoreEntryUpdateOneWithoutResultingProposalsNestedInput - resultingBibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutProposalsNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateWithoutTargetLoreEntryInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUncheckedUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateManyWithoutTargetLoreEntryInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - resultingLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type ProposalUpdateWithoutResultingLoreEntryInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutProposalsNestedInput - author?: Prisma.UserUpdateOneRequiredWithoutProposalsNestedInput - targetLoreEntry?: Prisma.LoreEntryUpdateOneWithoutTargetProposalsNestedInput - resultingBibleVersion?: Prisma.WorldBibleVersionUpdateOneWithoutProposalsNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateWithoutResultingLoreEntryInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutProposalNestedInput - aiReports?: Prisma.AIReportUncheckedUpdateManyWithoutProposalNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutProposalNestedInput -} - -export type ProposalUncheckedUpdateManyWithoutResultingLoreEntryInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - authorId?: Prisma.StringFieldUpdateOperationsInput | string - proposalType?: Prisma.EnumProposalTypeFieldUpdateOperationsInput | $Enums.ProposalType - status?: Prisma.EnumProposalStatusFieldUpdateOperationsInput | $Enums.ProposalStatus - title?: Prisma.StringFieldUpdateOperationsInput | string - summary?: Prisma.StringFieldUpdateOperationsInput | string - proposedContent?: Prisma.JsonNullValueInput | runtime.InputJsonValue - targetLoreEntryId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - resultingBibleVersionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - submittedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - votingStartedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - approvedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - rejectedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - -/** - * Count Type ProposalCountOutputType - */ - -export type ProposalCountOutputType = { - votes: number - aiReports: number - moderationReports: number -} - -export type ProposalCountOutputTypeSelect = { - votes?: boolean | ProposalCountOutputTypeCountVotesArgs - aiReports?: boolean | ProposalCountOutputTypeCountAiReportsArgs - moderationReports?: boolean | ProposalCountOutputTypeCountModerationReportsArgs -} - -/** - * ProposalCountOutputType without action - */ -export type ProposalCountOutputTypeDefaultArgs = { - /** - * Select specific fields to fetch from the ProposalCountOutputType - */ - select?: Prisma.ProposalCountOutputTypeSelect | null -} - -/** - * ProposalCountOutputType without action - */ -export type ProposalCountOutputTypeCountVotesArgs = { - where?: Prisma.AppVoteWhereInput -} - -/** - * ProposalCountOutputType without action - */ -export type ProposalCountOutputTypeCountAiReportsArgs = { - where?: Prisma.AIReportWhereInput -} - -/** - * ProposalCountOutputType without action - */ -export type ProposalCountOutputTypeCountModerationReportsArgs = { - where?: Prisma.ModerationReportWhereInput -} - - -export type ProposalSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - authorId?: boolean - proposalType?: boolean - status?: boolean - title?: boolean - summary?: boolean - proposedContent?: boolean - targetLoreEntryId?: boolean - resultingLoreEntryId?: boolean - resultingBibleVersionId?: boolean - submittedAt?: boolean - votingStartedAt?: boolean - approvedAt?: boolean - rejectedAt?: boolean - publishedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - targetLoreEntry?: boolean | Prisma.Proposal$targetLoreEntryArgs - resultingLoreEntry?: boolean | Prisma.Proposal$resultingLoreEntryArgs - resultingBibleVersion?: boolean | Prisma.Proposal$resultingBibleVersionArgs - votes?: boolean | Prisma.Proposal$votesArgs - aiReports?: boolean | Prisma.Proposal$aiReportsArgs - moderationReports?: boolean | Prisma.Proposal$moderationReportsArgs - _count?: boolean | Prisma.ProposalCountOutputTypeDefaultArgs -}, ExtArgs["result"]["proposal"]> - -export type ProposalSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - authorId?: boolean - proposalType?: boolean - status?: boolean - title?: boolean - summary?: boolean - proposedContent?: boolean - targetLoreEntryId?: boolean - resultingLoreEntryId?: boolean - resultingBibleVersionId?: boolean - submittedAt?: boolean - votingStartedAt?: boolean - approvedAt?: boolean - rejectedAt?: boolean - publishedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - targetLoreEntry?: boolean | Prisma.Proposal$targetLoreEntryArgs - resultingLoreEntry?: boolean | Prisma.Proposal$resultingLoreEntryArgs - resultingBibleVersion?: boolean | Prisma.Proposal$resultingBibleVersionArgs -}, ExtArgs["result"]["proposal"]> - -export type ProposalSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - authorId?: boolean - proposalType?: boolean - status?: boolean - title?: boolean - summary?: boolean - proposedContent?: boolean - targetLoreEntryId?: boolean - resultingLoreEntryId?: boolean - resultingBibleVersionId?: boolean - submittedAt?: boolean - votingStartedAt?: boolean - approvedAt?: boolean - rejectedAt?: boolean - publishedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - targetLoreEntry?: boolean | Prisma.Proposal$targetLoreEntryArgs - resultingLoreEntry?: boolean | Prisma.Proposal$resultingLoreEntryArgs - resultingBibleVersion?: boolean | Prisma.Proposal$resultingBibleVersionArgs -}, ExtArgs["result"]["proposal"]> - -export type ProposalSelectScalar = { - id?: boolean - worldId?: boolean - authorId?: boolean - proposalType?: boolean - status?: boolean - title?: boolean - summary?: boolean - proposedContent?: boolean - targetLoreEntryId?: boolean - resultingLoreEntryId?: boolean - resultingBibleVersionId?: boolean - submittedAt?: boolean - votingStartedAt?: boolean - approvedAt?: boolean - rejectedAt?: boolean - publishedAt?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type ProposalOmit = runtime.Types.Extensions.GetOmit<"id" | "worldId" | "authorId" | "proposalType" | "status" | "title" | "summary" | "proposedContent" | "targetLoreEntryId" | "resultingLoreEntryId" | "resultingBibleVersionId" | "submittedAt" | "votingStartedAt" | "approvedAt" | "rejectedAt" | "publishedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["proposal"]> -export type ProposalInclude = { - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - targetLoreEntry?: boolean | Prisma.Proposal$targetLoreEntryArgs - resultingLoreEntry?: boolean | Prisma.Proposal$resultingLoreEntryArgs - resultingBibleVersion?: boolean | Prisma.Proposal$resultingBibleVersionArgs - votes?: boolean | Prisma.Proposal$votesArgs - aiReports?: boolean | Prisma.Proposal$aiReportsArgs - moderationReports?: boolean | Prisma.Proposal$moderationReportsArgs - _count?: boolean | Prisma.ProposalCountOutputTypeDefaultArgs -} -export type ProposalIncludeCreateManyAndReturn = { - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - targetLoreEntry?: boolean | Prisma.Proposal$targetLoreEntryArgs - resultingLoreEntry?: boolean | Prisma.Proposal$resultingLoreEntryArgs - resultingBibleVersion?: boolean | Prisma.Proposal$resultingBibleVersionArgs -} -export type ProposalIncludeUpdateManyAndReturn = { - world?: boolean | Prisma.WorldDefaultArgs - author?: boolean | Prisma.UserDefaultArgs - targetLoreEntry?: boolean | Prisma.Proposal$targetLoreEntryArgs - resultingLoreEntry?: boolean | Prisma.Proposal$resultingLoreEntryArgs - resultingBibleVersion?: boolean | Prisma.Proposal$resultingBibleVersionArgs -} - -export type $ProposalPayload = { - name: "Proposal" - objects: { - world: Prisma.$WorldPayload - author: Prisma.$UserPayload - targetLoreEntry: Prisma.$LoreEntryPayload | null - resultingLoreEntry: Prisma.$LoreEntryPayload | null - resultingBibleVersion: Prisma.$WorldBibleVersionPayload | null - votes: Prisma.$AppVotePayload[] - aiReports: Prisma.$AIReportPayload[] - moderationReports: Prisma.$ModerationReportPayload[] - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - worldId: string - authorId: string - proposalType: $Enums.ProposalType - status: $Enums.ProposalStatus - title: string - summary: string - proposedContent: runtime.JsonValue - targetLoreEntryId: string | null - resultingLoreEntryId: string | null - resultingBibleVersionId: string | null - submittedAt: Date | null - votingStartedAt: Date | null - approvedAt: Date | null - rejectedAt: Date | null - publishedAt: Date | null - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["proposal"]> - composites: {} -} - -export type ProposalGetPayload = runtime.Types.Result.GetResult - -export type ProposalCountArgs = - Omit & { - select?: ProposalCountAggregateInputType | true - } - -export interface ProposalDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['Proposal'], meta: { name: 'Proposal' } } - /** - * Find zero or one Proposal that matches the filter. - * @param {ProposalFindUniqueArgs} args - Arguments to find a Proposal - * @example - * // Get one Proposal - * const proposal = await prisma.proposal.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__ProposalClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one Proposal that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {ProposalFindUniqueOrThrowArgs} args - Arguments to find a Proposal - * @example - * // Get one Proposal - * const proposal = await prisma.proposal.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__ProposalClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first Proposal 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 {ProposalFindFirstArgs} args - Arguments to find a Proposal - * @example - * // Get one Proposal - * const proposal = await prisma.proposal.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__ProposalClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first Proposal 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 {ProposalFindFirstOrThrowArgs} args - Arguments to find a Proposal - * @example - * // Get one Proposal - * const proposal = await prisma.proposal.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__ProposalClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more Proposals 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 {ProposalFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all Proposals - * const proposals = await prisma.proposal.findMany() - * - * // Get first 10 Proposals - * const proposals = await prisma.proposal.findMany({ take: 10 }) - * - * // Only select the `id` - * const proposalWithIdOnly = await prisma.proposal.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a Proposal. - * @param {ProposalCreateArgs} args - Arguments to create a Proposal. - * @example - * // Create one Proposal - * const Proposal = await prisma.proposal.create({ - * data: { - * // ... data to create a Proposal - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__ProposalClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many Proposals. - * @param {ProposalCreateManyArgs} args - Arguments to create many Proposals. - * @example - * // Create many Proposals - * const proposal = await prisma.proposal.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many Proposals and returns the data saved in the database. - * @param {ProposalCreateManyAndReturnArgs} args - Arguments to create many Proposals. - * @example - * // Create many Proposals - * const proposal = await prisma.proposal.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many Proposals and only return the `id` - * const proposalWithIdOnly = await prisma.proposal.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 Proposal. - * @param {ProposalDeleteArgs} args - Arguments to delete one Proposal. - * @example - * // Delete one Proposal - * const Proposal = await prisma.proposal.delete({ - * where: { - * // ... filter to delete one Proposal - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__ProposalClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one Proposal. - * @param {ProposalUpdateArgs} args - Arguments to update one Proposal. - * @example - * // Update one Proposal - * const proposal = await prisma.proposal.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__ProposalClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more Proposals. - * @param {ProposalDeleteManyArgs} args - Arguments to filter Proposals to delete. - * @example - * // Delete a few Proposals - * const { count } = await prisma.proposal.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more Proposals. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {ProposalUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many Proposals - * const proposal = await prisma.proposal.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more Proposals and returns the data updated in the database. - * @param {ProposalUpdateManyAndReturnArgs} args - Arguments to update many Proposals. - * @example - * // Update many Proposals - * const proposal = await prisma.proposal.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more Proposals and only return the `id` - * const proposalWithIdOnly = await prisma.proposal.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 Proposal. - * @param {ProposalUpsertArgs} args - Arguments to update or create a Proposal. - * @example - * // Update or create a Proposal - * const proposal = await prisma.proposal.upsert({ - * create: { - * // ... data to create a Proposal - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the Proposal we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__ProposalClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of Proposals. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {ProposalCountArgs} args - Arguments to filter Proposals to count. - * @example - * // Count the number of Proposals - * const count = await prisma.proposal.count({ - * where: { - * // ... the filter for the Proposals 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 Proposal. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {ProposalAggregateArgs} 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 Proposal. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {ProposalGroupByArgs} 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 ProposalGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: ProposalGroupByArgs['orderBy'] } - : { orderBy?: ProposalGroupByArgs['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 ? GetProposalGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the Proposal model - */ -readonly fields: ProposalFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for Proposal. - * 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__ProposalClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - world = {}>(args?: Prisma.Subset>): Prisma.Prisma__WorldClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - author = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - targetLoreEntry = {}>(args?: Prisma.Subset>): Prisma.Prisma__LoreEntryClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - resultingLoreEntry = {}>(args?: Prisma.Subset>): Prisma.Prisma__LoreEntryClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - resultingBibleVersion = {}>(args?: Prisma.Subset>): Prisma.Prisma__WorldBibleVersionClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - votes = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - aiReports = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - moderationReports = {}>(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 Proposal model - */ -export interface ProposalFieldRefs { - readonly id: Prisma.FieldRef<"Proposal", 'String'> - readonly worldId: Prisma.FieldRef<"Proposal", 'String'> - readonly authorId: Prisma.FieldRef<"Proposal", 'String'> - readonly proposalType: Prisma.FieldRef<"Proposal", 'ProposalType'> - readonly status: Prisma.FieldRef<"Proposal", 'ProposalStatus'> - readonly title: Prisma.FieldRef<"Proposal", 'String'> - readonly summary: Prisma.FieldRef<"Proposal", 'String'> - readonly proposedContent: Prisma.FieldRef<"Proposal", 'Json'> - readonly targetLoreEntryId: Prisma.FieldRef<"Proposal", 'String'> - readonly resultingLoreEntryId: Prisma.FieldRef<"Proposal", 'String'> - readonly resultingBibleVersionId: Prisma.FieldRef<"Proposal", 'String'> - readonly submittedAt: Prisma.FieldRef<"Proposal", 'DateTime'> - readonly votingStartedAt: Prisma.FieldRef<"Proposal", 'DateTime'> - readonly approvedAt: Prisma.FieldRef<"Proposal", 'DateTime'> - readonly rejectedAt: Prisma.FieldRef<"Proposal", 'DateTime'> - readonly publishedAt: Prisma.FieldRef<"Proposal", 'DateTime'> - readonly createdAt: Prisma.FieldRef<"Proposal", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"Proposal", 'DateTime'> -} - - -// Custom InputTypes -/** - * Proposal findUnique - */ -export type ProposalFindUniqueArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - /** - * Filter, which Proposal to fetch. - */ - where: Prisma.ProposalWhereUniqueInput -} - -/** - * Proposal findUniqueOrThrow - */ -export type ProposalFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - /** - * Filter, which Proposal to fetch. - */ - where: Prisma.ProposalWhereUniqueInput -} - -/** - * Proposal findFirst - */ -export type ProposalFindFirstArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - /** - * Filter, which Proposal to fetch. - */ - where?: Prisma.ProposalWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of Proposals to fetch. - */ - orderBy?: Prisma.ProposalOrderByWithRelationInput | Prisma.ProposalOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for Proposals. - */ - cursor?: Prisma.ProposalWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` Proposals 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` Proposals. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of Proposals. - */ - distinct?: Prisma.ProposalScalarFieldEnum | Prisma.ProposalScalarFieldEnum[] -} - -/** - * Proposal findFirstOrThrow - */ -export type ProposalFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - /** - * Filter, which Proposal to fetch. - */ - where?: Prisma.ProposalWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of Proposals to fetch. - */ - orderBy?: Prisma.ProposalOrderByWithRelationInput | Prisma.ProposalOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for Proposals. - */ - cursor?: Prisma.ProposalWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` Proposals 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` Proposals. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of Proposals. - */ - distinct?: Prisma.ProposalScalarFieldEnum | Prisma.ProposalScalarFieldEnum[] -} - -/** - * Proposal findMany - */ -export type ProposalFindManyArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - /** - * Filter, which Proposals to fetch. - */ - where?: Prisma.ProposalWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of Proposals to fetch. - */ - orderBy?: Prisma.ProposalOrderByWithRelationInput | Prisma.ProposalOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing Proposals. - */ - cursor?: Prisma.ProposalWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` Proposals 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` Proposals. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of Proposals. - */ - distinct?: Prisma.ProposalScalarFieldEnum | Prisma.ProposalScalarFieldEnum[] -} - -/** - * Proposal create - */ -export type ProposalCreateArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - /** - * The data needed to create a Proposal. - */ - data: Prisma.XOR -} - -/** - * Proposal createMany - */ -export type ProposalCreateManyArgs = { - /** - * The data used to create many Proposals. - */ - data: Prisma.ProposalCreateManyInput | Prisma.ProposalCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * Proposal createManyAndReturn - */ -export type ProposalCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelectCreateManyAndReturn | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * The data used to create many Proposals. - */ - data: Prisma.ProposalCreateManyInput | Prisma.ProposalCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalIncludeCreateManyAndReturn | null -} - -/** - * Proposal update - */ -export type ProposalUpdateArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - /** - * The data needed to update a Proposal. - */ - data: Prisma.XOR - /** - * Choose, which Proposal to update. - */ - where: Prisma.ProposalWhereUniqueInput -} - -/** - * Proposal updateMany - */ -export type ProposalUpdateManyArgs = { - /** - * The data used to update Proposals. - */ - data: Prisma.XOR - /** - * Filter which Proposals to update - */ - where?: Prisma.ProposalWhereInput - /** - * Limit how many Proposals to update. - */ - limit?: number -} - -/** - * Proposal updateManyAndReturn - */ -export type ProposalUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * The data used to update Proposals. - */ - data: Prisma.XOR - /** - * Filter which Proposals to update - */ - where?: Prisma.ProposalWhereInput - /** - * Limit how many Proposals to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalIncludeUpdateManyAndReturn | null -} - -/** - * Proposal upsert - */ -export type ProposalUpsertArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - /** - * The filter to search for the Proposal to update in case it exists. - */ - where: Prisma.ProposalWhereUniqueInput - /** - * In case the Proposal found by the `where` argument doesn't exist, create a new Proposal with this data. - */ - create: Prisma.XOR - /** - * In case the Proposal was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * Proposal delete - */ -export type ProposalDeleteArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - /** - * Filter which Proposal to delete. - */ - where: Prisma.ProposalWhereUniqueInput -} - -/** - * Proposal deleteMany - */ -export type ProposalDeleteManyArgs = { - /** - * Filter which Proposals to delete - */ - where?: Prisma.ProposalWhereInput - /** - * Limit how many Proposals to delete. - */ - limit?: number -} - -/** - * Proposal.targetLoreEntry - */ -export type Proposal$targetLoreEntryArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - where?: Prisma.LoreEntryWhereInput -} - -/** - * Proposal.resultingLoreEntry - */ -export type Proposal$resultingLoreEntryArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - where?: Prisma.LoreEntryWhereInput -} - -/** - * Proposal.resultingBibleVersion - */ -export type Proposal$resultingBibleVersionArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - where?: Prisma.WorldBibleVersionWhereInput -} - -/** - * Proposal.votes - */ -export type Proposal$votesArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - where?: Prisma.AppVoteWhereInput - orderBy?: Prisma.AppVoteOrderByWithRelationInput | Prisma.AppVoteOrderByWithRelationInput[] - cursor?: Prisma.AppVoteWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.AppVoteScalarFieldEnum | Prisma.AppVoteScalarFieldEnum[] -} - -/** - * Proposal.aiReports - */ -export type Proposal$aiReportsArgs = { - /** - * Select specific fields to fetch from the AIReport - */ - select?: Prisma.AIReportSelect | null - /** - * Omit specific fields from the AIReport - */ - omit?: Prisma.AIReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AIReportInclude | null - where?: Prisma.AIReportWhereInput - orderBy?: Prisma.AIReportOrderByWithRelationInput | Prisma.AIReportOrderByWithRelationInput[] - cursor?: Prisma.AIReportWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.AIReportScalarFieldEnum | Prisma.AIReportScalarFieldEnum[] -} - -/** - * Proposal.moderationReports - */ -export type Proposal$moderationReportsArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - where?: Prisma.ModerationReportWhereInput - orderBy?: Prisma.ModerationReportOrderByWithRelationInput | Prisma.ModerationReportOrderByWithRelationInput[] - cursor?: Prisma.ModerationReportWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.ModerationReportScalarFieldEnum | Prisma.ModerationReportScalarFieldEnum[] -} - -/** - * Proposal without action - */ -export type ProposalDefaultArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null -} diff --git a/apps/api/src/generated/prisma/models/RewardRecord.ts b/apps/api/src/generated/prisma/models/RewardRecord.ts deleted file mode 100644 index 14467c5..0000000 --- a/apps/api/src/generated/prisma/models/RewardRecord.ts +++ /dev/null @@ -1,1880 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `RewardRecord` 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 RewardRecord - * - */ -export type RewardRecordModel = runtime.Types.Result.DefaultSelection - -export type AggregateRewardRecord = { - _count: RewardRecordCountAggregateOutputType | null - _avg: RewardRecordAvgAggregateOutputType | null - _sum: RewardRecordSumAggregateOutputType | null - _min: RewardRecordMinAggregateOutputType | null - _max: RewardRecordMaxAggregateOutputType | null -} - -export type RewardRecordAvgAggregateOutputType = { - amount: runtime.Decimal | null - operationIndex: number | null - blockNumber: number | null -} - -export type RewardRecordSumAggregateOutputType = { - amount: runtime.Decimal | null - operationIndex: number | null - blockNumber: bigint | null -} - -export type RewardRecordMinAggregateOutputType = { - id: string | null - userId: string | null - hiveReferenceId: string | null - rewardType: $Enums.RewardType | null - assetSymbol: string | null - amount: runtime.Decimal | null - transactionId: string | null - operationIndex: number | null - blockNumber: bigint | null - payoutAt: Date | null - idempotencyKey: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type RewardRecordMaxAggregateOutputType = { - id: string | null - userId: string | null - hiveReferenceId: string | null - rewardType: $Enums.RewardType | null - assetSymbol: string | null - amount: runtime.Decimal | null - transactionId: string | null - operationIndex: number | null - blockNumber: bigint | null - payoutAt: Date | null - idempotencyKey: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type RewardRecordCountAggregateOutputType = { - id: number - userId: number - hiveReferenceId: number - rewardType: number - assetSymbol: number - amount: number - transactionId: number - operationIndex: number - blockNumber: number - payoutAt: number - idempotencyKey: number - createdAt: number - updatedAt: number - _all: number -} - - -export type RewardRecordAvgAggregateInputType = { - amount?: true - operationIndex?: true - blockNumber?: true -} - -export type RewardRecordSumAggregateInputType = { - amount?: true - operationIndex?: true - blockNumber?: true -} - -export type RewardRecordMinAggregateInputType = { - id?: true - userId?: true - hiveReferenceId?: true - rewardType?: true - assetSymbol?: true - amount?: true - transactionId?: true - operationIndex?: true - blockNumber?: true - payoutAt?: true - idempotencyKey?: true - createdAt?: true - updatedAt?: true -} - -export type RewardRecordMaxAggregateInputType = { - id?: true - userId?: true - hiveReferenceId?: true - rewardType?: true - assetSymbol?: true - amount?: true - transactionId?: true - operationIndex?: true - blockNumber?: true - payoutAt?: true - idempotencyKey?: true - createdAt?: true - updatedAt?: true -} - -export type RewardRecordCountAggregateInputType = { - id?: true - userId?: true - hiveReferenceId?: true - rewardType?: true - assetSymbol?: true - amount?: true - transactionId?: true - operationIndex?: true - blockNumber?: true - payoutAt?: true - idempotencyKey?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type RewardRecordAggregateArgs = { - /** - * Filter which RewardRecord to aggregate. - */ - where?: Prisma.RewardRecordWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of RewardRecords to fetch. - */ - orderBy?: Prisma.RewardRecordOrderByWithRelationInput | Prisma.RewardRecordOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.RewardRecordWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` RewardRecords 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` RewardRecords. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned RewardRecords - **/ - _count?: true | RewardRecordCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to average - **/ - _avg?: RewardRecordAvgAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to sum - **/ - _sum?: RewardRecordSumAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: RewardRecordMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: RewardRecordMaxAggregateInputType -} - -export type GetRewardRecordAggregateType = { - [P in keyof T & keyof AggregateRewardRecord]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type RewardRecordGroupByArgs = { - where?: Prisma.RewardRecordWhereInput - orderBy?: Prisma.RewardRecordOrderByWithAggregationInput | Prisma.RewardRecordOrderByWithAggregationInput[] - by: Prisma.RewardRecordScalarFieldEnum[] | Prisma.RewardRecordScalarFieldEnum - having?: Prisma.RewardRecordScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: RewardRecordCountAggregateInputType | true - _avg?: RewardRecordAvgAggregateInputType - _sum?: RewardRecordSumAggregateInputType - _min?: RewardRecordMinAggregateInputType - _max?: RewardRecordMaxAggregateInputType -} - -export type RewardRecordGroupByOutputType = { - id: string - userId: string - hiveReferenceId: string | null - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal - transactionId: string - operationIndex: number - blockNumber: bigint - payoutAt: Date - idempotencyKey: string - createdAt: Date - updatedAt: Date - _count: RewardRecordCountAggregateOutputType | null - _avg: RewardRecordAvgAggregateOutputType | null - _sum: RewardRecordSumAggregateOutputType | null - _min: RewardRecordMinAggregateOutputType | null - _max: RewardRecordMaxAggregateOutputType | null -} - -export type GetRewardRecordGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof RewardRecordGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type RewardRecordWhereInput = { - AND?: Prisma.RewardRecordWhereInput | Prisma.RewardRecordWhereInput[] - OR?: Prisma.RewardRecordWhereInput[] - NOT?: Prisma.RewardRecordWhereInput | Prisma.RewardRecordWhereInput[] - id?: Prisma.StringFilter<"RewardRecord"> | string - userId?: Prisma.StringFilter<"RewardRecord"> | string - hiveReferenceId?: Prisma.StringNullableFilter<"RewardRecord"> | string | null - rewardType?: Prisma.EnumRewardTypeFilter<"RewardRecord"> | $Enums.RewardType - assetSymbol?: Prisma.StringFilter<"RewardRecord"> | string - amount?: Prisma.DecimalFilter<"RewardRecord"> | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFilter<"RewardRecord"> | string - operationIndex?: Prisma.IntFilter<"RewardRecord"> | number - blockNumber?: Prisma.BigIntFilter<"RewardRecord"> | bigint | number - payoutAt?: Prisma.DateTimeFilter<"RewardRecord"> | Date | string - idempotencyKey?: Prisma.StringFilter<"RewardRecord"> | string - createdAt?: Prisma.DateTimeFilter<"RewardRecord"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"RewardRecord"> | Date | string - user?: Prisma.XOR - hiveReference?: Prisma.XOR | null -} - -export type RewardRecordOrderByWithRelationInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrderInput | Prisma.SortOrder - rewardType?: Prisma.SortOrder - assetSymbol?: Prisma.SortOrder - amount?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - payoutAt?: Prisma.SortOrder - idempotencyKey?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - user?: Prisma.UserOrderByWithRelationInput - hiveReference?: Prisma.HiveReferenceOrderByWithRelationInput -} - -export type RewardRecordWhereUniqueInput = Prisma.AtLeast<{ - id?: string - idempotencyKey?: string - AND?: Prisma.RewardRecordWhereInput | Prisma.RewardRecordWhereInput[] - OR?: Prisma.RewardRecordWhereInput[] - NOT?: Prisma.RewardRecordWhereInput | Prisma.RewardRecordWhereInput[] - userId?: Prisma.StringFilter<"RewardRecord"> | string - hiveReferenceId?: Prisma.StringNullableFilter<"RewardRecord"> | string | null - rewardType?: Prisma.EnumRewardTypeFilter<"RewardRecord"> | $Enums.RewardType - assetSymbol?: Prisma.StringFilter<"RewardRecord"> | string - amount?: Prisma.DecimalFilter<"RewardRecord"> | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFilter<"RewardRecord"> | string - operationIndex?: Prisma.IntFilter<"RewardRecord"> | number - blockNumber?: Prisma.BigIntFilter<"RewardRecord"> | bigint | number - payoutAt?: Prisma.DateTimeFilter<"RewardRecord"> | Date | string - createdAt?: Prisma.DateTimeFilter<"RewardRecord"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"RewardRecord"> | Date | string - user?: Prisma.XOR - hiveReference?: Prisma.XOR | null -}, "id" | "idempotencyKey"> - -export type RewardRecordOrderByWithAggregationInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrderInput | Prisma.SortOrder - rewardType?: Prisma.SortOrder - assetSymbol?: Prisma.SortOrder - amount?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - payoutAt?: Prisma.SortOrder - idempotencyKey?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.RewardRecordCountOrderByAggregateInput - _avg?: Prisma.RewardRecordAvgOrderByAggregateInput - _max?: Prisma.RewardRecordMaxOrderByAggregateInput - _min?: Prisma.RewardRecordMinOrderByAggregateInput - _sum?: Prisma.RewardRecordSumOrderByAggregateInput -} - -export type RewardRecordScalarWhereWithAggregatesInput = { - AND?: Prisma.RewardRecordScalarWhereWithAggregatesInput | Prisma.RewardRecordScalarWhereWithAggregatesInput[] - OR?: Prisma.RewardRecordScalarWhereWithAggregatesInput[] - NOT?: Prisma.RewardRecordScalarWhereWithAggregatesInput | Prisma.RewardRecordScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"RewardRecord"> | string - userId?: Prisma.StringWithAggregatesFilter<"RewardRecord"> | string - hiveReferenceId?: Prisma.StringNullableWithAggregatesFilter<"RewardRecord"> | string | null - rewardType?: Prisma.EnumRewardTypeWithAggregatesFilter<"RewardRecord"> | $Enums.RewardType - assetSymbol?: Prisma.StringWithAggregatesFilter<"RewardRecord"> | string - amount?: Prisma.DecimalWithAggregatesFilter<"RewardRecord"> | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringWithAggregatesFilter<"RewardRecord"> | string - operationIndex?: Prisma.IntWithAggregatesFilter<"RewardRecord"> | number - blockNumber?: Prisma.BigIntWithAggregatesFilter<"RewardRecord"> | bigint | number - payoutAt?: Prisma.DateTimeWithAggregatesFilter<"RewardRecord"> | Date | string - idempotencyKey?: Prisma.StringWithAggregatesFilter<"RewardRecord"> | string - createdAt?: Prisma.DateTimeWithAggregatesFilter<"RewardRecord"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"RewardRecord"> | Date | string -} - -export type RewardRecordCreateInput = { - id?: string - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId: string - operationIndex: number - blockNumber: bigint | number - payoutAt: Date | string - idempotencyKey: string - createdAt?: Date | string - updatedAt?: Date | string - user: Prisma.UserCreateNestedOneWithoutRewardRecordsInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutRewardRecordsInput -} - -export type RewardRecordUncheckedCreateInput = { - id?: string - userId: string - hiveReferenceId?: string | null - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId: string - operationIndex: number - blockNumber: bigint | number - payoutAt: Date | string - idempotencyKey: string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type RewardRecordUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - rewardType?: Prisma.EnumRewardTypeFieldUpdateOperationsInput | $Enums.RewardType - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - amount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - payoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - user?: Prisma.UserUpdateOneRequiredWithoutRewardRecordsNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutRewardRecordsNestedInput -} - -export type RewardRecordUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - userId?: Prisma.StringFieldUpdateOperationsInput | string - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - rewardType?: Prisma.EnumRewardTypeFieldUpdateOperationsInput | $Enums.RewardType - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - amount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - payoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type RewardRecordCreateManyInput = { - id?: string - userId: string - hiveReferenceId?: string | null - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId: string - operationIndex: number - blockNumber: bigint | number - payoutAt: Date | string - idempotencyKey: string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type RewardRecordUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - rewardType?: Prisma.EnumRewardTypeFieldUpdateOperationsInput | $Enums.RewardType - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - amount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - payoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type RewardRecordUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - userId?: Prisma.StringFieldUpdateOperationsInput | string - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - rewardType?: Prisma.EnumRewardTypeFieldUpdateOperationsInput | $Enums.RewardType - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - amount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - payoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type RewardRecordListRelationFilter = { - every?: Prisma.RewardRecordWhereInput - some?: Prisma.RewardRecordWhereInput - none?: Prisma.RewardRecordWhereInput -} - -export type RewardRecordOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type RewardRecordCountOrderByAggregateInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrder - rewardType?: Prisma.SortOrder - assetSymbol?: Prisma.SortOrder - amount?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - payoutAt?: Prisma.SortOrder - idempotencyKey?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type RewardRecordAvgOrderByAggregateInput = { - amount?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder -} - -export type RewardRecordMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrder - rewardType?: Prisma.SortOrder - assetSymbol?: Prisma.SortOrder - amount?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - payoutAt?: Prisma.SortOrder - idempotencyKey?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type RewardRecordMinOrderByAggregateInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrder - rewardType?: Prisma.SortOrder - assetSymbol?: Prisma.SortOrder - amount?: Prisma.SortOrder - transactionId?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder - payoutAt?: Prisma.SortOrder - idempotencyKey?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type RewardRecordSumOrderByAggregateInput = { - amount?: Prisma.SortOrder - operationIndex?: Prisma.SortOrder - blockNumber?: Prisma.SortOrder -} - -export type RewardRecordCreateNestedManyWithoutUserInput = { - create?: Prisma.XOR | Prisma.RewardRecordCreateWithoutUserInput[] | Prisma.RewardRecordUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.RewardRecordCreateOrConnectWithoutUserInput | Prisma.RewardRecordCreateOrConnectWithoutUserInput[] - createMany?: Prisma.RewardRecordCreateManyUserInputEnvelope - connect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] -} - -export type RewardRecordUncheckedCreateNestedManyWithoutUserInput = { - create?: Prisma.XOR | Prisma.RewardRecordCreateWithoutUserInput[] | Prisma.RewardRecordUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.RewardRecordCreateOrConnectWithoutUserInput | Prisma.RewardRecordCreateOrConnectWithoutUserInput[] - createMany?: Prisma.RewardRecordCreateManyUserInputEnvelope - connect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] -} - -export type RewardRecordUpdateManyWithoutUserNestedInput = { - create?: Prisma.XOR | Prisma.RewardRecordCreateWithoutUserInput[] | Prisma.RewardRecordUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.RewardRecordCreateOrConnectWithoutUserInput | Prisma.RewardRecordCreateOrConnectWithoutUserInput[] - upsert?: Prisma.RewardRecordUpsertWithWhereUniqueWithoutUserInput | Prisma.RewardRecordUpsertWithWhereUniqueWithoutUserInput[] - createMany?: Prisma.RewardRecordCreateManyUserInputEnvelope - set?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - disconnect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - delete?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - connect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - update?: Prisma.RewardRecordUpdateWithWhereUniqueWithoutUserInput | Prisma.RewardRecordUpdateWithWhereUniqueWithoutUserInput[] - updateMany?: Prisma.RewardRecordUpdateManyWithWhereWithoutUserInput | Prisma.RewardRecordUpdateManyWithWhereWithoutUserInput[] - deleteMany?: Prisma.RewardRecordScalarWhereInput | Prisma.RewardRecordScalarWhereInput[] -} - -export type RewardRecordUncheckedUpdateManyWithoutUserNestedInput = { - create?: Prisma.XOR | Prisma.RewardRecordCreateWithoutUserInput[] | Prisma.RewardRecordUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.RewardRecordCreateOrConnectWithoutUserInput | Prisma.RewardRecordCreateOrConnectWithoutUserInput[] - upsert?: Prisma.RewardRecordUpsertWithWhereUniqueWithoutUserInput | Prisma.RewardRecordUpsertWithWhereUniqueWithoutUserInput[] - createMany?: Prisma.RewardRecordCreateManyUserInputEnvelope - set?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - disconnect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - delete?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - connect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - update?: Prisma.RewardRecordUpdateWithWhereUniqueWithoutUserInput | Prisma.RewardRecordUpdateWithWhereUniqueWithoutUserInput[] - updateMany?: Prisma.RewardRecordUpdateManyWithWhereWithoutUserInput | Prisma.RewardRecordUpdateManyWithWhereWithoutUserInput[] - deleteMany?: Prisma.RewardRecordScalarWhereInput | Prisma.RewardRecordScalarWhereInput[] -} - -export type RewardRecordCreateNestedManyWithoutHiveReferenceInput = { - create?: Prisma.XOR | Prisma.RewardRecordCreateWithoutHiveReferenceInput[] | Prisma.RewardRecordUncheckedCreateWithoutHiveReferenceInput[] - connectOrCreate?: Prisma.RewardRecordCreateOrConnectWithoutHiveReferenceInput | Prisma.RewardRecordCreateOrConnectWithoutHiveReferenceInput[] - createMany?: Prisma.RewardRecordCreateManyHiveReferenceInputEnvelope - connect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] -} - -export type RewardRecordUncheckedCreateNestedManyWithoutHiveReferenceInput = { - create?: Prisma.XOR | Prisma.RewardRecordCreateWithoutHiveReferenceInput[] | Prisma.RewardRecordUncheckedCreateWithoutHiveReferenceInput[] - connectOrCreate?: Prisma.RewardRecordCreateOrConnectWithoutHiveReferenceInput | Prisma.RewardRecordCreateOrConnectWithoutHiveReferenceInput[] - createMany?: Prisma.RewardRecordCreateManyHiveReferenceInputEnvelope - connect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] -} - -export type RewardRecordUpdateManyWithoutHiveReferenceNestedInput = { - create?: Prisma.XOR | Prisma.RewardRecordCreateWithoutHiveReferenceInput[] | Prisma.RewardRecordUncheckedCreateWithoutHiveReferenceInput[] - connectOrCreate?: Prisma.RewardRecordCreateOrConnectWithoutHiveReferenceInput | Prisma.RewardRecordCreateOrConnectWithoutHiveReferenceInput[] - upsert?: Prisma.RewardRecordUpsertWithWhereUniqueWithoutHiveReferenceInput | Prisma.RewardRecordUpsertWithWhereUniqueWithoutHiveReferenceInput[] - createMany?: Prisma.RewardRecordCreateManyHiveReferenceInputEnvelope - set?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - disconnect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - delete?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - connect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - update?: Prisma.RewardRecordUpdateWithWhereUniqueWithoutHiveReferenceInput | Prisma.RewardRecordUpdateWithWhereUniqueWithoutHiveReferenceInput[] - updateMany?: Prisma.RewardRecordUpdateManyWithWhereWithoutHiveReferenceInput | Prisma.RewardRecordUpdateManyWithWhereWithoutHiveReferenceInput[] - deleteMany?: Prisma.RewardRecordScalarWhereInput | Prisma.RewardRecordScalarWhereInput[] -} - -export type RewardRecordUncheckedUpdateManyWithoutHiveReferenceNestedInput = { - create?: Prisma.XOR | Prisma.RewardRecordCreateWithoutHiveReferenceInput[] | Prisma.RewardRecordUncheckedCreateWithoutHiveReferenceInput[] - connectOrCreate?: Prisma.RewardRecordCreateOrConnectWithoutHiveReferenceInput | Prisma.RewardRecordCreateOrConnectWithoutHiveReferenceInput[] - upsert?: Prisma.RewardRecordUpsertWithWhereUniqueWithoutHiveReferenceInput | Prisma.RewardRecordUpsertWithWhereUniqueWithoutHiveReferenceInput[] - createMany?: Prisma.RewardRecordCreateManyHiveReferenceInputEnvelope - set?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - disconnect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - delete?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - connect?: Prisma.RewardRecordWhereUniqueInput | Prisma.RewardRecordWhereUniqueInput[] - update?: Prisma.RewardRecordUpdateWithWhereUniqueWithoutHiveReferenceInput | Prisma.RewardRecordUpdateWithWhereUniqueWithoutHiveReferenceInput[] - updateMany?: Prisma.RewardRecordUpdateManyWithWhereWithoutHiveReferenceInput | Prisma.RewardRecordUpdateManyWithWhereWithoutHiveReferenceInput[] - deleteMany?: Prisma.RewardRecordScalarWhereInput | Prisma.RewardRecordScalarWhereInput[] -} - -export type EnumRewardTypeFieldUpdateOperationsInput = { - set?: $Enums.RewardType -} - -export type DecimalFieldUpdateOperationsInput = { - set?: runtime.Decimal | runtime.DecimalJsLike | number | string - increment?: runtime.Decimal | runtime.DecimalJsLike | number | string - decrement?: runtime.Decimal | runtime.DecimalJsLike | number | string - multiply?: runtime.Decimal | runtime.DecimalJsLike | number | string - divide?: runtime.Decimal | runtime.DecimalJsLike | number | string -} - -export type RewardRecordCreateWithoutUserInput = { - id?: string - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId: string - operationIndex: number - blockNumber: bigint | number - payoutAt: Date | string - idempotencyKey: string - createdAt?: Date | string - updatedAt?: Date | string - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutRewardRecordsInput -} - -export type RewardRecordUncheckedCreateWithoutUserInput = { - id?: string - hiveReferenceId?: string | null - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId: string - operationIndex: number - blockNumber: bigint | number - payoutAt: Date | string - idempotencyKey: string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type RewardRecordCreateOrConnectWithoutUserInput = { - where: Prisma.RewardRecordWhereUniqueInput - create: Prisma.XOR -} - -export type RewardRecordCreateManyUserInputEnvelope = { - data: Prisma.RewardRecordCreateManyUserInput | Prisma.RewardRecordCreateManyUserInput[] - skipDuplicates?: boolean -} - -export type RewardRecordUpsertWithWhereUniqueWithoutUserInput = { - where: Prisma.RewardRecordWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type RewardRecordUpdateWithWhereUniqueWithoutUserInput = { - where: Prisma.RewardRecordWhereUniqueInput - data: Prisma.XOR -} - -export type RewardRecordUpdateManyWithWhereWithoutUserInput = { - where: Prisma.RewardRecordScalarWhereInput - data: Prisma.XOR -} - -export type RewardRecordScalarWhereInput = { - AND?: Prisma.RewardRecordScalarWhereInput | Prisma.RewardRecordScalarWhereInput[] - OR?: Prisma.RewardRecordScalarWhereInput[] - NOT?: Prisma.RewardRecordScalarWhereInput | Prisma.RewardRecordScalarWhereInput[] - id?: Prisma.StringFilter<"RewardRecord"> | string - userId?: Prisma.StringFilter<"RewardRecord"> | string - hiveReferenceId?: Prisma.StringNullableFilter<"RewardRecord"> | string | null - rewardType?: Prisma.EnumRewardTypeFilter<"RewardRecord"> | $Enums.RewardType - assetSymbol?: Prisma.StringFilter<"RewardRecord"> | string - amount?: Prisma.DecimalFilter<"RewardRecord"> | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFilter<"RewardRecord"> | string - operationIndex?: Prisma.IntFilter<"RewardRecord"> | number - blockNumber?: Prisma.BigIntFilter<"RewardRecord"> | bigint | number - payoutAt?: Prisma.DateTimeFilter<"RewardRecord"> | Date | string - idempotencyKey?: Prisma.StringFilter<"RewardRecord"> | string - createdAt?: Prisma.DateTimeFilter<"RewardRecord"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"RewardRecord"> | Date | string -} - -export type RewardRecordCreateWithoutHiveReferenceInput = { - id?: string - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId: string - operationIndex: number - blockNumber: bigint | number - payoutAt: Date | string - idempotencyKey: string - createdAt?: Date | string - updatedAt?: Date | string - user: Prisma.UserCreateNestedOneWithoutRewardRecordsInput -} - -export type RewardRecordUncheckedCreateWithoutHiveReferenceInput = { - id?: string - userId: string - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId: string - operationIndex: number - blockNumber: bigint | number - payoutAt: Date | string - idempotencyKey: string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type RewardRecordCreateOrConnectWithoutHiveReferenceInput = { - where: Prisma.RewardRecordWhereUniqueInput - create: Prisma.XOR -} - -export type RewardRecordCreateManyHiveReferenceInputEnvelope = { - data: Prisma.RewardRecordCreateManyHiveReferenceInput | Prisma.RewardRecordCreateManyHiveReferenceInput[] - skipDuplicates?: boolean -} - -export type RewardRecordUpsertWithWhereUniqueWithoutHiveReferenceInput = { - where: Prisma.RewardRecordWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type RewardRecordUpdateWithWhereUniqueWithoutHiveReferenceInput = { - where: Prisma.RewardRecordWhereUniqueInput - data: Prisma.XOR -} - -export type RewardRecordUpdateManyWithWhereWithoutHiveReferenceInput = { - where: Prisma.RewardRecordScalarWhereInput - data: Prisma.XOR -} - -export type RewardRecordCreateManyUserInput = { - id?: string - hiveReferenceId?: string | null - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId: string - operationIndex: number - blockNumber: bigint | number - payoutAt: Date | string - idempotencyKey: string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type RewardRecordUpdateWithoutUserInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - rewardType?: Prisma.EnumRewardTypeFieldUpdateOperationsInput | $Enums.RewardType - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - amount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - payoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutRewardRecordsNestedInput -} - -export type RewardRecordUncheckedUpdateWithoutUserInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - rewardType?: Prisma.EnumRewardTypeFieldUpdateOperationsInput | $Enums.RewardType - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - amount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - payoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type RewardRecordUncheckedUpdateManyWithoutUserInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - rewardType?: Prisma.EnumRewardTypeFieldUpdateOperationsInput | $Enums.RewardType - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - amount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - payoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type RewardRecordCreateManyHiveReferenceInput = { - id?: string - userId: string - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId: string - operationIndex: number - blockNumber: bigint | number - payoutAt: Date | string - idempotencyKey: string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type RewardRecordUpdateWithoutHiveReferenceInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - rewardType?: Prisma.EnumRewardTypeFieldUpdateOperationsInput | $Enums.RewardType - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - amount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - payoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - user?: Prisma.UserUpdateOneRequiredWithoutRewardRecordsNestedInput -} - -export type RewardRecordUncheckedUpdateWithoutHiveReferenceInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - userId?: Prisma.StringFieldUpdateOperationsInput | string - rewardType?: Prisma.EnumRewardTypeFieldUpdateOperationsInput | $Enums.RewardType - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - amount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - payoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type RewardRecordUncheckedUpdateManyWithoutHiveReferenceInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - userId?: Prisma.StringFieldUpdateOperationsInput | string - rewardType?: Prisma.EnumRewardTypeFieldUpdateOperationsInput | $Enums.RewardType - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - amount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - transactionId?: Prisma.StringFieldUpdateOperationsInput | string - operationIndex?: Prisma.IntFieldUpdateOperationsInput | number - blockNumber?: Prisma.BigIntFieldUpdateOperationsInput | bigint | number - payoutAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - idempotencyKey?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - - -export type RewardRecordSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - userId?: boolean - hiveReferenceId?: boolean - rewardType?: boolean - assetSymbol?: boolean - amount?: boolean - transactionId?: boolean - operationIndex?: boolean - blockNumber?: boolean - payoutAt?: boolean - idempotencyKey?: boolean - createdAt?: boolean - updatedAt?: boolean - user?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.RewardRecord$hiveReferenceArgs -}, ExtArgs["result"]["rewardRecord"]> - -export type RewardRecordSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - userId?: boolean - hiveReferenceId?: boolean - rewardType?: boolean - assetSymbol?: boolean - amount?: boolean - transactionId?: boolean - operationIndex?: boolean - blockNumber?: boolean - payoutAt?: boolean - idempotencyKey?: boolean - createdAt?: boolean - updatedAt?: boolean - user?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.RewardRecord$hiveReferenceArgs -}, ExtArgs["result"]["rewardRecord"]> - -export type RewardRecordSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - userId?: boolean - hiveReferenceId?: boolean - rewardType?: boolean - assetSymbol?: boolean - amount?: boolean - transactionId?: boolean - operationIndex?: boolean - blockNumber?: boolean - payoutAt?: boolean - idempotencyKey?: boolean - createdAt?: boolean - updatedAt?: boolean - user?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.RewardRecord$hiveReferenceArgs -}, ExtArgs["result"]["rewardRecord"]> - -export type RewardRecordSelectScalar = { - id?: boolean - userId?: boolean - hiveReferenceId?: boolean - rewardType?: boolean - assetSymbol?: boolean - amount?: boolean - transactionId?: boolean - operationIndex?: boolean - blockNumber?: boolean - payoutAt?: boolean - idempotencyKey?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type RewardRecordOmit = runtime.Types.Extensions.GetOmit<"id" | "userId" | "hiveReferenceId" | "rewardType" | "assetSymbol" | "amount" | "transactionId" | "operationIndex" | "blockNumber" | "payoutAt" | "idempotencyKey" | "createdAt" | "updatedAt", ExtArgs["result"]["rewardRecord"]> -export type RewardRecordInclude = { - user?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.RewardRecord$hiveReferenceArgs -} -export type RewardRecordIncludeCreateManyAndReturn = { - user?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.RewardRecord$hiveReferenceArgs -} -export type RewardRecordIncludeUpdateManyAndReturn = { - user?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.RewardRecord$hiveReferenceArgs -} - -export type $RewardRecordPayload = { - name: "RewardRecord" - objects: { - user: Prisma.$UserPayload - hiveReference: Prisma.$HiveReferencePayload | null - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - userId: string - hiveReferenceId: string | null - rewardType: $Enums.RewardType - assetSymbol: string - amount: runtime.Decimal - transactionId: string - operationIndex: number - blockNumber: bigint - payoutAt: Date - idempotencyKey: string - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["rewardRecord"]> - composites: {} -} - -export type RewardRecordGetPayload = runtime.Types.Result.GetResult - -export type RewardRecordCountArgs = - Omit & { - select?: RewardRecordCountAggregateInputType | true - } - -export interface RewardRecordDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['RewardRecord'], meta: { name: 'RewardRecord' } } - /** - * Find zero or one RewardRecord that matches the filter. - * @param {RewardRecordFindUniqueArgs} args - Arguments to find a RewardRecord - * @example - * // Get one RewardRecord - * const rewardRecord = await prisma.rewardRecord.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__RewardRecordClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one RewardRecord that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {RewardRecordFindUniqueOrThrowArgs} args - Arguments to find a RewardRecord - * @example - * // Get one RewardRecord - * const rewardRecord = await prisma.rewardRecord.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__RewardRecordClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first RewardRecord 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 {RewardRecordFindFirstArgs} args - Arguments to find a RewardRecord - * @example - * // Get one RewardRecord - * const rewardRecord = await prisma.rewardRecord.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__RewardRecordClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first RewardRecord 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 {RewardRecordFindFirstOrThrowArgs} args - Arguments to find a RewardRecord - * @example - * // Get one RewardRecord - * const rewardRecord = await prisma.rewardRecord.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__RewardRecordClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more RewardRecords 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 {RewardRecordFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all RewardRecords - * const rewardRecords = await prisma.rewardRecord.findMany() - * - * // Get first 10 RewardRecords - * const rewardRecords = await prisma.rewardRecord.findMany({ take: 10 }) - * - * // Only select the `id` - * const rewardRecordWithIdOnly = await prisma.rewardRecord.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a RewardRecord. - * @param {RewardRecordCreateArgs} args - Arguments to create a RewardRecord. - * @example - * // Create one RewardRecord - * const RewardRecord = await prisma.rewardRecord.create({ - * data: { - * // ... data to create a RewardRecord - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__RewardRecordClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many RewardRecords. - * @param {RewardRecordCreateManyArgs} args - Arguments to create many RewardRecords. - * @example - * // Create many RewardRecords - * const rewardRecord = await prisma.rewardRecord.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many RewardRecords and returns the data saved in the database. - * @param {RewardRecordCreateManyAndReturnArgs} args - Arguments to create many RewardRecords. - * @example - * // Create many RewardRecords - * const rewardRecord = await prisma.rewardRecord.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many RewardRecords and only return the `id` - * const rewardRecordWithIdOnly = await prisma.rewardRecord.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 RewardRecord. - * @param {RewardRecordDeleteArgs} args - Arguments to delete one RewardRecord. - * @example - * // Delete one RewardRecord - * const RewardRecord = await prisma.rewardRecord.delete({ - * where: { - * // ... filter to delete one RewardRecord - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__RewardRecordClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one RewardRecord. - * @param {RewardRecordUpdateArgs} args - Arguments to update one RewardRecord. - * @example - * // Update one RewardRecord - * const rewardRecord = await prisma.rewardRecord.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__RewardRecordClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more RewardRecords. - * @param {RewardRecordDeleteManyArgs} args - Arguments to filter RewardRecords to delete. - * @example - * // Delete a few RewardRecords - * const { count } = await prisma.rewardRecord.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more RewardRecords. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {RewardRecordUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many RewardRecords - * const rewardRecord = await prisma.rewardRecord.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more RewardRecords and returns the data updated in the database. - * @param {RewardRecordUpdateManyAndReturnArgs} args - Arguments to update many RewardRecords. - * @example - * // Update many RewardRecords - * const rewardRecord = await prisma.rewardRecord.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more RewardRecords and only return the `id` - * const rewardRecordWithIdOnly = await prisma.rewardRecord.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 RewardRecord. - * @param {RewardRecordUpsertArgs} args - Arguments to update or create a RewardRecord. - * @example - * // Update or create a RewardRecord - * const rewardRecord = await prisma.rewardRecord.upsert({ - * create: { - * // ... data to create a RewardRecord - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the RewardRecord we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__RewardRecordClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of RewardRecords. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {RewardRecordCountArgs} args - Arguments to filter RewardRecords to count. - * @example - * // Count the number of RewardRecords - * const count = await prisma.rewardRecord.count({ - * where: { - * // ... the filter for the RewardRecords 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 RewardRecord. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {RewardRecordAggregateArgs} 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 RewardRecord. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {RewardRecordGroupByArgs} 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 RewardRecordGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: RewardRecordGroupByArgs['orderBy'] } - : { orderBy?: RewardRecordGroupByArgs['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 ? GetRewardRecordGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the RewardRecord model - */ -readonly fields: RewardRecordFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for RewardRecord. - * 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__RewardRecordClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - user = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - hiveReference = {}>(args?: Prisma.Subset>): Prisma.Prisma__HiveReferenceClient, 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 RewardRecord model - */ -export interface RewardRecordFieldRefs { - readonly id: Prisma.FieldRef<"RewardRecord", 'String'> - readonly userId: Prisma.FieldRef<"RewardRecord", 'String'> - readonly hiveReferenceId: Prisma.FieldRef<"RewardRecord", 'String'> - readonly rewardType: Prisma.FieldRef<"RewardRecord", 'RewardType'> - readonly assetSymbol: Prisma.FieldRef<"RewardRecord", 'String'> - readonly amount: Prisma.FieldRef<"RewardRecord", 'Decimal'> - readonly transactionId: Prisma.FieldRef<"RewardRecord", 'String'> - readonly operationIndex: Prisma.FieldRef<"RewardRecord", 'Int'> - readonly blockNumber: Prisma.FieldRef<"RewardRecord", 'BigInt'> - readonly payoutAt: Prisma.FieldRef<"RewardRecord", 'DateTime'> - readonly idempotencyKey: Prisma.FieldRef<"RewardRecord", 'String'> - readonly createdAt: Prisma.FieldRef<"RewardRecord", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"RewardRecord", 'DateTime'> -} - - -// Custom InputTypes -/** - * RewardRecord findUnique - */ -export type RewardRecordFindUniqueArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - /** - * Filter, which RewardRecord to fetch. - */ - where: Prisma.RewardRecordWhereUniqueInput -} - -/** - * RewardRecord findUniqueOrThrow - */ -export type RewardRecordFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - /** - * Filter, which RewardRecord to fetch. - */ - where: Prisma.RewardRecordWhereUniqueInput -} - -/** - * RewardRecord findFirst - */ -export type RewardRecordFindFirstArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - /** - * Filter, which RewardRecord to fetch. - */ - where?: Prisma.RewardRecordWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of RewardRecords to fetch. - */ - orderBy?: Prisma.RewardRecordOrderByWithRelationInput | Prisma.RewardRecordOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for RewardRecords. - */ - cursor?: Prisma.RewardRecordWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` RewardRecords 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` RewardRecords. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of RewardRecords. - */ - distinct?: Prisma.RewardRecordScalarFieldEnum | Prisma.RewardRecordScalarFieldEnum[] -} - -/** - * RewardRecord findFirstOrThrow - */ -export type RewardRecordFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - /** - * Filter, which RewardRecord to fetch. - */ - where?: Prisma.RewardRecordWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of RewardRecords to fetch. - */ - orderBy?: Prisma.RewardRecordOrderByWithRelationInput | Prisma.RewardRecordOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for RewardRecords. - */ - cursor?: Prisma.RewardRecordWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` RewardRecords 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` RewardRecords. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of RewardRecords. - */ - distinct?: Prisma.RewardRecordScalarFieldEnum | Prisma.RewardRecordScalarFieldEnum[] -} - -/** - * RewardRecord findMany - */ -export type RewardRecordFindManyArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - /** - * Filter, which RewardRecords to fetch. - */ - where?: Prisma.RewardRecordWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of RewardRecords to fetch. - */ - orderBy?: Prisma.RewardRecordOrderByWithRelationInput | Prisma.RewardRecordOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing RewardRecords. - */ - cursor?: Prisma.RewardRecordWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` RewardRecords 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` RewardRecords. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of RewardRecords. - */ - distinct?: Prisma.RewardRecordScalarFieldEnum | Prisma.RewardRecordScalarFieldEnum[] -} - -/** - * RewardRecord create - */ -export type RewardRecordCreateArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - /** - * The data needed to create a RewardRecord. - */ - data: Prisma.XOR -} - -/** - * RewardRecord createMany - */ -export type RewardRecordCreateManyArgs = { - /** - * The data used to create many RewardRecords. - */ - data: Prisma.RewardRecordCreateManyInput | Prisma.RewardRecordCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * RewardRecord createManyAndReturn - */ -export type RewardRecordCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelectCreateManyAndReturn | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * The data used to create many RewardRecords. - */ - data: Prisma.RewardRecordCreateManyInput | Prisma.RewardRecordCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordIncludeCreateManyAndReturn | null -} - -/** - * RewardRecord update - */ -export type RewardRecordUpdateArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - /** - * The data needed to update a RewardRecord. - */ - data: Prisma.XOR - /** - * Choose, which RewardRecord to update. - */ - where: Prisma.RewardRecordWhereUniqueInput -} - -/** - * RewardRecord updateMany - */ -export type RewardRecordUpdateManyArgs = { - /** - * The data used to update RewardRecords. - */ - data: Prisma.XOR - /** - * Filter which RewardRecords to update - */ - where?: Prisma.RewardRecordWhereInput - /** - * Limit how many RewardRecords to update. - */ - limit?: number -} - -/** - * RewardRecord updateManyAndReturn - */ -export type RewardRecordUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * The data used to update RewardRecords. - */ - data: Prisma.XOR - /** - * Filter which RewardRecords to update - */ - where?: Prisma.RewardRecordWhereInput - /** - * Limit how many RewardRecords to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordIncludeUpdateManyAndReturn | null -} - -/** - * RewardRecord upsert - */ -export type RewardRecordUpsertArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - /** - * The filter to search for the RewardRecord to update in case it exists. - */ - where: Prisma.RewardRecordWhereUniqueInput - /** - * In case the RewardRecord found by the `where` argument doesn't exist, create a new RewardRecord with this data. - */ - create: Prisma.XOR - /** - * In case the RewardRecord was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * RewardRecord delete - */ -export type RewardRecordDeleteArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - /** - * Filter which RewardRecord to delete. - */ - where: Prisma.RewardRecordWhereUniqueInput -} - -/** - * RewardRecord deleteMany - */ -export type RewardRecordDeleteManyArgs = { - /** - * Filter which RewardRecords to delete - */ - where?: Prisma.RewardRecordWhereInput - /** - * Limit how many RewardRecords to delete. - */ - limit?: number -} - -/** - * RewardRecord.hiveReference - */ -export type RewardRecord$hiveReferenceArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - where?: Prisma.HiveReferenceWhereInput -} - -/** - * RewardRecord without action - */ -export type RewardRecordDefaultArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null -} diff --git a/apps/api/src/generated/prisma/models/SearchIndex.ts b/apps/api/src/generated/prisma/models/SearchIndex.ts deleted file mode 100644 index bc1bed5..0000000 --- a/apps/api/src/generated/prisma/models/SearchIndex.ts +++ /dev/null @@ -1,1508 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `SearchIndex` 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 SearchIndex - * - */ -export type SearchIndexModel = runtime.Types.Result.DefaultSelection - -export type AggregateSearchIndex = { - _count: SearchIndexCountAggregateOutputType | null - _min: SearchIndexMinAggregateOutputType | null - _max: SearchIndexMaxAggregateOutputType | null -} - -export type SearchIndexMinAggregateOutputType = { - id: string | null - worldId: string | null - entityType: $Enums.SearchEntityType | null - entityId: string | null - title: string | null - searchableContent: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type SearchIndexMaxAggregateOutputType = { - id: string | null - worldId: string | null - entityType: $Enums.SearchEntityType | null - entityId: string | null - title: string | null - searchableContent: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type SearchIndexCountAggregateOutputType = { - id: number - worldId: number - entityType: number - entityId: number - title: number - searchableContent: number - metadata: number - createdAt: number - updatedAt: number - _all: number -} - - -export type SearchIndexMinAggregateInputType = { - id?: true - worldId?: true - entityType?: true - entityId?: true - title?: true - searchableContent?: true - createdAt?: true - updatedAt?: true -} - -export type SearchIndexMaxAggregateInputType = { - id?: true - worldId?: true - entityType?: true - entityId?: true - title?: true - searchableContent?: true - createdAt?: true - updatedAt?: true -} - -export type SearchIndexCountAggregateInputType = { - id?: true - worldId?: true - entityType?: true - entityId?: true - title?: true - searchableContent?: true - metadata?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type SearchIndexAggregateArgs = { - /** - * Filter which SearchIndex to aggregate. - */ - where?: Prisma.SearchIndexWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of SearchIndices to fetch. - */ - orderBy?: Prisma.SearchIndexOrderByWithRelationInput | Prisma.SearchIndexOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.SearchIndexWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` SearchIndices 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` SearchIndices. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned SearchIndices - **/ - _count?: true | SearchIndexCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: SearchIndexMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: SearchIndexMaxAggregateInputType -} - -export type GetSearchIndexAggregateType = { - [P in keyof T & keyof AggregateSearchIndex]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type SearchIndexGroupByArgs = { - where?: Prisma.SearchIndexWhereInput - orderBy?: Prisma.SearchIndexOrderByWithAggregationInput | Prisma.SearchIndexOrderByWithAggregationInput[] - by: Prisma.SearchIndexScalarFieldEnum[] | Prisma.SearchIndexScalarFieldEnum - having?: Prisma.SearchIndexScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: SearchIndexCountAggregateInputType | true - _min?: SearchIndexMinAggregateInputType - _max?: SearchIndexMaxAggregateInputType -} - -export type SearchIndexGroupByOutputType = { - id: string - worldId: string | null - entityType: $Enums.SearchEntityType - entityId: string - title: string - searchableContent: string - metadata: runtime.JsonValue | null - createdAt: Date - updatedAt: Date - _count: SearchIndexCountAggregateOutputType | null - _min: SearchIndexMinAggregateOutputType | null - _max: SearchIndexMaxAggregateOutputType | null -} - -export type GetSearchIndexGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof SearchIndexGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type SearchIndexWhereInput = { - AND?: Prisma.SearchIndexWhereInput | Prisma.SearchIndexWhereInput[] - OR?: Prisma.SearchIndexWhereInput[] - NOT?: Prisma.SearchIndexWhereInput | Prisma.SearchIndexWhereInput[] - id?: Prisma.StringFilter<"SearchIndex"> | string - worldId?: Prisma.StringNullableFilter<"SearchIndex"> | string | null - entityType?: Prisma.EnumSearchEntityTypeFilter<"SearchIndex"> | $Enums.SearchEntityType - entityId?: Prisma.StringFilter<"SearchIndex"> | string - title?: Prisma.StringFilter<"SearchIndex"> | string - searchableContent?: Prisma.StringFilter<"SearchIndex"> | string - metadata?: Prisma.JsonNullableFilter<"SearchIndex"> - createdAt?: Prisma.DateTimeFilter<"SearchIndex"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"SearchIndex"> | Date | string - world?: Prisma.XOR | null -} - -export type SearchIndexOrderByWithRelationInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrderInput | Prisma.SortOrder - entityType?: Prisma.SortOrder - entityId?: Prisma.SortOrder - title?: Prisma.SortOrder - searchableContent?: Prisma.SortOrder - metadata?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - world?: Prisma.WorldOrderByWithRelationInput -} - -export type SearchIndexWhereUniqueInput = Prisma.AtLeast<{ - id?: string - entityType_entityId?: Prisma.SearchIndexEntityTypeEntityIdCompoundUniqueInput - AND?: Prisma.SearchIndexWhereInput | Prisma.SearchIndexWhereInput[] - OR?: Prisma.SearchIndexWhereInput[] - NOT?: Prisma.SearchIndexWhereInput | Prisma.SearchIndexWhereInput[] - worldId?: Prisma.StringNullableFilter<"SearchIndex"> | string | null - entityType?: Prisma.EnumSearchEntityTypeFilter<"SearchIndex"> | $Enums.SearchEntityType - entityId?: Prisma.StringFilter<"SearchIndex"> | string - title?: Prisma.StringFilter<"SearchIndex"> | string - searchableContent?: Prisma.StringFilter<"SearchIndex"> | string - metadata?: Prisma.JsonNullableFilter<"SearchIndex"> - createdAt?: Prisma.DateTimeFilter<"SearchIndex"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"SearchIndex"> | Date | string - world?: Prisma.XOR | null -}, "id" | "entityType_entityId"> - -export type SearchIndexOrderByWithAggregationInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrderInput | Prisma.SortOrder - entityType?: Prisma.SortOrder - entityId?: Prisma.SortOrder - title?: Prisma.SortOrder - searchableContent?: Prisma.SortOrder - metadata?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.SearchIndexCountOrderByAggregateInput - _max?: Prisma.SearchIndexMaxOrderByAggregateInput - _min?: Prisma.SearchIndexMinOrderByAggregateInput -} - -export type SearchIndexScalarWhereWithAggregatesInput = { - AND?: Prisma.SearchIndexScalarWhereWithAggregatesInput | Prisma.SearchIndexScalarWhereWithAggregatesInput[] - OR?: Prisma.SearchIndexScalarWhereWithAggregatesInput[] - NOT?: Prisma.SearchIndexScalarWhereWithAggregatesInput | Prisma.SearchIndexScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"SearchIndex"> | string - worldId?: Prisma.StringNullableWithAggregatesFilter<"SearchIndex"> | string | null - entityType?: Prisma.EnumSearchEntityTypeWithAggregatesFilter<"SearchIndex"> | $Enums.SearchEntityType - entityId?: Prisma.StringWithAggregatesFilter<"SearchIndex"> | string - title?: Prisma.StringWithAggregatesFilter<"SearchIndex"> | string - searchableContent?: Prisma.StringWithAggregatesFilter<"SearchIndex"> | string - metadata?: Prisma.JsonNullableWithAggregatesFilter<"SearchIndex"> - createdAt?: Prisma.DateTimeWithAggregatesFilter<"SearchIndex"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"SearchIndex"> | Date | string -} - -export type SearchIndexCreateInput = { - id?: string - entityType: $Enums.SearchEntityType - entityId: string - title: string - searchableContent: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string - world?: Prisma.WorldCreateNestedOneWithoutSearchIndexesInput -} - -export type SearchIndexUncheckedCreateInput = { - id?: string - worldId?: string | null - entityType: $Enums.SearchEntityType - entityId: string - title: string - searchableContent: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type SearchIndexUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumSearchEntityTypeFieldUpdateOperationsInput | $Enums.SearchEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - searchableContent?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneWithoutSearchIndexesNestedInput -} - -export type SearchIndexUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - entityType?: Prisma.EnumSearchEntityTypeFieldUpdateOperationsInput | $Enums.SearchEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - searchableContent?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type SearchIndexCreateManyInput = { - id?: string - worldId?: string | null - entityType: $Enums.SearchEntityType - entityId: string - title: string - searchableContent: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type SearchIndexUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumSearchEntityTypeFieldUpdateOperationsInput | $Enums.SearchEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - searchableContent?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type SearchIndexUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - entityType?: Prisma.EnumSearchEntityTypeFieldUpdateOperationsInput | $Enums.SearchEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - searchableContent?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type SearchIndexListRelationFilter = { - every?: Prisma.SearchIndexWhereInput - some?: Prisma.SearchIndexWhereInput - none?: Prisma.SearchIndexWhereInput -} - -export type SearchIndexOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type SearchIndexEntityTypeEntityIdCompoundUniqueInput = { - entityType: $Enums.SearchEntityType - entityId: string -} - -export type SearchIndexCountOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - entityType?: Prisma.SortOrder - entityId?: Prisma.SortOrder - title?: Prisma.SortOrder - searchableContent?: Prisma.SortOrder - metadata?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type SearchIndexMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - entityType?: Prisma.SortOrder - entityId?: Prisma.SortOrder - title?: Prisma.SortOrder - searchableContent?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type SearchIndexMinOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - entityType?: Prisma.SortOrder - entityId?: Prisma.SortOrder - title?: Prisma.SortOrder - searchableContent?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type SearchIndexCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.SearchIndexCreateWithoutWorldInput[] | Prisma.SearchIndexUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.SearchIndexCreateOrConnectWithoutWorldInput | Prisma.SearchIndexCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.SearchIndexCreateManyWorldInputEnvelope - connect?: Prisma.SearchIndexWhereUniqueInput | Prisma.SearchIndexWhereUniqueInput[] -} - -export type SearchIndexUncheckedCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.SearchIndexCreateWithoutWorldInput[] | Prisma.SearchIndexUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.SearchIndexCreateOrConnectWithoutWorldInput | Prisma.SearchIndexCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.SearchIndexCreateManyWorldInputEnvelope - connect?: Prisma.SearchIndexWhereUniqueInput | Prisma.SearchIndexWhereUniqueInput[] -} - -export type SearchIndexUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.SearchIndexCreateWithoutWorldInput[] | Prisma.SearchIndexUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.SearchIndexCreateOrConnectWithoutWorldInput | Prisma.SearchIndexCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.SearchIndexUpsertWithWhereUniqueWithoutWorldInput | Prisma.SearchIndexUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.SearchIndexCreateManyWorldInputEnvelope - set?: Prisma.SearchIndexWhereUniqueInput | Prisma.SearchIndexWhereUniqueInput[] - disconnect?: Prisma.SearchIndexWhereUniqueInput | Prisma.SearchIndexWhereUniqueInput[] - delete?: Prisma.SearchIndexWhereUniqueInput | Prisma.SearchIndexWhereUniqueInput[] - connect?: Prisma.SearchIndexWhereUniqueInput | Prisma.SearchIndexWhereUniqueInput[] - update?: Prisma.SearchIndexUpdateWithWhereUniqueWithoutWorldInput | Prisma.SearchIndexUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.SearchIndexUpdateManyWithWhereWithoutWorldInput | Prisma.SearchIndexUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.SearchIndexScalarWhereInput | Prisma.SearchIndexScalarWhereInput[] -} - -export type SearchIndexUncheckedUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.SearchIndexCreateWithoutWorldInput[] | Prisma.SearchIndexUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.SearchIndexCreateOrConnectWithoutWorldInput | Prisma.SearchIndexCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.SearchIndexUpsertWithWhereUniqueWithoutWorldInput | Prisma.SearchIndexUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.SearchIndexCreateManyWorldInputEnvelope - set?: Prisma.SearchIndexWhereUniqueInput | Prisma.SearchIndexWhereUniqueInput[] - disconnect?: Prisma.SearchIndexWhereUniqueInput | Prisma.SearchIndexWhereUniqueInput[] - delete?: Prisma.SearchIndexWhereUniqueInput | Prisma.SearchIndexWhereUniqueInput[] - connect?: Prisma.SearchIndexWhereUniqueInput | Prisma.SearchIndexWhereUniqueInput[] - update?: Prisma.SearchIndexUpdateWithWhereUniqueWithoutWorldInput | Prisma.SearchIndexUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.SearchIndexUpdateManyWithWhereWithoutWorldInput | Prisma.SearchIndexUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.SearchIndexScalarWhereInput | Prisma.SearchIndexScalarWhereInput[] -} - -export type EnumSearchEntityTypeFieldUpdateOperationsInput = { - set?: $Enums.SearchEntityType -} - -export type SearchIndexCreateWithoutWorldInput = { - id?: string - entityType: $Enums.SearchEntityType - entityId: string - title: string - searchableContent: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type SearchIndexUncheckedCreateWithoutWorldInput = { - id?: string - entityType: $Enums.SearchEntityType - entityId: string - title: string - searchableContent: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type SearchIndexCreateOrConnectWithoutWorldInput = { - where: Prisma.SearchIndexWhereUniqueInput - create: Prisma.XOR -} - -export type SearchIndexCreateManyWorldInputEnvelope = { - data: Prisma.SearchIndexCreateManyWorldInput | Prisma.SearchIndexCreateManyWorldInput[] - skipDuplicates?: boolean -} - -export type SearchIndexUpsertWithWhereUniqueWithoutWorldInput = { - where: Prisma.SearchIndexWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type SearchIndexUpdateWithWhereUniqueWithoutWorldInput = { - where: Prisma.SearchIndexWhereUniqueInput - data: Prisma.XOR -} - -export type SearchIndexUpdateManyWithWhereWithoutWorldInput = { - where: Prisma.SearchIndexScalarWhereInput - data: Prisma.XOR -} - -export type SearchIndexScalarWhereInput = { - AND?: Prisma.SearchIndexScalarWhereInput | Prisma.SearchIndexScalarWhereInput[] - OR?: Prisma.SearchIndexScalarWhereInput[] - NOT?: Prisma.SearchIndexScalarWhereInput | Prisma.SearchIndexScalarWhereInput[] - id?: Prisma.StringFilter<"SearchIndex"> | string - worldId?: Prisma.StringNullableFilter<"SearchIndex"> | string | null - entityType?: Prisma.EnumSearchEntityTypeFilter<"SearchIndex"> | $Enums.SearchEntityType - entityId?: Prisma.StringFilter<"SearchIndex"> | string - title?: Prisma.StringFilter<"SearchIndex"> | string - searchableContent?: Prisma.StringFilter<"SearchIndex"> | string - metadata?: Prisma.JsonNullableFilter<"SearchIndex"> - createdAt?: Prisma.DateTimeFilter<"SearchIndex"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"SearchIndex"> | Date | string -} - -export type SearchIndexCreateManyWorldInput = { - id?: string - entityType: $Enums.SearchEntityType - entityId: string - title: string - searchableContent: string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Date | string - updatedAt?: Date | string -} - -export type SearchIndexUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumSearchEntityTypeFieldUpdateOperationsInput | $Enums.SearchEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - searchableContent?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type SearchIndexUncheckedUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumSearchEntityTypeFieldUpdateOperationsInput | $Enums.SearchEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - searchableContent?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type SearchIndexUncheckedUpdateManyWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - entityType?: Prisma.EnumSearchEntityTypeFieldUpdateOperationsInput | $Enums.SearchEntityType - entityId?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - searchableContent?: Prisma.StringFieldUpdateOperationsInput | string - metadata?: Prisma.NullableJsonNullValueInput | runtime.InputJsonValue - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - - -export type SearchIndexSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - entityType?: boolean - entityId?: boolean - title?: boolean - searchableContent?: boolean - metadata?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.SearchIndex$worldArgs -}, ExtArgs["result"]["searchIndex"]> - -export type SearchIndexSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - entityType?: boolean - entityId?: boolean - title?: boolean - searchableContent?: boolean - metadata?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.SearchIndex$worldArgs -}, ExtArgs["result"]["searchIndex"]> - -export type SearchIndexSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - entityType?: boolean - entityId?: boolean - title?: boolean - searchableContent?: boolean - metadata?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.SearchIndex$worldArgs -}, ExtArgs["result"]["searchIndex"]> - -export type SearchIndexSelectScalar = { - id?: boolean - worldId?: boolean - entityType?: boolean - entityId?: boolean - title?: boolean - searchableContent?: boolean - metadata?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type SearchIndexOmit = runtime.Types.Extensions.GetOmit<"id" | "worldId" | "entityType" | "entityId" | "title" | "searchableContent" | "metadata" | "createdAt" | "updatedAt", ExtArgs["result"]["searchIndex"]> -export type SearchIndexInclude = { - world?: boolean | Prisma.SearchIndex$worldArgs -} -export type SearchIndexIncludeCreateManyAndReturn = { - world?: boolean | Prisma.SearchIndex$worldArgs -} -export type SearchIndexIncludeUpdateManyAndReturn = { - world?: boolean | Prisma.SearchIndex$worldArgs -} - -export type $SearchIndexPayload = { - name: "SearchIndex" - objects: { - world: Prisma.$WorldPayload | null - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - worldId: string | null - entityType: $Enums.SearchEntityType - entityId: string - title: string - searchableContent: string - metadata: runtime.JsonValue | null - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["searchIndex"]> - composites: {} -} - -export type SearchIndexGetPayload = runtime.Types.Result.GetResult - -export type SearchIndexCountArgs = - Omit & { - select?: SearchIndexCountAggregateInputType | true - } - -export interface SearchIndexDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['SearchIndex'], meta: { name: 'SearchIndex' } } - /** - * Find zero or one SearchIndex that matches the filter. - * @param {SearchIndexFindUniqueArgs} args - Arguments to find a SearchIndex - * @example - * // Get one SearchIndex - * const searchIndex = await prisma.searchIndex.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__SearchIndexClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one SearchIndex that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {SearchIndexFindUniqueOrThrowArgs} args - Arguments to find a SearchIndex - * @example - * // Get one SearchIndex - * const searchIndex = await prisma.searchIndex.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__SearchIndexClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first SearchIndex 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 {SearchIndexFindFirstArgs} args - Arguments to find a SearchIndex - * @example - * // Get one SearchIndex - * const searchIndex = await prisma.searchIndex.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__SearchIndexClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first SearchIndex 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 {SearchIndexFindFirstOrThrowArgs} args - Arguments to find a SearchIndex - * @example - * // Get one SearchIndex - * const searchIndex = await prisma.searchIndex.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__SearchIndexClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more SearchIndices 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 {SearchIndexFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all SearchIndices - * const searchIndices = await prisma.searchIndex.findMany() - * - * // Get first 10 SearchIndices - * const searchIndices = await prisma.searchIndex.findMany({ take: 10 }) - * - * // Only select the `id` - * const searchIndexWithIdOnly = await prisma.searchIndex.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a SearchIndex. - * @param {SearchIndexCreateArgs} args - Arguments to create a SearchIndex. - * @example - * // Create one SearchIndex - * const SearchIndex = await prisma.searchIndex.create({ - * data: { - * // ... data to create a SearchIndex - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__SearchIndexClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many SearchIndices. - * @param {SearchIndexCreateManyArgs} args - Arguments to create many SearchIndices. - * @example - * // Create many SearchIndices - * const searchIndex = await prisma.searchIndex.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many SearchIndices and returns the data saved in the database. - * @param {SearchIndexCreateManyAndReturnArgs} args - Arguments to create many SearchIndices. - * @example - * // Create many SearchIndices - * const searchIndex = await prisma.searchIndex.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many SearchIndices and only return the `id` - * const searchIndexWithIdOnly = await prisma.searchIndex.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 SearchIndex. - * @param {SearchIndexDeleteArgs} args - Arguments to delete one SearchIndex. - * @example - * // Delete one SearchIndex - * const SearchIndex = await prisma.searchIndex.delete({ - * where: { - * // ... filter to delete one SearchIndex - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__SearchIndexClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one SearchIndex. - * @param {SearchIndexUpdateArgs} args - Arguments to update one SearchIndex. - * @example - * // Update one SearchIndex - * const searchIndex = await prisma.searchIndex.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__SearchIndexClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more SearchIndices. - * @param {SearchIndexDeleteManyArgs} args - Arguments to filter SearchIndices to delete. - * @example - * // Delete a few SearchIndices - * const { count } = await prisma.searchIndex.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more SearchIndices. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {SearchIndexUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many SearchIndices - * const searchIndex = await prisma.searchIndex.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more SearchIndices and returns the data updated in the database. - * @param {SearchIndexUpdateManyAndReturnArgs} args - Arguments to update many SearchIndices. - * @example - * // Update many SearchIndices - * const searchIndex = await prisma.searchIndex.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more SearchIndices and only return the `id` - * const searchIndexWithIdOnly = await prisma.searchIndex.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 SearchIndex. - * @param {SearchIndexUpsertArgs} args - Arguments to update or create a SearchIndex. - * @example - * // Update or create a SearchIndex - * const searchIndex = await prisma.searchIndex.upsert({ - * create: { - * // ... data to create a SearchIndex - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the SearchIndex we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__SearchIndexClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of SearchIndices. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {SearchIndexCountArgs} args - Arguments to filter SearchIndices to count. - * @example - * // Count the number of SearchIndices - * const count = await prisma.searchIndex.count({ - * where: { - * // ... the filter for the SearchIndices 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 SearchIndex. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {SearchIndexAggregateArgs} 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 SearchIndex. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {SearchIndexGroupByArgs} 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 SearchIndexGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: SearchIndexGroupByArgs['orderBy'] } - : { orderBy?: SearchIndexGroupByArgs['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 ? GetSearchIndexGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the SearchIndex model - */ -readonly fields: SearchIndexFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for SearchIndex. - * 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__SearchIndexClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - world = {}>(args?: Prisma.Subset>): Prisma.Prisma__WorldClient, 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 SearchIndex model - */ -export interface SearchIndexFieldRefs { - readonly id: Prisma.FieldRef<"SearchIndex", 'String'> - readonly worldId: Prisma.FieldRef<"SearchIndex", 'String'> - readonly entityType: Prisma.FieldRef<"SearchIndex", 'SearchEntityType'> - readonly entityId: Prisma.FieldRef<"SearchIndex", 'String'> - readonly title: Prisma.FieldRef<"SearchIndex", 'String'> - readonly searchableContent: Prisma.FieldRef<"SearchIndex", 'String'> - readonly metadata: Prisma.FieldRef<"SearchIndex", 'Json'> - readonly createdAt: Prisma.FieldRef<"SearchIndex", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"SearchIndex", 'DateTime'> -} - - -// Custom InputTypes -/** - * SearchIndex findUnique - */ -export type SearchIndexFindUniqueArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null - /** - * Filter, which SearchIndex to fetch. - */ - where: Prisma.SearchIndexWhereUniqueInput -} - -/** - * SearchIndex findUniqueOrThrow - */ -export type SearchIndexFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null - /** - * Filter, which SearchIndex to fetch. - */ - where: Prisma.SearchIndexWhereUniqueInput -} - -/** - * SearchIndex findFirst - */ -export type SearchIndexFindFirstArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null - /** - * Filter, which SearchIndex to fetch. - */ - where?: Prisma.SearchIndexWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of SearchIndices to fetch. - */ - orderBy?: Prisma.SearchIndexOrderByWithRelationInput | Prisma.SearchIndexOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for SearchIndices. - */ - cursor?: Prisma.SearchIndexWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` SearchIndices 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` SearchIndices. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of SearchIndices. - */ - distinct?: Prisma.SearchIndexScalarFieldEnum | Prisma.SearchIndexScalarFieldEnum[] -} - -/** - * SearchIndex findFirstOrThrow - */ -export type SearchIndexFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null - /** - * Filter, which SearchIndex to fetch. - */ - where?: Prisma.SearchIndexWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of SearchIndices to fetch. - */ - orderBy?: Prisma.SearchIndexOrderByWithRelationInput | Prisma.SearchIndexOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for SearchIndices. - */ - cursor?: Prisma.SearchIndexWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` SearchIndices 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` SearchIndices. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of SearchIndices. - */ - distinct?: Prisma.SearchIndexScalarFieldEnum | Prisma.SearchIndexScalarFieldEnum[] -} - -/** - * SearchIndex findMany - */ -export type SearchIndexFindManyArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null - /** - * Filter, which SearchIndices to fetch. - */ - where?: Prisma.SearchIndexWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of SearchIndices to fetch. - */ - orderBy?: Prisma.SearchIndexOrderByWithRelationInput | Prisma.SearchIndexOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing SearchIndices. - */ - cursor?: Prisma.SearchIndexWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` SearchIndices 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` SearchIndices. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of SearchIndices. - */ - distinct?: Prisma.SearchIndexScalarFieldEnum | Prisma.SearchIndexScalarFieldEnum[] -} - -/** - * SearchIndex create - */ -export type SearchIndexCreateArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null - /** - * The data needed to create a SearchIndex. - */ - data: Prisma.XOR -} - -/** - * SearchIndex createMany - */ -export type SearchIndexCreateManyArgs = { - /** - * The data used to create many SearchIndices. - */ - data: Prisma.SearchIndexCreateManyInput | Prisma.SearchIndexCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * SearchIndex createManyAndReturn - */ -export type SearchIndexCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelectCreateManyAndReturn | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * The data used to create many SearchIndices. - */ - data: Prisma.SearchIndexCreateManyInput | Prisma.SearchIndexCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexIncludeCreateManyAndReturn | null -} - -/** - * SearchIndex update - */ -export type SearchIndexUpdateArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null - /** - * The data needed to update a SearchIndex. - */ - data: Prisma.XOR - /** - * Choose, which SearchIndex to update. - */ - where: Prisma.SearchIndexWhereUniqueInput -} - -/** - * SearchIndex updateMany - */ -export type SearchIndexUpdateManyArgs = { - /** - * The data used to update SearchIndices. - */ - data: Prisma.XOR - /** - * Filter which SearchIndices to update - */ - where?: Prisma.SearchIndexWhereInput - /** - * Limit how many SearchIndices to update. - */ - limit?: number -} - -/** - * SearchIndex updateManyAndReturn - */ -export type SearchIndexUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * The data used to update SearchIndices. - */ - data: Prisma.XOR - /** - * Filter which SearchIndices to update - */ - where?: Prisma.SearchIndexWhereInput - /** - * Limit how many SearchIndices to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexIncludeUpdateManyAndReturn | null -} - -/** - * SearchIndex upsert - */ -export type SearchIndexUpsertArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null - /** - * The filter to search for the SearchIndex to update in case it exists. - */ - where: Prisma.SearchIndexWhereUniqueInput - /** - * In case the SearchIndex found by the `where` argument doesn't exist, create a new SearchIndex with this data. - */ - create: Prisma.XOR - /** - * In case the SearchIndex was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * SearchIndex delete - */ -export type SearchIndexDeleteArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null - /** - * Filter which SearchIndex to delete. - */ - where: Prisma.SearchIndexWhereUniqueInput -} - -/** - * SearchIndex deleteMany - */ -export type SearchIndexDeleteManyArgs = { - /** - * Filter which SearchIndices to delete - */ - where?: Prisma.SearchIndexWhereInput - /** - * Limit how many SearchIndices to delete. - */ - limit?: number -} - -/** - * SearchIndex.world - */ -export type SearchIndex$worldArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - where?: Prisma.WorldWhereInput -} - -/** - * SearchIndex without action - */ -export type SearchIndexDefaultArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null -} diff --git a/apps/api/src/generated/prisma/models/User.ts b/apps/api/src/generated/prisma/models/User.ts deleted file mode 100644 index 0da83a8..0000000 --- a/apps/api/src/generated/prisma/models/User.ts +++ /dev/null @@ -1,3064 +0,0 @@ - -/* !!! 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 - hiveUsername: string | null - normalizedHiveUsername: string | null - displayName: string | null - avatarUrl: string | null - bio: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type UserMaxAggregateOutputType = { - id: string | null - hiveUsername: string | null - normalizedHiveUsername: string | null - displayName: string | null - avatarUrl: string | null - bio: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type UserCountAggregateOutputType = { - id: number - hiveUsername: number - normalizedHiveUsername: number - displayName: number - avatarUrl: number - bio: number - createdAt: number - updatedAt: number - _all: number -} - - -export type UserMinAggregateInputType = { - id?: true - hiveUsername?: true - normalizedHiveUsername?: true - displayName?: true - avatarUrl?: true - bio?: true - createdAt?: true - updatedAt?: true -} - -export type UserMaxAggregateInputType = { - id?: true - hiveUsername?: true - normalizedHiveUsername?: true - displayName?: true - avatarUrl?: true - bio?: true - createdAt?: true - updatedAt?: true -} - -export type UserCountAggregateInputType = { - id?: true - hiveUsername?: true - normalizedHiveUsername?: true - displayName?: true - avatarUrl?: true - bio?: 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 - hiveUsername: string - normalizedHiveUsername: string - displayName: string | null - avatarUrl: string | null - bio: string | null - 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 - hiveUsername?: Prisma.StringFilter<"User"> | string - normalizedHiveUsername?: Prisma.StringFilter<"User"> | string - displayName?: Prisma.StringNullableFilter<"User"> | string | null - avatarUrl?: Prisma.StringNullableFilter<"User"> | string | null - bio?: Prisma.StringNullableFilter<"User"> | string | null - createdAt?: Prisma.DateTimeFilter<"User"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string - foundedWorlds?: Prisma.WorldListRelationFilter - bibleVersions?: Prisma.WorldBibleVersionListRelationFilter - loreEntries?: Prisma.LoreEntryListRelationFilter - proposals?: Prisma.ProposalListRelationFilter - votes?: Prisma.AppVoteListRelationFilter - moderationReports?: Prisma.ModerationReportListRelationFilter - moderationReviews?: Prisma.ModerationReportListRelationFilter - hiveReferences?: Prisma.HiveReferenceListRelationFilter - rewardRecords?: Prisma.RewardRecordListRelationFilter - rewardSummaries?: Prisma.UserRewardSummaryListRelationFilter - reputationSnapshots?: Prisma.UserReputationSnapshotListRelationFilter -} - -export type UserOrderByWithRelationInput = { - id?: Prisma.SortOrder - hiveUsername?: Prisma.SortOrder - normalizedHiveUsername?: Prisma.SortOrder - displayName?: Prisma.SortOrderInput | Prisma.SortOrder - avatarUrl?: Prisma.SortOrderInput | Prisma.SortOrder - bio?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - foundedWorlds?: Prisma.WorldOrderByRelationAggregateInput - bibleVersions?: Prisma.WorldBibleVersionOrderByRelationAggregateInput - loreEntries?: Prisma.LoreEntryOrderByRelationAggregateInput - proposals?: Prisma.ProposalOrderByRelationAggregateInput - votes?: Prisma.AppVoteOrderByRelationAggregateInput - moderationReports?: Prisma.ModerationReportOrderByRelationAggregateInput - moderationReviews?: Prisma.ModerationReportOrderByRelationAggregateInput - hiveReferences?: Prisma.HiveReferenceOrderByRelationAggregateInput - rewardRecords?: Prisma.RewardRecordOrderByRelationAggregateInput - rewardSummaries?: Prisma.UserRewardSummaryOrderByRelationAggregateInput - reputationSnapshots?: Prisma.UserReputationSnapshotOrderByRelationAggregateInput -} - -export type UserWhereUniqueInput = Prisma.AtLeast<{ - id?: string - hiveUsername?: string - normalizedHiveUsername?: string - AND?: Prisma.UserWhereInput | Prisma.UserWhereInput[] - OR?: Prisma.UserWhereInput[] - NOT?: Prisma.UserWhereInput | Prisma.UserWhereInput[] - displayName?: Prisma.StringNullableFilter<"User"> | string | null - avatarUrl?: Prisma.StringNullableFilter<"User"> | string | null - bio?: Prisma.StringNullableFilter<"User"> | string | null - createdAt?: Prisma.DateTimeFilter<"User"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string - foundedWorlds?: Prisma.WorldListRelationFilter - bibleVersions?: Prisma.WorldBibleVersionListRelationFilter - loreEntries?: Prisma.LoreEntryListRelationFilter - proposals?: Prisma.ProposalListRelationFilter - votes?: Prisma.AppVoteListRelationFilter - moderationReports?: Prisma.ModerationReportListRelationFilter - moderationReviews?: Prisma.ModerationReportListRelationFilter - hiveReferences?: Prisma.HiveReferenceListRelationFilter - rewardRecords?: Prisma.RewardRecordListRelationFilter - rewardSummaries?: Prisma.UserRewardSummaryListRelationFilter - reputationSnapshots?: Prisma.UserReputationSnapshotListRelationFilter -}, "id" | "hiveUsername" | "normalizedHiveUsername"> - -export type UserOrderByWithAggregationInput = { - id?: Prisma.SortOrder - hiveUsername?: Prisma.SortOrder - normalizedHiveUsername?: Prisma.SortOrder - displayName?: Prisma.SortOrderInput | Prisma.SortOrder - avatarUrl?: Prisma.SortOrderInput | Prisma.SortOrder - bio?: Prisma.SortOrderInput | 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 - hiveUsername?: Prisma.StringWithAggregatesFilter<"User"> | string - normalizedHiveUsername?: Prisma.StringWithAggregatesFilter<"User"> | string - displayName?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null - avatarUrl?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null - bio?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null - createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string -} - -export type UserCreateInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserCreateManyInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type UserUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type UserUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type UserCountOrderByAggregateInput = { - id?: Prisma.SortOrder - hiveUsername?: Prisma.SortOrder - normalizedHiveUsername?: Prisma.SortOrder - displayName?: Prisma.SortOrder - avatarUrl?: Prisma.SortOrder - bio?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type UserMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - hiveUsername?: Prisma.SortOrder - normalizedHiveUsername?: Prisma.SortOrder - displayName?: Prisma.SortOrder - avatarUrl?: Prisma.SortOrder - bio?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type UserMinOrderByAggregateInput = { - id?: Prisma.SortOrder - hiveUsername?: Prisma.SortOrder - normalizedHiveUsername?: Prisma.SortOrder - displayName?: Prisma.SortOrder - avatarUrl?: Prisma.SortOrder - bio?: 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 DateTimeFieldUpdateOperationsInput = { - set?: Date | string -} - -export type UserCreateNestedOneWithoutFoundedWorldsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutFoundedWorldsInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserUpdateOneRequiredWithoutFoundedWorldsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutFoundedWorldsInput - upsert?: Prisma.UserUpsertWithoutFoundedWorldsInput - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutFoundedWorldsInput> -} - -export type UserCreateNestedOneWithoutBibleVersionsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutBibleVersionsInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserUpdateOneRequiredWithoutBibleVersionsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutBibleVersionsInput - upsert?: Prisma.UserUpsertWithoutBibleVersionsInput - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutBibleVersionsInput> -} - -export type UserCreateNestedOneWithoutLoreEntriesInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutLoreEntriesInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserUpdateOneRequiredWithoutLoreEntriesNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutLoreEntriesInput - upsert?: Prisma.UserUpsertWithoutLoreEntriesInput - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutLoreEntriesInput> -} - -export type UserCreateNestedOneWithoutProposalsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutProposalsInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserUpdateOneRequiredWithoutProposalsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutProposalsInput - upsert?: Prisma.UserUpsertWithoutProposalsInput - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutProposalsInput> -} - -export type UserCreateNestedOneWithoutVotesInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutVotesInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserUpdateOneRequiredWithoutVotesNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutVotesInput - upsert?: Prisma.UserUpsertWithoutVotesInput - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutVotesInput> -} - -export type UserCreateNestedOneWithoutModerationReportsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutModerationReportsInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserCreateNestedOneWithoutModerationReviewsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutModerationReviewsInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserUpdateOneRequiredWithoutModerationReportsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutModerationReportsInput - upsert?: Prisma.UserUpsertWithoutModerationReportsInput - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutModerationReportsInput> -} - -export type UserUpdateOneWithoutModerationReviewsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutModerationReviewsInput - upsert?: Prisma.UserUpsertWithoutModerationReviewsInput - disconnect?: Prisma.UserWhereInput | boolean - delete?: Prisma.UserWhereInput | boolean - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutModerationReviewsInput> -} - -export type UserCreateNestedOneWithoutHiveReferencesInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutHiveReferencesInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserUpdateOneWithoutHiveReferencesNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutHiveReferencesInput - upsert?: Prisma.UserUpsertWithoutHiveReferencesInput - disconnect?: Prisma.UserWhereInput | boolean - delete?: Prisma.UserWhereInput | boolean - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutHiveReferencesInput> -} - -export type UserCreateNestedOneWithoutRewardRecordsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutRewardRecordsInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserUpdateOneRequiredWithoutRewardRecordsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutRewardRecordsInput - upsert?: Prisma.UserUpsertWithoutRewardRecordsInput - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutRewardRecordsInput> -} - -export type UserCreateNestedOneWithoutRewardSummariesInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutRewardSummariesInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserUpdateOneRequiredWithoutRewardSummariesNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutRewardSummariesInput - upsert?: Prisma.UserUpsertWithoutRewardSummariesInput - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutRewardSummariesInput> -} - -export type UserCreateNestedOneWithoutReputationSnapshotsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutReputationSnapshotsInput - connect?: Prisma.UserWhereUniqueInput -} - -export type UserUpdateOneRequiredWithoutReputationSnapshotsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserCreateOrConnectWithoutReputationSnapshotsInput - upsert?: Prisma.UserUpsertWithoutReputationSnapshotsInput - connect?: Prisma.UserWhereUniqueInput - update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutReputationSnapshotsInput> -} - -export type UserCreateWithoutFoundedWorldsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutFoundedWorldsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutFoundedWorldsInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserUpsertWithoutFoundedWorldsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutFoundedWorldsInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutFoundedWorldsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutFoundedWorldsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserCreateWithoutBibleVersionsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutBibleVersionsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutBibleVersionsInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserUpsertWithoutBibleVersionsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutBibleVersionsInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutBibleVersionsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutBibleVersionsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserCreateWithoutLoreEntriesInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutLoreEntriesInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutLoreEntriesInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserUpsertWithoutLoreEntriesInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutLoreEntriesInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutLoreEntriesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutLoreEntriesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserCreateWithoutProposalsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutProposalsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutProposalsInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserUpsertWithoutProposalsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutProposalsInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutProposalsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutProposalsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserCreateWithoutVotesInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutVotesInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutVotesInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserUpsertWithoutVotesInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutVotesInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutVotesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutVotesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserCreateWithoutModerationReportsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutModerationReportsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutModerationReportsInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserCreateWithoutModerationReviewsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutModerationReviewsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutModerationReviewsInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserUpsertWithoutModerationReportsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutModerationReportsInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutModerationReportsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutModerationReportsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserUpsertWithoutModerationReviewsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutModerationReviewsInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutModerationReviewsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutModerationReviewsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserCreateWithoutHiveReferencesInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutHiveReferencesInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutHiveReferencesInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserUpsertWithoutHiveReferencesInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutHiveReferencesInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutHiveReferencesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutHiveReferencesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserCreateWithoutRewardRecordsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutRewardRecordsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutRewardRecordsInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserUpsertWithoutRewardRecordsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutRewardRecordsInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutRewardRecordsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutRewardRecordsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserCreateWithoutRewardSummariesInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutRewardSummariesInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutRewardSummariesInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserUpsertWithoutRewardSummariesInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutRewardSummariesInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutRewardSummariesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutRewardSummariesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - reputationSnapshots?: Prisma.UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput -} - -export type UserCreateWithoutReputationSnapshotsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryCreateNestedManyWithoutUserInput -} - -export type UserUncheckedCreateWithoutReputationSnapshotsInput = { - id?: string - hiveUsername: string - normalizedHiveUsername: string - displayName?: string | null - avatarUrl?: string | null - bio?: string | null - createdAt?: Date | string - updatedAt?: Date | string - foundedWorlds?: Prisma.WorldUncheckedCreateNestedManyWithoutFounderInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutAuthorInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutAuthorInput - votes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutVoterInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReporterInput - moderationReviews?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutReviewerInput - hiveReferences?: Prisma.HiveReferenceUncheckedCreateNestedManyWithoutAuthorInput - rewardRecords?: Prisma.RewardRecordUncheckedCreateNestedManyWithoutUserInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput -} - -export type UserCreateOrConnectWithoutReputationSnapshotsInput = { - where: Prisma.UserWhereUniqueInput - create: Prisma.XOR -} - -export type UserUpsertWithoutReputationSnapshotsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserWhereInput -} - -export type UserUpdateToOneWithWhereWithoutReputationSnapshotsInput = { - where?: Prisma.UserWhereInput - data: Prisma.XOR -} - -export type UserUpdateWithoutReputationSnapshotsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUpdateManyWithoutUserNestedInput -} - -export type UserUncheckedUpdateWithoutReputationSnapshotsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - hiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - normalizedHiveUsername?: Prisma.StringFieldUpdateOperationsInput | string - displayName?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - avatarUrl?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - bio?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - foundedWorlds?: Prisma.WorldUncheckedUpdateManyWithoutFounderNestedInput - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutAuthorNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutAuthorNestedInput - votes?: Prisma.AppVoteUncheckedUpdateManyWithoutVoterNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutReporterNestedInput - moderationReviews?: Prisma.ModerationReportUncheckedUpdateManyWithoutReviewerNestedInput - hiveReferences?: Prisma.HiveReferenceUncheckedUpdateManyWithoutAuthorNestedInput - rewardRecords?: Prisma.RewardRecordUncheckedUpdateManyWithoutUserNestedInput - rewardSummaries?: Prisma.UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput -} - - -/** - * Count Type UserCountOutputType - */ - -export type UserCountOutputType = { - foundedWorlds: number - bibleVersions: number - loreEntries: number - proposals: number - votes: number - moderationReports: number - moderationReviews: number - hiveReferences: number - rewardRecords: number - rewardSummaries: number - reputationSnapshots: number -} - -export type UserCountOutputTypeSelect = { - foundedWorlds?: boolean | UserCountOutputTypeCountFoundedWorldsArgs - bibleVersions?: boolean | UserCountOutputTypeCountBibleVersionsArgs - loreEntries?: boolean | UserCountOutputTypeCountLoreEntriesArgs - proposals?: boolean | UserCountOutputTypeCountProposalsArgs - votes?: boolean | UserCountOutputTypeCountVotesArgs - moderationReports?: boolean | UserCountOutputTypeCountModerationReportsArgs - moderationReviews?: boolean | UserCountOutputTypeCountModerationReviewsArgs - hiveReferences?: boolean | UserCountOutputTypeCountHiveReferencesArgs - rewardRecords?: boolean | UserCountOutputTypeCountRewardRecordsArgs - rewardSummaries?: boolean | UserCountOutputTypeCountRewardSummariesArgs - reputationSnapshots?: boolean | UserCountOutputTypeCountReputationSnapshotsArgs -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeDefaultArgs = { - /** - * Select specific fields to fetch from the UserCountOutputType - */ - select?: Prisma.UserCountOutputTypeSelect | null -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountFoundedWorldsArgs = { - where?: Prisma.WorldWhereInput -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountBibleVersionsArgs = { - where?: Prisma.WorldBibleVersionWhereInput -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountLoreEntriesArgs = { - where?: Prisma.LoreEntryWhereInput -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountProposalsArgs = { - where?: Prisma.ProposalWhereInput -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountVotesArgs = { - where?: Prisma.AppVoteWhereInput -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountModerationReportsArgs = { - where?: Prisma.ModerationReportWhereInput -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountModerationReviewsArgs = { - where?: Prisma.ModerationReportWhereInput -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountHiveReferencesArgs = { - where?: Prisma.HiveReferenceWhereInput -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountRewardRecordsArgs = { - where?: Prisma.RewardRecordWhereInput -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountRewardSummariesArgs = { - where?: Prisma.UserRewardSummaryWhereInput -} - -/** - * UserCountOutputType without action - */ -export type UserCountOutputTypeCountReputationSnapshotsArgs = { - where?: Prisma.UserReputationSnapshotWhereInput -} - - -export type UserSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - hiveUsername?: boolean - normalizedHiveUsername?: boolean - displayName?: boolean - avatarUrl?: boolean - bio?: boolean - createdAt?: boolean - updatedAt?: boolean - foundedWorlds?: boolean | Prisma.User$foundedWorldsArgs - bibleVersions?: boolean | Prisma.User$bibleVersionsArgs - loreEntries?: boolean | Prisma.User$loreEntriesArgs - proposals?: boolean | Prisma.User$proposalsArgs - votes?: boolean | Prisma.User$votesArgs - moderationReports?: boolean | Prisma.User$moderationReportsArgs - moderationReviews?: boolean | Prisma.User$moderationReviewsArgs - hiveReferences?: boolean | Prisma.User$hiveReferencesArgs - rewardRecords?: boolean | Prisma.User$rewardRecordsArgs - rewardSummaries?: boolean | Prisma.User$rewardSummariesArgs - reputationSnapshots?: boolean | Prisma.User$reputationSnapshotsArgs - _count?: boolean | Prisma.UserCountOutputTypeDefaultArgs -}, ExtArgs["result"]["user"]> - -export type UserSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - hiveUsername?: boolean - normalizedHiveUsername?: boolean - displayName?: boolean - avatarUrl?: boolean - bio?: boolean - createdAt?: boolean - updatedAt?: boolean -}, ExtArgs["result"]["user"]> - -export type UserSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - hiveUsername?: boolean - normalizedHiveUsername?: boolean - displayName?: boolean - avatarUrl?: boolean - bio?: boolean - createdAt?: boolean - updatedAt?: boolean -}, ExtArgs["result"]["user"]> - -export type UserSelectScalar = { - id?: boolean - hiveUsername?: boolean - normalizedHiveUsername?: boolean - displayName?: boolean - avatarUrl?: boolean - bio?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type UserOmit = runtime.Types.Extensions.GetOmit<"id" | "hiveUsername" | "normalizedHiveUsername" | "displayName" | "avatarUrl" | "bio" | "createdAt" | "updatedAt", ExtArgs["result"]["user"]> -export type UserInclude = { - foundedWorlds?: boolean | Prisma.User$foundedWorldsArgs - bibleVersions?: boolean | Prisma.User$bibleVersionsArgs - loreEntries?: boolean | Prisma.User$loreEntriesArgs - proposals?: boolean | Prisma.User$proposalsArgs - votes?: boolean | Prisma.User$votesArgs - moderationReports?: boolean | Prisma.User$moderationReportsArgs - moderationReviews?: boolean | Prisma.User$moderationReviewsArgs - hiveReferences?: boolean | Prisma.User$hiveReferencesArgs - rewardRecords?: boolean | Prisma.User$rewardRecordsArgs - rewardSummaries?: boolean | Prisma.User$rewardSummariesArgs - reputationSnapshots?: boolean | Prisma.User$reputationSnapshotsArgs - _count?: boolean | Prisma.UserCountOutputTypeDefaultArgs -} -export type UserIncludeCreateManyAndReturn = {} -export type UserIncludeUpdateManyAndReturn = {} - -export type $UserPayload = { - name: "User" - objects: { - foundedWorlds: Prisma.$WorldPayload[] - bibleVersions: Prisma.$WorldBibleVersionPayload[] - loreEntries: Prisma.$LoreEntryPayload[] - proposals: Prisma.$ProposalPayload[] - votes: Prisma.$AppVotePayload[] - moderationReports: Prisma.$ModerationReportPayload[] - moderationReviews: Prisma.$ModerationReportPayload[] - hiveReferences: Prisma.$HiveReferencePayload[] - rewardRecords: Prisma.$RewardRecordPayload[] - rewardSummaries: Prisma.$UserRewardSummaryPayload[] - reputationSnapshots: Prisma.$UserReputationSnapshotPayload[] - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - hiveUsername: string - normalizedHiveUsername: string - displayName: string | null - avatarUrl: string | null - bio: string | null - 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" - foundedWorlds = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - bibleVersions = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - loreEntries = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - proposals = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - votes = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - moderationReports = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - moderationReviews = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - hiveReferences = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - rewardRecords = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - rewardSummaries = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - reputationSnapshots = {}>(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 hiveUsername: Prisma.FieldRef<"User", 'String'> - readonly normalizedHiveUsername: Prisma.FieldRef<"User", 'String'> - readonly displayName: Prisma.FieldRef<"User", 'String'> - readonly avatarUrl: Prisma.FieldRef<"User", 'String'> - readonly bio: Prisma.FieldRef<"User", 'String'> - 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.foundedWorlds - */ -export type User$foundedWorldsArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - where?: Prisma.WorldWhereInput - orderBy?: Prisma.WorldOrderByWithRelationInput | Prisma.WorldOrderByWithRelationInput[] - cursor?: Prisma.WorldWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.WorldScalarFieldEnum | Prisma.WorldScalarFieldEnum[] -} - -/** - * User.bibleVersions - */ -export type User$bibleVersionsArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - where?: Prisma.WorldBibleVersionWhereInput - orderBy?: Prisma.WorldBibleVersionOrderByWithRelationInput | Prisma.WorldBibleVersionOrderByWithRelationInput[] - cursor?: Prisma.WorldBibleVersionWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.WorldBibleVersionScalarFieldEnum | Prisma.WorldBibleVersionScalarFieldEnum[] -} - -/** - * User.loreEntries - */ -export type User$loreEntriesArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - where?: Prisma.LoreEntryWhereInput - orderBy?: Prisma.LoreEntryOrderByWithRelationInput | Prisma.LoreEntryOrderByWithRelationInput[] - cursor?: Prisma.LoreEntryWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.LoreEntryScalarFieldEnum | Prisma.LoreEntryScalarFieldEnum[] -} - -/** - * User.proposals - */ -export type User$proposalsArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - where?: Prisma.ProposalWhereInput - orderBy?: Prisma.ProposalOrderByWithRelationInput | Prisma.ProposalOrderByWithRelationInput[] - cursor?: Prisma.ProposalWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.ProposalScalarFieldEnum | Prisma.ProposalScalarFieldEnum[] -} - -/** - * User.votes - */ -export type User$votesArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - where?: Prisma.AppVoteWhereInput - orderBy?: Prisma.AppVoteOrderByWithRelationInput | Prisma.AppVoteOrderByWithRelationInput[] - cursor?: Prisma.AppVoteWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.AppVoteScalarFieldEnum | Prisma.AppVoteScalarFieldEnum[] -} - -/** - * User.moderationReports - */ -export type User$moderationReportsArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - where?: Prisma.ModerationReportWhereInput - orderBy?: Prisma.ModerationReportOrderByWithRelationInput | Prisma.ModerationReportOrderByWithRelationInput[] - cursor?: Prisma.ModerationReportWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.ModerationReportScalarFieldEnum | Prisma.ModerationReportScalarFieldEnum[] -} - -/** - * User.moderationReviews - */ -export type User$moderationReviewsArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - where?: Prisma.ModerationReportWhereInput - orderBy?: Prisma.ModerationReportOrderByWithRelationInput | Prisma.ModerationReportOrderByWithRelationInput[] - cursor?: Prisma.ModerationReportWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.ModerationReportScalarFieldEnum | Prisma.ModerationReportScalarFieldEnum[] -} - -/** - * User.hiveReferences - */ -export type User$hiveReferencesArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - where?: Prisma.HiveReferenceWhereInput - orderBy?: Prisma.HiveReferenceOrderByWithRelationInput | Prisma.HiveReferenceOrderByWithRelationInput[] - cursor?: Prisma.HiveReferenceWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.HiveReferenceScalarFieldEnum | Prisma.HiveReferenceScalarFieldEnum[] -} - -/** - * User.rewardRecords - */ -export type User$rewardRecordsArgs = { - /** - * Select specific fields to fetch from the RewardRecord - */ - select?: Prisma.RewardRecordSelect | null - /** - * Omit specific fields from the RewardRecord - */ - omit?: Prisma.RewardRecordOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.RewardRecordInclude | null - where?: Prisma.RewardRecordWhereInput - orderBy?: Prisma.RewardRecordOrderByWithRelationInput | Prisma.RewardRecordOrderByWithRelationInput[] - cursor?: Prisma.RewardRecordWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.RewardRecordScalarFieldEnum | Prisma.RewardRecordScalarFieldEnum[] -} - -/** - * User.rewardSummaries - */ -export type User$rewardSummariesArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null - where?: Prisma.UserRewardSummaryWhereInput - orderBy?: Prisma.UserRewardSummaryOrderByWithRelationInput | Prisma.UserRewardSummaryOrderByWithRelationInput[] - cursor?: Prisma.UserRewardSummaryWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.UserRewardSummaryScalarFieldEnum | Prisma.UserRewardSummaryScalarFieldEnum[] -} - -/** - * User.reputationSnapshots - */ -export type User$reputationSnapshotsArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - where?: Prisma.UserReputationSnapshotWhereInput - orderBy?: Prisma.UserReputationSnapshotOrderByWithRelationInput | Prisma.UserReputationSnapshotOrderByWithRelationInput[] - cursor?: Prisma.UserReputationSnapshotWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.UserReputationSnapshotScalarFieldEnum | Prisma.UserReputationSnapshotScalarFieldEnum[] -} - -/** - * 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/UserReputationSnapshot.ts b/apps/api/src/generated/prisma/models/UserReputationSnapshot.ts deleted file mode 100644 index ee243f4..0000000 --- a/apps/api/src/generated/prisma/models/UserReputationSnapshot.ts +++ /dev/null @@ -1,1600 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `UserReputationSnapshot` 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 UserReputationSnapshot - * - */ -export type UserReputationSnapshotModel = runtime.Types.Result.DefaultSelection - -export type AggregateUserReputationSnapshot = { - _count: UserReputationSnapshotCountAggregateOutputType | null - _avg: UserReputationSnapshotAvgAggregateOutputType | null - _sum: UserReputationSnapshotSumAggregateOutputType | null - _min: UserReputationSnapshotMinAggregateOutputType | null - _max: UserReputationSnapshotMaxAggregateOutputType | null -} - -export type UserReputationSnapshotAvgAggregateOutputType = { - score: runtime.Decimal | null -} - -export type UserReputationSnapshotSumAggregateOutputType = { - score: runtime.Decimal | null -} - -export type UserReputationSnapshotMinAggregateOutputType = { - id: string | null - userId: string | null - score: runtime.Decimal | null - calculationVersion: string | null - calculatedAt: Date | null - createdAt: Date | null -} - -export type UserReputationSnapshotMaxAggregateOutputType = { - id: string | null - userId: string | null - score: runtime.Decimal | null - calculationVersion: string | null - calculatedAt: Date | null - createdAt: Date | null -} - -export type UserReputationSnapshotCountAggregateOutputType = { - id: number - userId: number - score: number - calculationVersion: number - breakdown: number - calculatedAt: number - createdAt: number - _all: number -} - - -export type UserReputationSnapshotAvgAggregateInputType = { - score?: true -} - -export type UserReputationSnapshotSumAggregateInputType = { - score?: true -} - -export type UserReputationSnapshotMinAggregateInputType = { - id?: true - userId?: true - score?: true - calculationVersion?: true - calculatedAt?: true - createdAt?: true -} - -export type UserReputationSnapshotMaxAggregateInputType = { - id?: true - userId?: true - score?: true - calculationVersion?: true - calculatedAt?: true - createdAt?: true -} - -export type UserReputationSnapshotCountAggregateInputType = { - id?: true - userId?: true - score?: true - calculationVersion?: true - breakdown?: true - calculatedAt?: true - createdAt?: true - _all?: true -} - -export type UserReputationSnapshotAggregateArgs = { - /** - * Filter which UserReputationSnapshot to aggregate. - */ - where?: Prisma.UserReputationSnapshotWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of UserReputationSnapshots to fetch. - */ - orderBy?: Prisma.UserReputationSnapshotOrderByWithRelationInput | Prisma.UserReputationSnapshotOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.UserReputationSnapshotWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` UserReputationSnapshots 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` UserReputationSnapshots. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned UserReputationSnapshots - **/ - _count?: true | UserReputationSnapshotCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to average - **/ - _avg?: UserReputationSnapshotAvgAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to sum - **/ - _sum?: UserReputationSnapshotSumAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: UserReputationSnapshotMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: UserReputationSnapshotMaxAggregateInputType -} - -export type GetUserReputationSnapshotAggregateType = { - [P in keyof T & keyof AggregateUserReputationSnapshot]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type UserReputationSnapshotGroupByArgs = { - where?: Prisma.UserReputationSnapshotWhereInput - orderBy?: Prisma.UserReputationSnapshotOrderByWithAggregationInput | Prisma.UserReputationSnapshotOrderByWithAggregationInput[] - by: Prisma.UserReputationSnapshotScalarFieldEnum[] | Prisma.UserReputationSnapshotScalarFieldEnum - having?: Prisma.UserReputationSnapshotScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: UserReputationSnapshotCountAggregateInputType | true - _avg?: UserReputationSnapshotAvgAggregateInputType - _sum?: UserReputationSnapshotSumAggregateInputType - _min?: UserReputationSnapshotMinAggregateInputType - _max?: UserReputationSnapshotMaxAggregateInputType -} - -export type UserReputationSnapshotGroupByOutputType = { - id: string - userId: string - score: runtime.Decimal - calculationVersion: string - breakdown: runtime.JsonValue - calculatedAt: Date - createdAt: Date - _count: UserReputationSnapshotCountAggregateOutputType | null - _avg: UserReputationSnapshotAvgAggregateOutputType | null - _sum: UserReputationSnapshotSumAggregateOutputType | null - _min: UserReputationSnapshotMinAggregateOutputType | null - _max: UserReputationSnapshotMaxAggregateOutputType | null -} - -export type GetUserReputationSnapshotGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof UserReputationSnapshotGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type UserReputationSnapshotWhereInput = { - AND?: Prisma.UserReputationSnapshotWhereInput | Prisma.UserReputationSnapshotWhereInput[] - OR?: Prisma.UserReputationSnapshotWhereInput[] - NOT?: Prisma.UserReputationSnapshotWhereInput | Prisma.UserReputationSnapshotWhereInput[] - id?: Prisma.StringFilter<"UserReputationSnapshot"> | string - userId?: Prisma.StringFilter<"UserReputationSnapshot"> | string - score?: Prisma.DecimalFilter<"UserReputationSnapshot"> | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFilter<"UserReputationSnapshot"> | string - breakdown?: Prisma.JsonFilter<"UserReputationSnapshot"> - calculatedAt?: Prisma.DateTimeFilter<"UserReputationSnapshot"> | Date | string - createdAt?: Prisma.DateTimeFilter<"UserReputationSnapshot"> | Date | string - user?: Prisma.XOR - appVotes?: Prisma.AppVoteListRelationFilter -} - -export type UserReputationSnapshotOrderByWithRelationInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - score?: Prisma.SortOrder - calculationVersion?: Prisma.SortOrder - breakdown?: Prisma.SortOrder - calculatedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - user?: Prisma.UserOrderByWithRelationInput - appVotes?: Prisma.AppVoteOrderByRelationAggregateInput -} - -export type UserReputationSnapshotWhereUniqueInput = Prisma.AtLeast<{ - id?: string - AND?: Prisma.UserReputationSnapshotWhereInput | Prisma.UserReputationSnapshotWhereInput[] - OR?: Prisma.UserReputationSnapshotWhereInput[] - NOT?: Prisma.UserReputationSnapshotWhereInput | Prisma.UserReputationSnapshotWhereInput[] - userId?: Prisma.StringFilter<"UserReputationSnapshot"> | string - score?: Prisma.DecimalFilter<"UserReputationSnapshot"> | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFilter<"UserReputationSnapshot"> | string - breakdown?: Prisma.JsonFilter<"UserReputationSnapshot"> - calculatedAt?: Prisma.DateTimeFilter<"UserReputationSnapshot"> | Date | string - createdAt?: Prisma.DateTimeFilter<"UserReputationSnapshot"> | Date | string - user?: Prisma.XOR - appVotes?: Prisma.AppVoteListRelationFilter -}, "id"> - -export type UserReputationSnapshotOrderByWithAggregationInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - score?: Prisma.SortOrder - calculationVersion?: Prisma.SortOrder - breakdown?: Prisma.SortOrder - calculatedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - _count?: Prisma.UserReputationSnapshotCountOrderByAggregateInput - _avg?: Prisma.UserReputationSnapshotAvgOrderByAggregateInput - _max?: Prisma.UserReputationSnapshotMaxOrderByAggregateInput - _min?: Prisma.UserReputationSnapshotMinOrderByAggregateInput - _sum?: Prisma.UserReputationSnapshotSumOrderByAggregateInput -} - -export type UserReputationSnapshotScalarWhereWithAggregatesInput = { - AND?: Prisma.UserReputationSnapshotScalarWhereWithAggregatesInput | Prisma.UserReputationSnapshotScalarWhereWithAggregatesInput[] - OR?: Prisma.UserReputationSnapshotScalarWhereWithAggregatesInput[] - NOT?: Prisma.UserReputationSnapshotScalarWhereWithAggregatesInput | Prisma.UserReputationSnapshotScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"UserReputationSnapshot"> | string - userId?: Prisma.StringWithAggregatesFilter<"UserReputationSnapshot"> | string - score?: Prisma.DecimalWithAggregatesFilter<"UserReputationSnapshot"> | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringWithAggregatesFilter<"UserReputationSnapshot"> | string - breakdown?: Prisma.JsonWithAggregatesFilter<"UserReputationSnapshot"> - calculatedAt?: Prisma.DateTimeWithAggregatesFilter<"UserReputationSnapshot"> | Date | string - createdAt?: Prisma.DateTimeWithAggregatesFilter<"UserReputationSnapshot"> | Date | string -} - -export type UserReputationSnapshotCreateInput = { - id?: string - score: runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion: string - breakdown: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Date | string - createdAt?: Date | string - user: Prisma.UserCreateNestedOneWithoutReputationSnapshotsInput - appVotes?: Prisma.AppVoteCreateNestedManyWithoutReputationSnapshotInput -} - -export type UserReputationSnapshotUncheckedCreateInput = { - id?: string - userId: string - score: runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion: string - breakdown: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Date | string - createdAt?: Date | string - appVotes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutReputationSnapshotInput -} - -export type UserReputationSnapshotUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - score?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFieldUpdateOperationsInput | string - breakdown?: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - user?: Prisma.UserUpdateOneRequiredWithoutReputationSnapshotsNestedInput - appVotes?: Prisma.AppVoteUpdateManyWithoutReputationSnapshotNestedInput -} - -export type UserReputationSnapshotUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - userId?: Prisma.StringFieldUpdateOperationsInput | string - score?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFieldUpdateOperationsInput | string - breakdown?: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - appVotes?: Prisma.AppVoteUncheckedUpdateManyWithoutReputationSnapshotNestedInput -} - -export type UserReputationSnapshotCreateManyInput = { - id?: string - userId: string - score: runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion: string - breakdown: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Date | string - createdAt?: Date | string -} - -export type UserReputationSnapshotUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - score?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFieldUpdateOperationsInput | string - breakdown?: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type UserReputationSnapshotUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - userId?: Prisma.StringFieldUpdateOperationsInput | string - score?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFieldUpdateOperationsInput | string - breakdown?: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type UserReputationSnapshotListRelationFilter = { - every?: Prisma.UserReputationSnapshotWhereInput - some?: Prisma.UserReputationSnapshotWhereInput - none?: Prisma.UserReputationSnapshotWhereInput -} - -export type UserReputationSnapshotOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type UserReputationSnapshotNullableScalarRelationFilter = { - is?: Prisma.UserReputationSnapshotWhereInput | null - isNot?: Prisma.UserReputationSnapshotWhereInput | null -} - -export type UserReputationSnapshotCountOrderByAggregateInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - score?: Prisma.SortOrder - calculationVersion?: Prisma.SortOrder - breakdown?: Prisma.SortOrder - calculatedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder -} - -export type UserReputationSnapshotAvgOrderByAggregateInput = { - score?: Prisma.SortOrder -} - -export type UserReputationSnapshotMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - score?: Prisma.SortOrder - calculationVersion?: Prisma.SortOrder - calculatedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder -} - -export type UserReputationSnapshotMinOrderByAggregateInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - score?: Prisma.SortOrder - calculationVersion?: Prisma.SortOrder - calculatedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder -} - -export type UserReputationSnapshotSumOrderByAggregateInput = { - score?: Prisma.SortOrder -} - -export type UserReputationSnapshotCreateNestedManyWithoutUserInput = { - create?: Prisma.XOR | Prisma.UserReputationSnapshotCreateWithoutUserInput[] | Prisma.UserReputationSnapshotUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.UserReputationSnapshotCreateOrConnectWithoutUserInput | Prisma.UserReputationSnapshotCreateOrConnectWithoutUserInput[] - createMany?: Prisma.UserReputationSnapshotCreateManyUserInputEnvelope - connect?: Prisma.UserReputationSnapshotWhereUniqueInput | Prisma.UserReputationSnapshotWhereUniqueInput[] -} - -export type UserReputationSnapshotUncheckedCreateNestedManyWithoutUserInput = { - create?: Prisma.XOR | Prisma.UserReputationSnapshotCreateWithoutUserInput[] | Prisma.UserReputationSnapshotUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.UserReputationSnapshotCreateOrConnectWithoutUserInput | Prisma.UserReputationSnapshotCreateOrConnectWithoutUserInput[] - createMany?: Prisma.UserReputationSnapshotCreateManyUserInputEnvelope - connect?: Prisma.UserReputationSnapshotWhereUniqueInput | Prisma.UserReputationSnapshotWhereUniqueInput[] -} - -export type UserReputationSnapshotUpdateManyWithoutUserNestedInput = { - create?: Prisma.XOR | Prisma.UserReputationSnapshotCreateWithoutUserInput[] | Prisma.UserReputationSnapshotUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.UserReputationSnapshotCreateOrConnectWithoutUserInput | Prisma.UserReputationSnapshotCreateOrConnectWithoutUserInput[] - upsert?: Prisma.UserReputationSnapshotUpsertWithWhereUniqueWithoutUserInput | Prisma.UserReputationSnapshotUpsertWithWhereUniqueWithoutUserInput[] - createMany?: Prisma.UserReputationSnapshotCreateManyUserInputEnvelope - set?: Prisma.UserReputationSnapshotWhereUniqueInput | Prisma.UserReputationSnapshotWhereUniqueInput[] - disconnect?: Prisma.UserReputationSnapshotWhereUniqueInput | Prisma.UserReputationSnapshotWhereUniqueInput[] - delete?: Prisma.UserReputationSnapshotWhereUniqueInput | Prisma.UserReputationSnapshotWhereUniqueInput[] - connect?: Prisma.UserReputationSnapshotWhereUniqueInput | Prisma.UserReputationSnapshotWhereUniqueInput[] - update?: Prisma.UserReputationSnapshotUpdateWithWhereUniqueWithoutUserInput | Prisma.UserReputationSnapshotUpdateWithWhereUniqueWithoutUserInput[] - updateMany?: Prisma.UserReputationSnapshotUpdateManyWithWhereWithoutUserInput | Prisma.UserReputationSnapshotUpdateManyWithWhereWithoutUserInput[] - deleteMany?: Prisma.UserReputationSnapshotScalarWhereInput | Prisma.UserReputationSnapshotScalarWhereInput[] -} - -export type UserReputationSnapshotUncheckedUpdateManyWithoutUserNestedInput = { - create?: Prisma.XOR | Prisma.UserReputationSnapshotCreateWithoutUserInput[] | Prisma.UserReputationSnapshotUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.UserReputationSnapshotCreateOrConnectWithoutUserInput | Prisma.UserReputationSnapshotCreateOrConnectWithoutUserInput[] - upsert?: Prisma.UserReputationSnapshotUpsertWithWhereUniqueWithoutUserInput | Prisma.UserReputationSnapshotUpsertWithWhereUniqueWithoutUserInput[] - createMany?: Prisma.UserReputationSnapshotCreateManyUserInputEnvelope - set?: Prisma.UserReputationSnapshotWhereUniqueInput | Prisma.UserReputationSnapshotWhereUniqueInput[] - disconnect?: Prisma.UserReputationSnapshotWhereUniqueInput | Prisma.UserReputationSnapshotWhereUniqueInput[] - delete?: Prisma.UserReputationSnapshotWhereUniqueInput | Prisma.UserReputationSnapshotWhereUniqueInput[] - connect?: Prisma.UserReputationSnapshotWhereUniqueInput | Prisma.UserReputationSnapshotWhereUniqueInput[] - update?: Prisma.UserReputationSnapshotUpdateWithWhereUniqueWithoutUserInput | Prisma.UserReputationSnapshotUpdateWithWhereUniqueWithoutUserInput[] - updateMany?: Prisma.UserReputationSnapshotUpdateManyWithWhereWithoutUserInput | Prisma.UserReputationSnapshotUpdateManyWithWhereWithoutUserInput[] - deleteMany?: Prisma.UserReputationSnapshotScalarWhereInput | Prisma.UserReputationSnapshotScalarWhereInput[] -} - -export type UserReputationSnapshotCreateNestedOneWithoutAppVotesInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserReputationSnapshotCreateOrConnectWithoutAppVotesInput - connect?: Prisma.UserReputationSnapshotWhereUniqueInput -} - -export type UserReputationSnapshotUpdateOneWithoutAppVotesNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.UserReputationSnapshotCreateOrConnectWithoutAppVotesInput - upsert?: Prisma.UserReputationSnapshotUpsertWithoutAppVotesInput - disconnect?: Prisma.UserReputationSnapshotWhereInput | boolean - delete?: Prisma.UserReputationSnapshotWhereInput | boolean - connect?: Prisma.UserReputationSnapshotWhereUniqueInput - update?: Prisma.XOR, Prisma.UserReputationSnapshotUncheckedUpdateWithoutAppVotesInput> -} - -export type UserReputationSnapshotCreateWithoutUserInput = { - id?: string - score: runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion: string - breakdown: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Date | string - createdAt?: Date | string - appVotes?: Prisma.AppVoteCreateNestedManyWithoutReputationSnapshotInput -} - -export type UserReputationSnapshotUncheckedCreateWithoutUserInput = { - id?: string - score: runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion: string - breakdown: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Date | string - createdAt?: Date | string - appVotes?: Prisma.AppVoteUncheckedCreateNestedManyWithoutReputationSnapshotInput -} - -export type UserReputationSnapshotCreateOrConnectWithoutUserInput = { - where: Prisma.UserReputationSnapshotWhereUniqueInput - create: Prisma.XOR -} - -export type UserReputationSnapshotCreateManyUserInputEnvelope = { - data: Prisma.UserReputationSnapshotCreateManyUserInput | Prisma.UserReputationSnapshotCreateManyUserInput[] - skipDuplicates?: boolean -} - -export type UserReputationSnapshotUpsertWithWhereUniqueWithoutUserInput = { - where: Prisma.UserReputationSnapshotWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type UserReputationSnapshotUpdateWithWhereUniqueWithoutUserInput = { - where: Prisma.UserReputationSnapshotWhereUniqueInput - data: Prisma.XOR -} - -export type UserReputationSnapshotUpdateManyWithWhereWithoutUserInput = { - where: Prisma.UserReputationSnapshotScalarWhereInput - data: Prisma.XOR -} - -export type UserReputationSnapshotScalarWhereInput = { - AND?: Prisma.UserReputationSnapshotScalarWhereInput | Prisma.UserReputationSnapshotScalarWhereInput[] - OR?: Prisma.UserReputationSnapshotScalarWhereInput[] - NOT?: Prisma.UserReputationSnapshotScalarWhereInput | Prisma.UserReputationSnapshotScalarWhereInput[] - id?: Prisma.StringFilter<"UserReputationSnapshot"> | string - userId?: Prisma.StringFilter<"UserReputationSnapshot"> | string - score?: Prisma.DecimalFilter<"UserReputationSnapshot"> | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFilter<"UserReputationSnapshot"> | string - breakdown?: Prisma.JsonFilter<"UserReputationSnapshot"> - calculatedAt?: Prisma.DateTimeFilter<"UserReputationSnapshot"> | Date | string - createdAt?: Prisma.DateTimeFilter<"UserReputationSnapshot"> | Date | string -} - -export type UserReputationSnapshotCreateWithoutAppVotesInput = { - id?: string - score: runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion: string - breakdown: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Date | string - createdAt?: Date | string - user: Prisma.UserCreateNestedOneWithoutReputationSnapshotsInput -} - -export type UserReputationSnapshotUncheckedCreateWithoutAppVotesInput = { - id?: string - userId: string - score: runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion: string - breakdown: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Date | string - createdAt?: Date | string -} - -export type UserReputationSnapshotCreateOrConnectWithoutAppVotesInput = { - where: Prisma.UserReputationSnapshotWhereUniqueInput - create: Prisma.XOR -} - -export type UserReputationSnapshotUpsertWithoutAppVotesInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.UserReputationSnapshotWhereInput -} - -export type UserReputationSnapshotUpdateToOneWithWhereWithoutAppVotesInput = { - where?: Prisma.UserReputationSnapshotWhereInput - data: Prisma.XOR -} - -export type UserReputationSnapshotUpdateWithoutAppVotesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - score?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFieldUpdateOperationsInput | string - breakdown?: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - user?: Prisma.UserUpdateOneRequiredWithoutReputationSnapshotsNestedInput -} - -export type UserReputationSnapshotUncheckedUpdateWithoutAppVotesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - userId?: Prisma.StringFieldUpdateOperationsInput | string - score?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFieldUpdateOperationsInput | string - breakdown?: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type UserReputationSnapshotCreateManyUserInput = { - id?: string - score: runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion: string - breakdown: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Date | string - createdAt?: Date | string -} - -export type UserReputationSnapshotUpdateWithoutUserInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - score?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFieldUpdateOperationsInput | string - breakdown?: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - appVotes?: Prisma.AppVoteUpdateManyWithoutReputationSnapshotNestedInput -} - -export type UserReputationSnapshotUncheckedUpdateWithoutUserInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - score?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFieldUpdateOperationsInput | string - breakdown?: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - appVotes?: Prisma.AppVoteUncheckedUpdateManyWithoutReputationSnapshotNestedInput -} - -export type UserReputationSnapshotUncheckedUpdateManyWithoutUserInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - score?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - calculationVersion?: Prisma.StringFieldUpdateOperationsInput | string - breakdown?: Prisma.JsonNullValueInput | runtime.InputJsonValue - calculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - -/** - * Count Type UserReputationSnapshotCountOutputType - */ - -export type UserReputationSnapshotCountOutputType = { - appVotes: number -} - -export type UserReputationSnapshotCountOutputTypeSelect = { - appVotes?: boolean | UserReputationSnapshotCountOutputTypeCountAppVotesArgs -} - -/** - * UserReputationSnapshotCountOutputType without action - */ -export type UserReputationSnapshotCountOutputTypeDefaultArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshotCountOutputType - */ - select?: Prisma.UserReputationSnapshotCountOutputTypeSelect | null -} - -/** - * UserReputationSnapshotCountOutputType without action - */ -export type UserReputationSnapshotCountOutputTypeCountAppVotesArgs = { - where?: Prisma.AppVoteWhereInput -} - - -export type UserReputationSnapshotSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - userId?: boolean - score?: boolean - calculationVersion?: boolean - breakdown?: boolean - calculatedAt?: boolean - createdAt?: boolean - user?: boolean | Prisma.UserDefaultArgs - appVotes?: boolean | Prisma.UserReputationSnapshot$appVotesArgs - _count?: boolean | Prisma.UserReputationSnapshotCountOutputTypeDefaultArgs -}, ExtArgs["result"]["userReputationSnapshot"]> - -export type UserReputationSnapshotSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - userId?: boolean - score?: boolean - calculationVersion?: boolean - breakdown?: boolean - calculatedAt?: boolean - createdAt?: boolean - user?: boolean | Prisma.UserDefaultArgs -}, ExtArgs["result"]["userReputationSnapshot"]> - -export type UserReputationSnapshotSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - userId?: boolean - score?: boolean - calculationVersion?: boolean - breakdown?: boolean - calculatedAt?: boolean - createdAt?: boolean - user?: boolean | Prisma.UserDefaultArgs -}, ExtArgs["result"]["userReputationSnapshot"]> - -export type UserReputationSnapshotSelectScalar = { - id?: boolean - userId?: boolean - score?: boolean - calculationVersion?: boolean - breakdown?: boolean - calculatedAt?: boolean - createdAt?: boolean -} - -export type UserReputationSnapshotOmit = runtime.Types.Extensions.GetOmit<"id" | "userId" | "score" | "calculationVersion" | "breakdown" | "calculatedAt" | "createdAt", ExtArgs["result"]["userReputationSnapshot"]> -export type UserReputationSnapshotInclude = { - user?: boolean | Prisma.UserDefaultArgs - appVotes?: boolean | Prisma.UserReputationSnapshot$appVotesArgs - _count?: boolean | Prisma.UserReputationSnapshotCountOutputTypeDefaultArgs -} -export type UserReputationSnapshotIncludeCreateManyAndReturn = { - user?: boolean | Prisma.UserDefaultArgs -} -export type UserReputationSnapshotIncludeUpdateManyAndReturn = { - user?: boolean | Prisma.UserDefaultArgs -} - -export type $UserReputationSnapshotPayload = { - name: "UserReputationSnapshot" - objects: { - user: Prisma.$UserPayload - appVotes: Prisma.$AppVotePayload[] - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - userId: string - score: runtime.Decimal - calculationVersion: string - breakdown: runtime.JsonValue - calculatedAt: Date - createdAt: Date - }, ExtArgs["result"]["userReputationSnapshot"]> - composites: {} -} - -export type UserReputationSnapshotGetPayload = runtime.Types.Result.GetResult - -export type UserReputationSnapshotCountArgs = - Omit & { - select?: UserReputationSnapshotCountAggregateInputType | true - } - -export interface UserReputationSnapshotDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['UserReputationSnapshot'], meta: { name: 'UserReputationSnapshot' } } - /** - * Find zero or one UserReputationSnapshot that matches the filter. - * @param {UserReputationSnapshotFindUniqueArgs} args - Arguments to find a UserReputationSnapshot - * @example - * // Get one UserReputationSnapshot - * const userReputationSnapshot = await prisma.userReputationSnapshot.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__UserReputationSnapshotClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one UserReputationSnapshot that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {UserReputationSnapshotFindUniqueOrThrowArgs} args - Arguments to find a UserReputationSnapshot - * @example - * // Get one UserReputationSnapshot - * const userReputationSnapshot = await prisma.userReputationSnapshot.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__UserReputationSnapshotClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first UserReputationSnapshot 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 {UserReputationSnapshotFindFirstArgs} args - Arguments to find a UserReputationSnapshot - * @example - * // Get one UserReputationSnapshot - * const userReputationSnapshot = await prisma.userReputationSnapshot.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__UserReputationSnapshotClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first UserReputationSnapshot 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 {UserReputationSnapshotFindFirstOrThrowArgs} args - Arguments to find a UserReputationSnapshot - * @example - * // Get one UserReputationSnapshot - * const userReputationSnapshot = await prisma.userReputationSnapshot.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__UserReputationSnapshotClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more UserReputationSnapshots 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 {UserReputationSnapshotFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all UserReputationSnapshots - * const userReputationSnapshots = await prisma.userReputationSnapshot.findMany() - * - * // Get first 10 UserReputationSnapshots - * const userReputationSnapshots = await prisma.userReputationSnapshot.findMany({ take: 10 }) - * - * // Only select the `id` - * const userReputationSnapshotWithIdOnly = await prisma.userReputationSnapshot.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a UserReputationSnapshot. - * @param {UserReputationSnapshotCreateArgs} args - Arguments to create a UserReputationSnapshot. - * @example - * // Create one UserReputationSnapshot - * const UserReputationSnapshot = await prisma.userReputationSnapshot.create({ - * data: { - * // ... data to create a UserReputationSnapshot - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__UserReputationSnapshotClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many UserReputationSnapshots. - * @param {UserReputationSnapshotCreateManyArgs} args - Arguments to create many UserReputationSnapshots. - * @example - * // Create many UserReputationSnapshots - * const userReputationSnapshot = await prisma.userReputationSnapshot.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many UserReputationSnapshots and returns the data saved in the database. - * @param {UserReputationSnapshotCreateManyAndReturnArgs} args - Arguments to create many UserReputationSnapshots. - * @example - * // Create many UserReputationSnapshots - * const userReputationSnapshot = await prisma.userReputationSnapshot.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many UserReputationSnapshots and only return the `id` - * const userReputationSnapshotWithIdOnly = await prisma.userReputationSnapshot.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 UserReputationSnapshot. - * @param {UserReputationSnapshotDeleteArgs} args - Arguments to delete one UserReputationSnapshot. - * @example - * // Delete one UserReputationSnapshot - * const UserReputationSnapshot = await prisma.userReputationSnapshot.delete({ - * where: { - * // ... filter to delete one UserReputationSnapshot - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__UserReputationSnapshotClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one UserReputationSnapshot. - * @param {UserReputationSnapshotUpdateArgs} args - Arguments to update one UserReputationSnapshot. - * @example - * // Update one UserReputationSnapshot - * const userReputationSnapshot = await prisma.userReputationSnapshot.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__UserReputationSnapshotClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more UserReputationSnapshots. - * @param {UserReputationSnapshotDeleteManyArgs} args - Arguments to filter UserReputationSnapshots to delete. - * @example - * // Delete a few UserReputationSnapshots - * const { count } = await prisma.userReputationSnapshot.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more UserReputationSnapshots. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {UserReputationSnapshotUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many UserReputationSnapshots - * const userReputationSnapshot = await prisma.userReputationSnapshot.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more UserReputationSnapshots and returns the data updated in the database. - * @param {UserReputationSnapshotUpdateManyAndReturnArgs} args - Arguments to update many UserReputationSnapshots. - * @example - * // Update many UserReputationSnapshots - * const userReputationSnapshot = await prisma.userReputationSnapshot.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more UserReputationSnapshots and only return the `id` - * const userReputationSnapshotWithIdOnly = await prisma.userReputationSnapshot.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 UserReputationSnapshot. - * @param {UserReputationSnapshotUpsertArgs} args - Arguments to update or create a UserReputationSnapshot. - * @example - * // Update or create a UserReputationSnapshot - * const userReputationSnapshot = await prisma.userReputationSnapshot.upsert({ - * create: { - * // ... data to create a UserReputationSnapshot - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the UserReputationSnapshot we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__UserReputationSnapshotClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of UserReputationSnapshots. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {UserReputationSnapshotCountArgs} args - Arguments to filter UserReputationSnapshots to count. - * @example - * // Count the number of UserReputationSnapshots - * const count = await prisma.userReputationSnapshot.count({ - * where: { - * // ... the filter for the UserReputationSnapshots 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 UserReputationSnapshot. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {UserReputationSnapshotAggregateArgs} 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 UserReputationSnapshot. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {UserReputationSnapshotGroupByArgs} 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 UserReputationSnapshotGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: UserReputationSnapshotGroupByArgs['orderBy'] } - : { orderBy?: UserReputationSnapshotGroupByArgs['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 ? GetUserReputationSnapshotGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the UserReputationSnapshot model - */ -readonly fields: UserReputationSnapshotFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for UserReputationSnapshot. - * 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__UserReputationSnapshotClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - user = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - appVotes = {}>(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 UserReputationSnapshot model - */ -export interface UserReputationSnapshotFieldRefs { - readonly id: Prisma.FieldRef<"UserReputationSnapshot", 'String'> - readonly userId: Prisma.FieldRef<"UserReputationSnapshot", 'String'> - readonly score: Prisma.FieldRef<"UserReputationSnapshot", 'Decimal'> - readonly calculationVersion: Prisma.FieldRef<"UserReputationSnapshot", 'String'> - readonly breakdown: Prisma.FieldRef<"UserReputationSnapshot", 'Json'> - readonly calculatedAt: Prisma.FieldRef<"UserReputationSnapshot", 'DateTime'> - readonly createdAt: Prisma.FieldRef<"UserReputationSnapshot", 'DateTime'> -} - - -// Custom InputTypes -/** - * UserReputationSnapshot findUnique - */ -export type UserReputationSnapshotFindUniqueArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - /** - * Filter, which UserReputationSnapshot to fetch. - */ - where: Prisma.UserReputationSnapshotWhereUniqueInput -} - -/** - * UserReputationSnapshot findUniqueOrThrow - */ -export type UserReputationSnapshotFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - /** - * Filter, which UserReputationSnapshot to fetch. - */ - where: Prisma.UserReputationSnapshotWhereUniqueInput -} - -/** - * UserReputationSnapshot findFirst - */ -export type UserReputationSnapshotFindFirstArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - /** - * Filter, which UserReputationSnapshot to fetch. - */ - where?: Prisma.UserReputationSnapshotWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of UserReputationSnapshots to fetch. - */ - orderBy?: Prisma.UserReputationSnapshotOrderByWithRelationInput | Prisma.UserReputationSnapshotOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for UserReputationSnapshots. - */ - cursor?: Prisma.UserReputationSnapshotWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` UserReputationSnapshots 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` UserReputationSnapshots. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of UserReputationSnapshots. - */ - distinct?: Prisma.UserReputationSnapshotScalarFieldEnum | Prisma.UserReputationSnapshotScalarFieldEnum[] -} - -/** - * UserReputationSnapshot findFirstOrThrow - */ -export type UserReputationSnapshotFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - /** - * Filter, which UserReputationSnapshot to fetch. - */ - where?: Prisma.UserReputationSnapshotWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of UserReputationSnapshots to fetch. - */ - orderBy?: Prisma.UserReputationSnapshotOrderByWithRelationInput | Prisma.UserReputationSnapshotOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for UserReputationSnapshots. - */ - cursor?: Prisma.UserReputationSnapshotWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` UserReputationSnapshots 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` UserReputationSnapshots. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of UserReputationSnapshots. - */ - distinct?: Prisma.UserReputationSnapshotScalarFieldEnum | Prisma.UserReputationSnapshotScalarFieldEnum[] -} - -/** - * UserReputationSnapshot findMany - */ -export type UserReputationSnapshotFindManyArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - /** - * Filter, which UserReputationSnapshots to fetch. - */ - where?: Prisma.UserReputationSnapshotWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of UserReputationSnapshots to fetch. - */ - orderBy?: Prisma.UserReputationSnapshotOrderByWithRelationInput | Prisma.UserReputationSnapshotOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing UserReputationSnapshots. - */ - cursor?: Prisma.UserReputationSnapshotWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` UserReputationSnapshots 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` UserReputationSnapshots. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of UserReputationSnapshots. - */ - distinct?: Prisma.UserReputationSnapshotScalarFieldEnum | Prisma.UserReputationSnapshotScalarFieldEnum[] -} - -/** - * UserReputationSnapshot create - */ -export type UserReputationSnapshotCreateArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - /** - * The data needed to create a UserReputationSnapshot. - */ - data: Prisma.XOR -} - -/** - * UserReputationSnapshot createMany - */ -export type UserReputationSnapshotCreateManyArgs = { - /** - * The data used to create many UserReputationSnapshots. - */ - data: Prisma.UserReputationSnapshotCreateManyInput | Prisma.UserReputationSnapshotCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * UserReputationSnapshot createManyAndReturn - */ -export type UserReputationSnapshotCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelectCreateManyAndReturn | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * The data used to create many UserReputationSnapshots. - */ - data: Prisma.UserReputationSnapshotCreateManyInput | Prisma.UserReputationSnapshotCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotIncludeCreateManyAndReturn | null -} - -/** - * UserReputationSnapshot update - */ -export type UserReputationSnapshotUpdateArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - /** - * The data needed to update a UserReputationSnapshot. - */ - data: Prisma.XOR - /** - * Choose, which UserReputationSnapshot to update. - */ - where: Prisma.UserReputationSnapshotWhereUniqueInput -} - -/** - * UserReputationSnapshot updateMany - */ -export type UserReputationSnapshotUpdateManyArgs = { - /** - * The data used to update UserReputationSnapshots. - */ - data: Prisma.XOR - /** - * Filter which UserReputationSnapshots to update - */ - where?: Prisma.UserReputationSnapshotWhereInput - /** - * Limit how many UserReputationSnapshots to update. - */ - limit?: number -} - -/** - * UserReputationSnapshot updateManyAndReturn - */ -export type UserReputationSnapshotUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * The data used to update UserReputationSnapshots. - */ - data: Prisma.XOR - /** - * Filter which UserReputationSnapshots to update - */ - where?: Prisma.UserReputationSnapshotWhereInput - /** - * Limit how many UserReputationSnapshots to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotIncludeUpdateManyAndReturn | null -} - -/** - * UserReputationSnapshot upsert - */ -export type UserReputationSnapshotUpsertArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - /** - * The filter to search for the UserReputationSnapshot to update in case it exists. - */ - where: Prisma.UserReputationSnapshotWhereUniqueInput - /** - * In case the UserReputationSnapshot found by the `where` argument doesn't exist, create a new UserReputationSnapshot with this data. - */ - create: Prisma.XOR - /** - * In case the UserReputationSnapshot was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * UserReputationSnapshot delete - */ -export type UserReputationSnapshotDeleteArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null - /** - * Filter which UserReputationSnapshot to delete. - */ - where: Prisma.UserReputationSnapshotWhereUniqueInput -} - -/** - * UserReputationSnapshot deleteMany - */ -export type UserReputationSnapshotDeleteManyArgs = { - /** - * Filter which UserReputationSnapshots to delete - */ - where?: Prisma.UserReputationSnapshotWhereInput - /** - * Limit how many UserReputationSnapshots to delete. - */ - limit?: number -} - -/** - * UserReputationSnapshot.appVotes - */ -export type UserReputationSnapshot$appVotesArgs = { - /** - * Select specific fields to fetch from the AppVote - */ - select?: Prisma.AppVoteSelect | null - /** - * Omit specific fields from the AppVote - */ - omit?: Prisma.AppVoteOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.AppVoteInclude | null - where?: Prisma.AppVoteWhereInput - orderBy?: Prisma.AppVoteOrderByWithRelationInput | Prisma.AppVoteOrderByWithRelationInput[] - cursor?: Prisma.AppVoteWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.AppVoteScalarFieldEnum | Prisma.AppVoteScalarFieldEnum[] -} - -/** - * UserReputationSnapshot without action - */ -export type UserReputationSnapshotDefaultArgs = { - /** - * Select specific fields to fetch from the UserReputationSnapshot - */ - select?: Prisma.UserReputationSnapshotSelect | null - /** - * Omit specific fields from the UserReputationSnapshot - */ - omit?: Prisma.UserReputationSnapshotOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserReputationSnapshotInclude | null -} diff --git a/apps/api/src/generated/prisma/models/UserRewardSummary.ts b/apps/api/src/generated/prisma/models/UserRewardSummary.ts deleted file mode 100644 index aa6a231..0000000 --- a/apps/api/src/generated/prisma/models/UserRewardSummary.ts +++ /dev/null @@ -1,1465 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `UserRewardSummary` 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 UserRewardSummary - * - */ -export type UserRewardSummaryModel = runtime.Types.Result.DefaultSelection - -export type AggregateUserRewardSummary = { - _count: UserRewardSummaryCountAggregateOutputType | null - _avg: UserRewardSummaryAvgAggregateOutputType | null - _sum: UserRewardSummarySumAggregateOutputType | null - _min: UserRewardSummaryMinAggregateOutputType | null - _max: UserRewardSummaryMaxAggregateOutputType | null -} - -export type UserRewardSummaryAvgAggregateOutputType = { - totalAmount: runtime.Decimal | null -} - -export type UserRewardSummarySumAggregateOutputType = { - totalAmount: runtime.Decimal | null -} - -export type UserRewardSummaryMinAggregateOutputType = { - id: string | null - userId: string | null - assetSymbol: string | null - totalAmount: runtime.Decimal | null - lastCalculatedAt: Date | null - createdAt: Date | null - updatedAt: Date | null -} - -export type UserRewardSummaryMaxAggregateOutputType = { - id: string | null - userId: string | null - assetSymbol: string | null - totalAmount: runtime.Decimal | null - lastCalculatedAt: Date | null - createdAt: Date | null - updatedAt: Date | null -} - -export type UserRewardSummaryCountAggregateOutputType = { - id: number - userId: number - assetSymbol: number - totalAmount: number - lastCalculatedAt: number - createdAt: number - updatedAt: number - _all: number -} - - -export type UserRewardSummaryAvgAggregateInputType = { - totalAmount?: true -} - -export type UserRewardSummarySumAggregateInputType = { - totalAmount?: true -} - -export type UserRewardSummaryMinAggregateInputType = { - id?: true - userId?: true - assetSymbol?: true - totalAmount?: true - lastCalculatedAt?: true - createdAt?: true - updatedAt?: true -} - -export type UserRewardSummaryMaxAggregateInputType = { - id?: true - userId?: true - assetSymbol?: true - totalAmount?: true - lastCalculatedAt?: true - createdAt?: true - updatedAt?: true -} - -export type UserRewardSummaryCountAggregateInputType = { - id?: true - userId?: true - assetSymbol?: true - totalAmount?: true - lastCalculatedAt?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type UserRewardSummaryAggregateArgs = { - /** - * Filter which UserRewardSummary to aggregate. - */ - where?: Prisma.UserRewardSummaryWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of UserRewardSummaries to fetch. - */ - orderBy?: Prisma.UserRewardSummaryOrderByWithRelationInput | Prisma.UserRewardSummaryOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.UserRewardSummaryWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` UserRewardSummaries 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` UserRewardSummaries. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned UserRewardSummaries - **/ - _count?: true | UserRewardSummaryCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to average - **/ - _avg?: UserRewardSummaryAvgAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to sum - **/ - _sum?: UserRewardSummarySumAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: UserRewardSummaryMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: UserRewardSummaryMaxAggregateInputType -} - -export type GetUserRewardSummaryAggregateType = { - [P in keyof T & keyof AggregateUserRewardSummary]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type UserRewardSummaryGroupByArgs = { - where?: Prisma.UserRewardSummaryWhereInput - orderBy?: Prisma.UserRewardSummaryOrderByWithAggregationInput | Prisma.UserRewardSummaryOrderByWithAggregationInput[] - by: Prisma.UserRewardSummaryScalarFieldEnum[] | Prisma.UserRewardSummaryScalarFieldEnum - having?: Prisma.UserRewardSummaryScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: UserRewardSummaryCountAggregateInputType | true - _avg?: UserRewardSummaryAvgAggregateInputType - _sum?: UserRewardSummarySumAggregateInputType - _min?: UserRewardSummaryMinAggregateInputType - _max?: UserRewardSummaryMaxAggregateInputType -} - -export type UserRewardSummaryGroupByOutputType = { - id: string - userId: string - assetSymbol: string - totalAmount: runtime.Decimal - lastCalculatedAt: Date - createdAt: Date - updatedAt: Date - _count: UserRewardSummaryCountAggregateOutputType | null - _avg: UserRewardSummaryAvgAggregateOutputType | null - _sum: UserRewardSummarySumAggregateOutputType | null - _min: UserRewardSummaryMinAggregateOutputType | null - _max: UserRewardSummaryMaxAggregateOutputType | null -} - -export type GetUserRewardSummaryGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof UserRewardSummaryGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type UserRewardSummaryWhereInput = { - AND?: Prisma.UserRewardSummaryWhereInput | Prisma.UserRewardSummaryWhereInput[] - OR?: Prisma.UserRewardSummaryWhereInput[] - NOT?: Prisma.UserRewardSummaryWhereInput | Prisma.UserRewardSummaryWhereInput[] - id?: Prisma.StringFilter<"UserRewardSummary"> | string - userId?: Prisma.StringFilter<"UserRewardSummary"> | string - assetSymbol?: Prisma.StringFilter<"UserRewardSummary"> | string - totalAmount?: Prisma.DecimalFilter<"UserRewardSummary"> | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeFilter<"UserRewardSummary"> | Date | string - createdAt?: Prisma.DateTimeFilter<"UserRewardSummary"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"UserRewardSummary"> | Date | string - user?: Prisma.XOR -} - -export type UserRewardSummaryOrderByWithRelationInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - assetSymbol?: Prisma.SortOrder - totalAmount?: Prisma.SortOrder - lastCalculatedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - user?: Prisma.UserOrderByWithRelationInput -} - -export type UserRewardSummaryWhereUniqueInput = Prisma.AtLeast<{ - id?: string - userId_assetSymbol?: Prisma.UserRewardSummaryUserIdAssetSymbolCompoundUniqueInput - AND?: Prisma.UserRewardSummaryWhereInput | Prisma.UserRewardSummaryWhereInput[] - OR?: Prisma.UserRewardSummaryWhereInput[] - NOT?: Prisma.UserRewardSummaryWhereInput | Prisma.UserRewardSummaryWhereInput[] - userId?: Prisma.StringFilter<"UserRewardSummary"> | string - assetSymbol?: Prisma.StringFilter<"UserRewardSummary"> | string - totalAmount?: Prisma.DecimalFilter<"UserRewardSummary"> | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeFilter<"UserRewardSummary"> | Date | string - createdAt?: Prisma.DateTimeFilter<"UserRewardSummary"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"UserRewardSummary"> | Date | string - user?: Prisma.XOR -}, "id" | "userId_assetSymbol"> - -export type UserRewardSummaryOrderByWithAggregationInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - assetSymbol?: Prisma.SortOrder - totalAmount?: Prisma.SortOrder - lastCalculatedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.UserRewardSummaryCountOrderByAggregateInput - _avg?: Prisma.UserRewardSummaryAvgOrderByAggregateInput - _max?: Prisma.UserRewardSummaryMaxOrderByAggregateInput - _min?: Prisma.UserRewardSummaryMinOrderByAggregateInput - _sum?: Prisma.UserRewardSummarySumOrderByAggregateInput -} - -export type UserRewardSummaryScalarWhereWithAggregatesInput = { - AND?: Prisma.UserRewardSummaryScalarWhereWithAggregatesInput | Prisma.UserRewardSummaryScalarWhereWithAggregatesInput[] - OR?: Prisma.UserRewardSummaryScalarWhereWithAggregatesInput[] - NOT?: Prisma.UserRewardSummaryScalarWhereWithAggregatesInput | Prisma.UserRewardSummaryScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"UserRewardSummary"> | string - userId?: Prisma.StringWithAggregatesFilter<"UserRewardSummary"> | string - assetSymbol?: Prisma.StringWithAggregatesFilter<"UserRewardSummary"> | string - totalAmount?: Prisma.DecimalWithAggregatesFilter<"UserRewardSummary"> | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeWithAggregatesFilter<"UserRewardSummary"> | Date | string - createdAt?: Prisma.DateTimeWithAggregatesFilter<"UserRewardSummary"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"UserRewardSummary"> | Date | string -} - -export type UserRewardSummaryCreateInput = { - id?: string - assetSymbol: string - totalAmount: runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string - user: Prisma.UserCreateNestedOneWithoutRewardSummariesInput -} - -export type UserRewardSummaryUncheckedCreateInput = { - id?: string - userId: string - assetSymbol: string - totalAmount: runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type UserRewardSummaryUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - totalAmount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - user?: Prisma.UserUpdateOneRequiredWithoutRewardSummariesNestedInput -} - -export type UserRewardSummaryUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - userId?: Prisma.StringFieldUpdateOperationsInput | string - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - totalAmount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type UserRewardSummaryCreateManyInput = { - id?: string - userId: string - assetSymbol: string - totalAmount: runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type UserRewardSummaryUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - totalAmount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type UserRewardSummaryUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - userId?: Prisma.StringFieldUpdateOperationsInput | string - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - totalAmount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type UserRewardSummaryListRelationFilter = { - every?: Prisma.UserRewardSummaryWhereInput - some?: Prisma.UserRewardSummaryWhereInput - none?: Prisma.UserRewardSummaryWhereInput -} - -export type UserRewardSummaryOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type UserRewardSummaryUserIdAssetSymbolCompoundUniqueInput = { - userId: string - assetSymbol: string -} - -export type UserRewardSummaryCountOrderByAggregateInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - assetSymbol?: Prisma.SortOrder - totalAmount?: Prisma.SortOrder - lastCalculatedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type UserRewardSummaryAvgOrderByAggregateInput = { - totalAmount?: Prisma.SortOrder -} - -export type UserRewardSummaryMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - assetSymbol?: Prisma.SortOrder - totalAmount?: Prisma.SortOrder - lastCalculatedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type UserRewardSummaryMinOrderByAggregateInput = { - id?: Prisma.SortOrder - userId?: Prisma.SortOrder - assetSymbol?: Prisma.SortOrder - totalAmount?: Prisma.SortOrder - lastCalculatedAt?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type UserRewardSummarySumOrderByAggregateInput = { - totalAmount?: Prisma.SortOrder -} - -export type UserRewardSummaryCreateNestedManyWithoutUserInput = { - create?: Prisma.XOR | Prisma.UserRewardSummaryCreateWithoutUserInput[] | Prisma.UserRewardSummaryUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.UserRewardSummaryCreateOrConnectWithoutUserInput | Prisma.UserRewardSummaryCreateOrConnectWithoutUserInput[] - createMany?: Prisma.UserRewardSummaryCreateManyUserInputEnvelope - connect?: Prisma.UserRewardSummaryWhereUniqueInput | Prisma.UserRewardSummaryWhereUniqueInput[] -} - -export type UserRewardSummaryUncheckedCreateNestedManyWithoutUserInput = { - create?: Prisma.XOR | Prisma.UserRewardSummaryCreateWithoutUserInput[] | Prisma.UserRewardSummaryUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.UserRewardSummaryCreateOrConnectWithoutUserInput | Prisma.UserRewardSummaryCreateOrConnectWithoutUserInput[] - createMany?: Prisma.UserRewardSummaryCreateManyUserInputEnvelope - connect?: Prisma.UserRewardSummaryWhereUniqueInput | Prisma.UserRewardSummaryWhereUniqueInput[] -} - -export type UserRewardSummaryUpdateManyWithoutUserNestedInput = { - create?: Prisma.XOR | Prisma.UserRewardSummaryCreateWithoutUserInput[] | Prisma.UserRewardSummaryUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.UserRewardSummaryCreateOrConnectWithoutUserInput | Prisma.UserRewardSummaryCreateOrConnectWithoutUserInput[] - upsert?: Prisma.UserRewardSummaryUpsertWithWhereUniqueWithoutUserInput | Prisma.UserRewardSummaryUpsertWithWhereUniqueWithoutUserInput[] - createMany?: Prisma.UserRewardSummaryCreateManyUserInputEnvelope - set?: Prisma.UserRewardSummaryWhereUniqueInput | Prisma.UserRewardSummaryWhereUniqueInput[] - disconnect?: Prisma.UserRewardSummaryWhereUniqueInput | Prisma.UserRewardSummaryWhereUniqueInput[] - delete?: Prisma.UserRewardSummaryWhereUniqueInput | Prisma.UserRewardSummaryWhereUniqueInput[] - connect?: Prisma.UserRewardSummaryWhereUniqueInput | Prisma.UserRewardSummaryWhereUniqueInput[] - update?: Prisma.UserRewardSummaryUpdateWithWhereUniqueWithoutUserInput | Prisma.UserRewardSummaryUpdateWithWhereUniqueWithoutUserInput[] - updateMany?: Prisma.UserRewardSummaryUpdateManyWithWhereWithoutUserInput | Prisma.UserRewardSummaryUpdateManyWithWhereWithoutUserInput[] - deleteMany?: Prisma.UserRewardSummaryScalarWhereInput | Prisma.UserRewardSummaryScalarWhereInput[] -} - -export type UserRewardSummaryUncheckedUpdateManyWithoutUserNestedInput = { - create?: Prisma.XOR | Prisma.UserRewardSummaryCreateWithoutUserInput[] | Prisma.UserRewardSummaryUncheckedCreateWithoutUserInput[] - connectOrCreate?: Prisma.UserRewardSummaryCreateOrConnectWithoutUserInput | Prisma.UserRewardSummaryCreateOrConnectWithoutUserInput[] - upsert?: Prisma.UserRewardSummaryUpsertWithWhereUniqueWithoutUserInput | Prisma.UserRewardSummaryUpsertWithWhereUniqueWithoutUserInput[] - createMany?: Prisma.UserRewardSummaryCreateManyUserInputEnvelope - set?: Prisma.UserRewardSummaryWhereUniqueInput | Prisma.UserRewardSummaryWhereUniqueInput[] - disconnect?: Prisma.UserRewardSummaryWhereUniqueInput | Prisma.UserRewardSummaryWhereUniqueInput[] - delete?: Prisma.UserRewardSummaryWhereUniqueInput | Prisma.UserRewardSummaryWhereUniqueInput[] - connect?: Prisma.UserRewardSummaryWhereUniqueInput | Prisma.UserRewardSummaryWhereUniqueInput[] - update?: Prisma.UserRewardSummaryUpdateWithWhereUniqueWithoutUserInput | Prisma.UserRewardSummaryUpdateWithWhereUniqueWithoutUserInput[] - updateMany?: Prisma.UserRewardSummaryUpdateManyWithWhereWithoutUserInput | Prisma.UserRewardSummaryUpdateManyWithWhereWithoutUserInput[] - deleteMany?: Prisma.UserRewardSummaryScalarWhereInput | Prisma.UserRewardSummaryScalarWhereInput[] -} - -export type UserRewardSummaryCreateWithoutUserInput = { - id?: string - assetSymbol: string - totalAmount: runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type UserRewardSummaryUncheckedCreateWithoutUserInput = { - id?: string - assetSymbol: string - totalAmount: runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type UserRewardSummaryCreateOrConnectWithoutUserInput = { - where: Prisma.UserRewardSummaryWhereUniqueInput - create: Prisma.XOR -} - -export type UserRewardSummaryCreateManyUserInputEnvelope = { - data: Prisma.UserRewardSummaryCreateManyUserInput | Prisma.UserRewardSummaryCreateManyUserInput[] - skipDuplicates?: boolean -} - -export type UserRewardSummaryUpsertWithWhereUniqueWithoutUserInput = { - where: Prisma.UserRewardSummaryWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type UserRewardSummaryUpdateWithWhereUniqueWithoutUserInput = { - where: Prisma.UserRewardSummaryWhereUniqueInput - data: Prisma.XOR -} - -export type UserRewardSummaryUpdateManyWithWhereWithoutUserInput = { - where: Prisma.UserRewardSummaryScalarWhereInput - data: Prisma.XOR -} - -export type UserRewardSummaryScalarWhereInput = { - AND?: Prisma.UserRewardSummaryScalarWhereInput | Prisma.UserRewardSummaryScalarWhereInput[] - OR?: Prisma.UserRewardSummaryScalarWhereInput[] - NOT?: Prisma.UserRewardSummaryScalarWhereInput | Prisma.UserRewardSummaryScalarWhereInput[] - id?: Prisma.StringFilter<"UserRewardSummary"> | string - userId?: Prisma.StringFilter<"UserRewardSummary"> | string - assetSymbol?: Prisma.StringFilter<"UserRewardSummary"> | string - totalAmount?: Prisma.DecimalFilter<"UserRewardSummary"> | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeFilter<"UserRewardSummary"> | Date | string - createdAt?: Prisma.DateTimeFilter<"UserRewardSummary"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"UserRewardSummary"> | Date | string -} - -export type UserRewardSummaryCreateManyUserInput = { - id?: string - assetSymbol: string - totalAmount: runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Date | string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type UserRewardSummaryUpdateWithoutUserInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - totalAmount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type UserRewardSummaryUncheckedUpdateWithoutUserInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - totalAmount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type UserRewardSummaryUncheckedUpdateManyWithoutUserInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - assetSymbol?: Prisma.StringFieldUpdateOperationsInput | string - totalAmount?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string - lastCalculatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - - -export type UserRewardSummarySelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - userId?: boolean - assetSymbol?: boolean - totalAmount?: boolean - lastCalculatedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - user?: boolean | Prisma.UserDefaultArgs -}, ExtArgs["result"]["userRewardSummary"]> - -export type UserRewardSummarySelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - userId?: boolean - assetSymbol?: boolean - totalAmount?: boolean - lastCalculatedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - user?: boolean | Prisma.UserDefaultArgs -}, ExtArgs["result"]["userRewardSummary"]> - -export type UserRewardSummarySelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - userId?: boolean - assetSymbol?: boolean - totalAmount?: boolean - lastCalculatedAt?: boolean - createdAt?: boolean - updatedAt?: boolean - user?: boolean | Prisma.UserDefaultArgs -}, ExtArgs["result"]["userRewardSummary"]> - -export type UserRewardSummarySelectScalar = { - id?: boolean - userId?: boolean - assetSymbol?: boolean - totalAmount?: boolean - lastCalculatedAt?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type UserRewardSummaryOmit = runtime.Types.Extensions.GetOmit<"id" | "userId" | "assetSymbol" | "totalAmount" | "lastCalculatedAt" | "createdAt" | "updatedAt", ExtArgs["result"]["userRewardSummary"]> -export type UserRewardSummaryInclude = { - user?: boolean | Prisma.UserDefaultArgs -} -export type UserRewardSummaryIncludeCreateManyAndReturn = { - user?: boolean | Prisma.UserDefaultArgs -} -export type UserRewardSummaryIncludeUpdateManyAndReturn = { - user?: boolean | Prisma.UserDefaultArgs -} - -export type $UserRewardSummaryPayload = { - name: "UserRewardSummary" - objects: { - user: Prisma.$UserPayload - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - userId: string - assetSymbol: string - totalAmount: runtime.Decimal - lastCalculatedAt: Date - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["userRewardSummary"]> - composites: {} -} - -export type UserRewardSummaryGetPayload = runtime.Types.Result.GetResult - -export type UserRewardSummaryCountArgs = - Omit & { - select?: UserRewardSummaryCountAggregateInputType | true - } - -export interface UserRewardSummaryDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['UserRewardSummary'], meta: { name: 'UserRewardSummary' } } - /** - * Find zero or one UserRewardSummary that matches the filter. - * @param {UserRewardSummaryFindUniqueArgs} args - Arguments to find a UserRewardSummary - * @example - * // Get one UserRewardSummary - * const userRewardSummary = await prisma.userRewardSummary.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__UserRewardSummaryClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one UserRewardSummary that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {UserRewardSummaryFindUniqueOrThrowArgs} args - Arguments to find a UserRewardSummary - * @example - * // Get one UserRewardSummary - * const userRewardSummary = await prisma.userRewardSummary.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__UserRewardSummaryClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first UserRewardSummary 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 {UserRewardSummaryFindFirstArgs} args - Arguments to find a UserRewardSummary - * @example - * // Get one UserRewardSummary - * const userRewardSummary = await prisma.userRewardSummary.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__UserRewardSummaryClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first UserRewardSummary 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 {UserRewardSummaryFindFirstOrThrowArgs} args - Arguments to find a UserRewardSummary - * @example - * // Get one UserRewardSummary - * const userRewardSummary = await prisma.userRewardSummary.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__UserRewardSummaryClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more UserRewardSummaries 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 {UserRewardSummaryFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all UserRewardSummaries - * const userRewardSummaries = await prisma.userRewardSummary.findMany() - * - * // Get first 10 UserRewardSummaries - * const userRewardSummaries = await prisma.userRewardSummary.findMany({ take: 10 }) - * - * // Only select the `id` - * const userRewardSummaryWithIdOnly = await prisma.userRewardSummary.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a UserRewardSummary. - * @param {UserRewardSummaryCreateArgs} args - Arguments to create a UserRewardSummary. - * @example - * // Create one UserRewardSummary - * const UserRewardSummary = await prisma.userRewardSummary.create({ - * data: { - * // ... data to create a UserRewardSummary - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__UserRewardSummaryClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many UserRewardSummaries. - * @param {UserRewardSummaryCreateManyArgs} args - Arguments to create many UserRewardSummaries. - * @example - * // Create many UserRewardSummaries - * const userRewardSummary = await prisma.userRewardSummary.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many UserRewardSummaries and returns the data saved in the database. - * @param {UserRewardSummaryCreateManyAndReturnArgs} args - Arguments to create many UserRewardSummaries. - * @example - * // Create many UserRewardSummaries - * const userRewardSummary = await prisma.userRewardSummary.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many UserRewardSummaries and only return the `id` - * const userRewardSummaryWithIdOnly = await prisma.userRewardSummary.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 UserRewardSummary. - * @param {UserRewardSummaryDeleteArgs} args - Arguments to delete one UserRewardSummary. - * @example - * // Delete one UserRewardSummary - * const UserRewardSummary = await prisma.userRewardSummary.delete({ - * where: { - * // ... filter to delete one UserRewardSummary - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__UserRewardSummaryClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one UserRewardSummary. - * @param {UserRewardSummaryUpdateArgs} args - Arguments to update one UserRewardSummary. - * @example - * // Update one UserRewardSummary - * const userRewardSummary = await prisma.userRewardSummary.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__UserRewardSummaryClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more UserRewardSummaries. - * @param {UserRewardSummaryDeleteManyArgs} args - Arguments to filter UserRewardSummaries to delete. - * @example - * // Delete a few UserRewardSummaries - * const { count } = await prisma.userRewardSummary.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more UserRewardSummaries. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {UserRewardSummaryUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many UserRewardSummaries - * const userRewardSummary = await prisma.userRewardSummary.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more UserRewardSummaries and returns the data updated in the database. - * @param {UserRewardSummaryUpdateManyAndReturnArgs} args - Arguments to update many UserRewardSummaries. - * @example - * // Update many UserRewardSummaries - * const userRewardSummary = await prisma.userRewardSummary.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more UserRewardSummaries and only return the `id` - * const userRewardSummaryWithIdOnly = await prisma.userRewardSummary.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 UserRewardSummary. - * @param {UserRewardSummaryUpsertArgs} args - Arguments to update or create a UserRewardSummary. - * @example - * // Update or create a UserRewardSummary - * const userRewardSummary = await prisma.userRewardSummary.upsert({ - * create: { - * // ... data to create a UserRewardSummary - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the UserRewardSummary we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__UserRewardSummaryClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of UserRewardSummaries. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {UserRewardSummaryCountArgs} args - Arguments to filter UserRewardSummaries to count. - * @example - * // Count the number of UserRewardSummaries - * const count = await prisma.userRewardSummary.count({ - * where: { - * // ... the filter for the UserRewardSummaries 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 UserRewardSummary. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {UserRewardSummaryAggregateArgs} 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 UserRewardSummary. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {UserRewardSummaryGroupByArgs} 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 UserRewardSummaryGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: UserRewardSummaryGroupByArgs['orderBy'] } - : { orderBy?: UserRewardSummaryGroupByArgs['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 ? GetUserRewardSummaryGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the UserRewardSummary model - */ -readonly fields: UserRewardSummaryFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for UserRewardSummary. - * 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__UserRewardSummaryClient 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 UserRewardSummary model - */ -export interface UserRewardSummaryFieldRefs { - readonly id: Prisma.FieldRef<"UserRewardSummary", 'String'> - readonly userId: Prisma.FieldRef<"UserRewardSummary", 'String'> - readonly assetSymbol: Prisma.FieldRef<"UserRewardSummary", 'String'> - readonly totalAmount: Prisma.FieldRef<"UserRewardSummary", 'Decimal'> - readonly lastCalculatedAt: Prisma.FieldRef<"UserRewardSummary", 'DateTime'> - readonly createdAt: Prisma.FieldRef<"UserRewardSummary", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"UserRewardSummary", 'DateTime'> -} - - -// Custom InputTypes -/** - * UserRewardSummary findUnique - */ -export type UserRewardSummaryFindUniqueArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null - /** - * Filter, which UserRewardSummary to fetch. - */ - where: Prisma.UserRewardSummaryWhereUniqueInput -} - -/** - * UserRewardSummary findUniqueOrThrow - */ -export type UserRewardSummaryFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null - /** - * Filter, which UserRewardSummary to fetch. - */ - where: Prisma.UserRewardSummaryWhereUniqueInput -} - -/** - * UserRewardSummary findFirst - */ -export type UserRewardSummaryFindFirstArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null - /** - * Filter, which UserRewardSummary to fetch. - */ - where?: Prisma.UserRewardSummaryWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of UserRewardSummaries to fetch. - */ - orderBy?: Prisma.UserRewardSummaryOrderByWithRelationInput | Prisma.UserRewardSummaryOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for UserRewardSummaries. - */ - cursor?: Prisma.UserRewardSummaryWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` UserRewardSummaries 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` UserRewardSummaries. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of UserRewardSummaries. - */ - distinct?: Prisma.UserRewardSummaryScalarFieldEnum | Prisma.UserRewardSummaryScalarFieldEnum[] -} - -/** - * UserRewardSummary findFirstOrThrow - */ -export type UserRewardSummaryFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null - /** - * Filter, which UserRewardSummary to fetch. - */ - where?: Prisma.UserRewardSummaryWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of UserRewardSummaries to fetch. - */ - orderBy?: Prisma.UserRewardSummaryOrderByWithRelationInput | Prisma.UserRewardSummaryOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for UserRewardSummaries. - */ - cursor?: Prisma.UserRewardSummaryWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` UserRewardSummaries 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` UserRewardSummaries. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of UserRewardSummaries. - */ - distinct?: Prisma.UserRewardSummaryScalarFieldEnum | Prisma.UserRewardSummaryScalarFieldEnum[] -} - -/** - * UserRewardSummary findMany - */ -export type UserRewardSummaryFindManyArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null - /** - * Filter, which UserRewardSummaries to fetch. - */ - where?: Prisma.UserRewardSummaryWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of UserRewardSummaries to fetch. - */ - orderBy?: Prisma.UserRewardSummaryOrderByWithRelationInput | Prisma.UserRewardSummaryOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing UserRewardSummaries. - */ - cursor?: Prisma.UserRewardSummaryWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` UserRewardSummaries 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` UserRewardSummaries. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of UserRewardSummaries. - */ - distinct?: Prisma.UserRewardSummaryScalarFieldEnum | Prisma.UserRewardSummaryScalarFieldEnum[] -} - -/** - * UserRewardSummary create - */ -export type UserRewardSummaryCreateArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null - /** - * The data needed to create a UserRewardSummary. - */ - data: Prisma.XOR -} - -/** - * UserRewardSummary createMany - */ -export type UserRewardSummaryCreateManyArgs = { - /** - * The data used to create many UserRewardSummaries. - */ - data: Prisma.UserRewardSummaryCreateManyInput | Prisma.UserRewardSummaryCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * UserRewardSummary createManyAndReturn - */ -export type UserRewardSummaryCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelectCreateManyAndReturn | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * The data used to create many UserRewardSummaries. - */ - data: Prisma.UserRewardSummaryCreateManyInput | Prisma.UserRewardSummaryCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryIncludeCreateManyAndReturn | null -} - -/** - * UserRewardSummary update - */ -export type UserRewardSummaryUpdateArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null - /** - * The data needed to update a UserRewardSummary. - */ - data: Prisma.XOR - /** - * Choose, which UserRewardSummary to update. - */ - where: Prisma.UserRewardSummaryWhereUniqueInput -} - -/** - * UserRewardSummary updateMany - */ -export type UserRewardSummaryUpdateManyArgs = { - /** - * The data used to update UserRewardSummaries. - */ - data: Prisma.XOR - /** - * Filter which UserRewardSummaries to update - */ - where?: Prisma.UserRewardSummaryWhereInput - /** - * Limit how many UserRewardSummaries to update. - */ - limit?: number -} - -/** - * UserRewardSummary updateManyAndReturn - */ -export type UserRewardSummaryUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelectUpdateManyAndReturn | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * The data used to update UserRewardSummaries. - */ - data: Prisma.XOR - /** - * Filter which UserRewardSummaries to update - */ - where?: Prisma.UserRewardSummaryWhereInput - /** - * Limit how many UserRewardSummaries to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryIncludeUpdateManyAndReturn | null -} - -/** - * UserRewardSummary upsert - */ -export type UserRewardSummaryUpsertArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null - /** - * The filter to search for the UserRewardSummary to update in case it exists. - */ - where: Prisma.UserRewardSummaryWhereUniqueInput - /** - * In case the UserRewardSummary found by the `where` argument doesn't exist, create a new UserRewardSummary with this data. - */ - create: Prisma.XOR - /** - * In case the UserRewardSummary was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * UserRewardSummary delete - */ -export type UserRewardSummaryDeleteArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null - /** - * Filter which UserRewardSummary to delete. - */ - where: Prisma.UserRewardSummaryWhereUniqueInput -} - -/** - * UserRewardSummary deleteMany - */ -export type UserRewardSummaryDeleteManyArgs = { - /** - * Filter which UserRewardSummaries to delete - */ - where?: Prisma.UserRewardSummaryWhereInput - /** - * Limit how many UserRewardSummaries to delete. - */ - limit?: number -} - -/** - * UserRewardSummary without action - */ -export type UserRewardSummaryDefaultArgs = { - /** - * Select specific fields to fetch from the UserRewardSummary - */ - select?: Prisma.UserRewardSummarySelect | null - /** - * Omit specific fields from the UserRewardSummary - */ - omit?: Prisma.UserRewardSummaryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.UserRewardSummaryInclude | null -} diff --git a/apps/api/src/generated/prisma/models/World.ts b/apps/api/src/generated/prisma/models/World.ts deleted file mode 100644 index 7fe05e0..0000000 --- a/apps/api/src/generated/prisma/models/World.ts +++ /dev/null @@ -1,2279 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `World` 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 World - * - */ -export type WorldModel = runtime.Types.Result.DefaultSelection - -export type AggregateWorld = { - _count: WorldCountAggregateOutputType | null - _min: WorldMinAggregateOutputType | null - _max: WorldMaxAggregateOutputType | null -} - -export type WorldMinAggregateOutputType = { - id: string | null - slug: string | null - title: string | null - description: string | null - founderId: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type WorldMaxAggregateOutputType = { - id: string | null - slug: string | null - title: string | null - description: string | null - founderId: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type WorldCountAggregateOutputType = { - id: number - slug: number - title: number - description: number - founderId: number - createdAt: number - updatedAt: number - _all: number -} - - -export type WorldMinAggregateInputType = { - id?: true - slug?: true - title?: true - description?: true - founderId?: true - createdAt?: true - updatedAt?: true -} - -export type WorldMaxAggregateInputType = { - id?: true - slug?: true - title?: true - description?: true - founderId?: true - createdAt?: true - updatedAt?: true -} - -export type WorldCountAggregateInputType = { - id?: true - slug?: true - title?: true - description?: true - founderId?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type WorldAggregateArgs = { - /** - * Filter which World to aggregate. - */ - where?: Prisma.WorldWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of Worlds to fetch. - */ - orderBy?: Prisma.WorldOrderByWithRelationInput | Prisma.WorldOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.WorldWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` Worlds 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` Worlds. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned Worlds - **/ - _count?: true | WorldCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: WorldMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: WorldMaxAggregateInputType -} - -export type GetWorldAggregateType = { - [P in keyof T & keyof AggregateWorld]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type WorldGroupByArgs = { - where?: Prisma.WorldWhereInput - orderBy?: Prisma.WorldOrderByWithAggregationInput | Prisma.WorldOrderByWithAggregationInput[] - by: Prisma.WorldScalarFieldEnum[] | Prisma.WorldScalarFieldEnum - having?: Prisma.WorldScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: WorldCountAggregateInputType | true - _min?: WorldMinAggregateInputType - _max?: WorldMaxAggregateInputType -} - -export type WorldGroupByOutputType = { - id: string - slug: string - title: string - description: string - founderId: string - createdAt: Date - updatedAt: Date - _count: WorldCountAggregateOutputType | null - _min: WorldMinAggregateOutputType | null - _max: WorldMaxAggregateOutputType | null -} - -export type GetWorldGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof WorldGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type WorldWhereInput = { - AND?: Prisma.WorldWhereInput | Prisma.WorldWhereInput[] - OR?: Prisma.WorldWhereInput[] - NOT?: Prisma.WorldWhereInput | Prisma.WorldWhereInput[] - id?: Prisma.StringFilter<"World"> | string - slug?: Prisma.StringFilter<"World"> | string - title?: Prisma.StringFilter<"World"> | string - description?: Prisma.StringFilter<"World"> | string - founderId?: Prisma.StringFilter<"World"> | string - createdAt?: Prisma.DateTimeFilter<"World"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"World"> | Date | string - founder?: Prisma.XOR - bibleVersions?: Prisma.WorldBibleVersionListRelationFilter - loreEntries?: Prisma.LoreEntryListRelationFilter - loreRelationships?: Prisma.LoreRelationshipListRelationFilter - proposals?: Prisma.ProposalListRelationFilter - moderationReports?: Prisma.ModerationReportListRelationFilter - searchIndexes?: Prisma.SearchIndexListRelationFilter -} - -export type WorldOrderByWithRelationInput = { - id?: Prisma.SortOrder - slug?: Prisma.SortOrder - title?: Prisma.SortOrder - description?: Prisma.SortOrder - founderId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - founder?: Prisma.UserOrderByWithRelationInput - bibleVersions?: Prisma.WorldBibleVersionOrderByRelationAggregateInput - loreEntries?: Prisma.LoreEntryOrderByRelationAggregateInput - loreRelationships?: Prisma.LoreRelationshipOrderByRelationAggregateInput - proposals?: Prisma.ProposalOrderByRelationAggregateInput - moderationReports?: Prisma.ModerationReportOrderByRelationAggregateInput - searchIndexes?: Prisma.SearchIndexOrderByRelationAggregateInput -} - -export type WorldWhereUniqueInput = Prisma.AtLeast<{ - id?: string - slug?: string - AND?: Prisma.WorldWhereInput | Prisma.WorldWhereInput[] - OR?: Prisma.WorldWhereInput[] - NOT?: Prisma.WorldWhereInput | Prisma.WorldWhereInput[] - title?: Prisma.StringFilter<"World"> | string - description?: Prisma.StringFilter<"World"> | string - founderId?: Prisma.StringFilter<"World"> | string - createdAt?: Prisma.DateTimeFilter<"World"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"World"> | Date | string - founder?: Prisma.XOR - bibleVersions?: Prisma.WorldBibleVersionListRelationFilter - loreEntries?: Prisma.LoreEntryListRelationFilter - loreRelationships?: Prisma.LoreRelationshipListRelationFilter - proposals?: Prisma.ProposalListRelationFilter - moderationReports?: Prisma.ModerationReportListRelationFilter - searchIndexes?: Prisma.SearchIndexListRelationFilter -}, "id" | "slug"> - -export type WorldOrderByWithAggregationInput = { - id?: Prisma.SortOrder - slug?: Prisma.SortOrder - title?: Prisma.SortOrder - description?: Prisma.SortOrder - founderId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.WorldCountOrderByAggregateInput - _max?: Prisma.WorldMaxOrderByAggregateInput - _min?: Prisma.WorldMinOrderByAggregateInput -} - -export type WorldScalarWhereWithAggregatesInput = { - AND?: Prisma.WorldScalarWhereWithAggregatesInput | Prisma.WorldScalarWhereWithAggregatesInput[] - OR?: Prisma.WorldScalarWhereWithAggregatesInput[] - NOT?: Prisma.WorldScalarWhereWithAggregatesInput | Prisma.WorldScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"World"> | string - slug?: Prisma.StringWithAggregatesFilter<"World"> | string - title?: Prisma.StringWithAggregatesFilter<"World"> | string - description?: Prisma.StringWithAggregatesFilter<"World"> | string - founderId?: Prisma.StringWithAggregatesFilter<"World"> | string - createdAt?: Prisma.DateTimeWithAggregatesFilter<"World"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"World"> | Date | string -} - -export type WorldCreateInput = { - id?: string - slug: string - title: string - description: string - createdAt?: Date | string - updatedAt?: Date | string - founder: Prisma.UserCreateNestedOneWithoutFoundedWorldsInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexCreateNestedManyWithoutWorldInput -} - -export type WorldUncheckedCreateInput = { - id?: string - slug: string - title: string - description: string - founderId: string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexUncheckedCreateNestedManyWithoutWorldInput -} - -export type WorldUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - founder?: Prisma.UserUpdateOneRequiredWithoutFoundedWorldsNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUpdateManyWithoutWorldNestedInput -} - -export type WorldUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - founderId?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUncheckedUpdateManyWithoutWorldNestedInput -} - -export type WorldCreateManyInput = { - id?: string - slug: string - title: string - description: string - founderId: string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type WorldUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type WorldUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - founderId?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type WorldListRelationFilter = { - every?: Prisma.WorldWhereInput - some?: Prisma.WorldWhereInput - none?: Prisma.WorldWhereInput -} - -export type WorldOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type WorldCountOrderByAggregateInput = { - id?: Prisma.SortOrder - slug?: Prisma.SortOrder - title?: Prisma.SortOrder - description?: Prisma.SortOrder - founderId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type WorldMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - slug?: Prisma.SortOrder - title?: Prisma.SortOrder - description?: Prisma.SortOrder - founderId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type WorldMinOrderByAggregateInput = { - id?: Prisma.SortOrder - slug?: Prisma.SortOrder - title?: Prisma.SortOrder - description?: Prisma.SortOrder - founderId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type WorldScalarRelationFilter = { - is?: Prisma.WorldWhereInput - isNot?: Prisma.WorldWhereInput -} - -export type WorldNullableScalarRelationFilter = { - is?: Prisma.WorldWhereInput | null - isNot?: Prisma.WorldWhereInput | null -} - -export type WorldCreateNestedManyWithoutFounderInput = { - create?: Prisma.XOR | Prisma.WorldCreateWithoutFounderInput[] | Prisma.WorldUncheckedCreateWithoutFounderInput[] - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutFounderInput | Prisma.WorldCreateOrConnectWithoutFounderInput[] - createMany?: Prisma.WorldCreateManyFounderInputEnvelope - connect?: Prisma.WorldWhereUniqueInput | Prisma.WorldWhereUniqueInput[] -} - -export type WorldUncheckedCreateNestedManyWithoutFounderInput = { - create?: Prisma.XOR | Prisma.WorldCreateWithoutFounderInput[] | Prisma.WorldUncheckedCreateWithoutFounderInput[] - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutFounderInput | Prisma.WorldCreateOrConnectWithoutFounderInput[] - createMany?: Prisma.WorldCreateManyFounderInputEnvelope - connect?: Prisma.WorldWhereUniqueInput | Prisma.WorldWhereUniqueInput[] -} - -export type WorldUpdateManyWithoutFounderNestedInput = { - create?: Prisma.XOR | Prisma.WorldCreateWithoutFounderInput[] | Prisma.WorldUncheckedCreateWithoutFounderInput[] - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutFounderInput | Prisma.WorldCreateOrConnectWithoutFounderInput[] - upsert?: Prisma.WorldUpsertWithWhereUniqueWithoutFounderInput | Prisma.WorldUpsertWithWhereUniqueWithoutFounderInput[] - createMany?: Prisma.WorldCreateManyFounderInputEnvelope - set?: Prisma.WorldWhereUniqueInput | Prisma.WorldWhereUniqueInput[] - disconnect?: Prisma.WorldWhereUniqueInput | Prisma.WorldWhereUniqueInput[] - delete?: Prisma.WorldWhereUniqueInput | Prisma.WorldWhereUniqueInput[] - connect?: Prisma.WorldWhereUniqueInput | Prisma.WorldWhereUniqueInput[] - update?: Prisma.WorldUpdateWithWhereUniqueWithoutFounderInput | Prisma.WorldUpdateWithWhereUniqueWithoutFounderInput[] - updateMany?: Prisma.WorldUpdateManyWithWhereWithoutFounderInput | Prisma.WorldUpdateManyWithWhereWithoutFounderInput[] - deleteMany?: Prisma.WorldScalarWhereInput | Prisma.WorldScalarWhereInput[] -} - -export type WorldUncheckedUpdateManyWithoutFounderNestedInput = { - create?: Prisma.XOR | Prisma.WorldCreateWithoutFounderInput[] | Prisma.WorldUncheckedCreateWithoutFounderInput[] - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutFounderInput | Prisma.WorldCreateOrConnectWithoutFounderInput[] - upsert?: Prisma.WorldUpsertWithWhereUniqueWithoutFounderInput | Prisma.WorldUpsertWithWhereUniqueWithoutFounderInput[] - createMany?: Prisma.WorldCreateManyFounderInputEnvelope - set?: Prisma.WorldWhereUniqueInput | Prisma.WorldWhereUniqueInput[] - disconnect?: Prisma.WorldWhereUniqueInput | Prisma.WorldWhereUniqueInput[] - delete?: Prisma.WorldWhereUniqueInput | Prisma.WorldWhereUniqueInput[] - connect?: Prisma.WorldWhereUniqueInput | Prisma.WorldWhereUniqueInput[] - update?: Prisma.WorldUpdateWithWhereUniqueWithoutFounderInput | Prisma.WorldUpdateWithWhereUniqueWithoutFounderInput[] - updateMany?: Prisma.WorldUpdateManyWithWhereWithoutFounderInput | Prisma.WorldUpdateManyWithWhereWithoutFounderInput[] - deleteMany?: Prisma.WorldScalarWhereInput | Prisma.WorldScalarWhereInput[] -} - -export type WorldCreateNestedOneWithoutBibleVersionsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutBibleVersionsInput - connect?: Prisma.WorldWhereUniqueInput -} - -export type WorldUpdateOneRequiredWithoutBibleVersionsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutBibleVersionsInput - upsert?: Prisma.WorldUpsertWithoutBibleVersionsInput - connect?: Prisma.WorldWhereUniqueInput - update?: Prisma.XOR, Prisma.WorldUncheckedUpdateWithoutBibleVersionsInput> -} - -export type WorldCreateNestedOneWithoutLoreEntriesInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutLoreEntriesInput - connect?: Prisma.WorldWhereUniqueInput -} - -export type WorldUpdateOneRequiredWithoutLoreEntriesNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutLoreEntriesInput - upsert?: Prisma.WorldUpsertWithoutLoreEntriesInput - connect?: Prisma.WorldWhereUniqueInput - update?: Prisma.XOR, Prisma.WorldUncheckedUpdateWithoutLoreEntriesInput> -} - -export type WorldCreateNestedOneWithoutLoreRelationshipsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutLoreRelationshipsInput - connect?: Prisma.WorldWhereUniqueInput -} - -export type WorldUpdateOneRequiredWithoutLoreRelationshipsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutLoreRelationshipsInput - upsert?: Prisma.WorldUpsertWithoutLoreRelationshipsInput - connect?: Prisma.WorldWhereUniqueInput - update?: Prisma.XOR, Prisma.WorldUncheckedUpdateWithoutLoreRelationshipsInput> -} - -export type WorldCreateNestedOneWithoutProposalsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutProposalsInput - connect?: Prisma.WorldWhereUniqueInput -} - -export type WorldUpdateOneRequiredWithoutProposalsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutProposalsInput - upsert?: Prisma.WorldUpsertWithoutProposalsInput - connect?: Prisma.WorldWhereUniqueInput - update?: Prisma.XOR, Prisma.WorldUncheckedUpdateWithoutProposalsInput> -} - -export type WorldCreateNestedOneWithoutModerationReportsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutModerationReportsInput - connect?: Prisma.WorldWhereUniqueInput -} - -export type WorldUpdateOneWithoutModerationReportsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutModerationReportsInput - upsert?: Prisma.WorldUpsertWithoutModerationReportsInput - disconnect?: Prisma.WorldWhereInput | boolean - delete?: Prisma.WorldWhereInput | boolean - connect?: Prisma.WorldWhereUniqueInput - update?: Prisma.XOR, Prisma.WorldUncheckedUpdateWithoutModerationReportsInput> -} - -export type WorldCreateNestedOneWithoutSearchIndexesInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutSearchIndexesInput - connect?: Prisma.WorldWhereUniqueInput -} - -export type WorldUpdateOneWithoutSearchIndexesNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldCreateOrConnectWithoutSearchIndexesInput - upsert?: Prisma.WorldUpsertWithoutSearchIndexesInput - disconnect?: Prisma.WorldWhereInput | boolean - delete?: Prisma.WorldWhereInput | boolean - connect?: Prisma.WorldWhereUniqueInput - update?: Prisma.XOR, Prisma.WorldUncheckedUpdateWithoutSearchIndexesInput> -} - -export type WorldCreateWithoutFounderInput = { - id?: string - slug: string - title: string - description: string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexCreateNestedManyWithoutWorldInput -} - -export type WorldUncheckedCreateWithoutFounderInput = { - id?: string - slug: string - title: string - description: string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexUncheckedCreateNestedManyWithoutWorldInput -} - -export type WorldCreateOrConnectWithoutFounderInput = { - where: Prisma.WorldWhereUniqueInput - create: Prisma.XOR -} - -export type WorldCreateManyFounderInputEnvelope = { - data: Prisma.WorldCreateManyFounderInput | Prisma.WorldCreateManyFounderInput[] - skipDuplicates?: boolean -} - -export type WorldUpsertWithWhereUniqueWithoutFounderInput = { - where: Prisma.WorldWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type WorldUpdateWithWhereUniqueWithoutFounderInput = { - where: Prisma.WorldWhereUniqueInput - data: Prisma.XOR -} - -export type WorldUpdateManyWithWhereWithoutFounderInput = { - where: Prisma.WorldScalarWhereInput - data: Prisma.XOR -} - -export type WorldScalarWhereInput = { - AND?: Prisma.WorldScalarWhereInput | Prisma.WorldScalarWhereInput[] - OR?: Prisma.WorldScalarWhereInput[] - NOT?: Prisma.WorldScalarWhereInput | Prisma.WorldScalarWhereInput[] - id?: Prisma.StringFilter<"World"> | string - slug?: Prisma.StringFilter<"World"> | string - title?: Prisma.StringFilter<"World"> | string - description?: Prisma.StringFilter<"World"> | string - founderId?: Prisma.StringFilter<"World"> | string - createdAt?: Prisma.DateTimeFilter<"World"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"World"> | Date | string -} - -export type WorldCreateWithoutBibleVersionsInput = { - id?: string - slug: string - title: string - description: string - createdAt?: Date | string - updatedAt?: Date | string - founder: Prisma.UserCreateNestedOneWithoutFoundedWorldsInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexCreateNestedManyWithoutWorldInput -} - -export type WorldUncheckedCreateWithoutBibleVersionsInput = { - id?: string - slug: string - title: string - description: string - founderId: string - createdAt?: Date | string - updatedAt?: Date | string - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexUncheckedCreateNestedManyWithoutWorldInput -} - -export type WorldCreateOrConnectWithoutBibleVersionsInput = { - where: Prisma.WorldWhereUniqueInput - create: Prisma.XOR -} - -export type WorldUpsertWithoutBibleVersionsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.WorldWhereInput -} - -export type WorldUpdateToOneWithWhereWithoutBibleVersionsInput = { - where?: Prisma.WorldWhereInput - data: Prisma.XOR -} - -export type WorldUpdateWithoutBibleVersionsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - founder?: Prisma.UserUpdateOneRequiredWithoutFoundedWorldsNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUpdateManyWithoutWorldNestedInput -} - -export type WorldUncheckedUpdateWithoutBibleVersionsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - founderId?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUncheckedUpdateManyWithoutWorldNestedInput -} - -export type WorldCreateWithoutLoreEntriesInput = { - id?: string - slug: string - title: string - description: string - createdAt?: Date | string - updatedAt?: Date | string - founder: Prisma.UserCreateNestedOneWithoutFoundedWorldsInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexCreateNestedManyWithoutWorldInput -} - -export type WorldUncheckedCreateWithoutLoreEntriesInput = { - id?: string - slug: string - title: string - description: string - founderId: string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexUncheckedCreateNestedManyWithoutWorldInput -} - -export type WorldCreateOrConnectWithoutLoreEntriesInput = { - where: Prisma.WorldWhereUniqueInput - create: Prisma.XOR -} - -export type WorldUpsertWithoutLoreEntriesInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.WorldWhereInput -} - -export type WorldUpdateToOneWithWhereWithoutLoreEntriesInput = { - where?: Prisma.WorldWhereInput - data: Prisma.XOR -} - -export type WorldUpdateWithoutLoreEntriesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - founder?: Prisma.UserUpdateOneRequiredWithoutFoundedWorldsNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUpdateManyWithoutWorldNestedInput -} - -export type WorldUncheckedUpdateWithoutLoreEntriesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - founderId?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUncheckedUpdateManyWithoutWorldNestedInput -} - -export type WorldCreateWithoutLoreRelationshipsInput = { - id?: string - slug: string - title: string - description: string - createdAt?: Date | string - updatedAt?: Date | string - founder: Prisma.UserCreateNestedOneWithoutFoundedWorldsInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexCreateNestedManyWithoutWorldInput -} - -export type WorldUncheckedCreateWithoutLoreRelationshipsInput = { - id?: string - slug: string - title: string - description: string - founderId: string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexUncheckedCreateNestedManyWithoutWorldInput -} - -export type WorldCreateOrConnectWithoutLoreRelationshipsInput = { - where: Prisma.WorldWhereUniqueInput - create: Prisma.XOR -} - -export type WorldUpsertWithoutLoreRelationshipsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.WorldWhereInput -} - -export type WorldUpdateToOneWithWhereWithoutLoreRelationshipsInput = { - where?: Prisma.WorldWhereInput - data: Prisma.XOR -} - -export type WorldUpdateWithoutLoreRelationshipsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - founder?: Prisma.UserUpdateOneRequiredWithoutFoundedWorldsNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUpdateManyWithoutWorldNestedInput -} - -export type WorldUncheckedUpdateWithoutLoreRelationshipsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - founderId?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUncheckedUpdateManyWithoutWorldNestedInput -} - -export type WorldCreateWithoutProposalsInput = { - id?: string - slug: string - title: string - description: string - createdAt?: Date | string - updatedAt?: Date | string - founder: Prisma.UserCreateNestedOneWithoutFoundedWorldsInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexCreateNestedManyWithoutWorldInput -} - -export type WorldUncheckedCreateWithoutProposalsInput = { - id?: string - slug: string - title: string - description: string - founderId: string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexUncheckedCreateNestedManyWithoutWorldInput -} - -export type WorldCreateOrConnectWithoutProposalsInput = { - where: Prisma.WorldWhereUniqueInput - create: Prisma.XOR -} - -export type WorldUpsertWithoutProposalsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.WorldWhereInput -} - -export type WorldUpdateToOneWithWhereWithoutProposalsInput = { - where?: Prisma.WorldWhereInput - data: Prisma.XOR -} - -export type WorldUpdateWithoutProposalsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - founder?: Prisma.UserUpdateOneRequiredWithoutFoundedWorldsNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUpdateManyWithoutWorldNestedInput -} - -export type WorldUncheckedUpdateWithoutProposalsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - founderId?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUncheckedUpdateManyWithoutWorldNestedInput -} - -export type WorldCreateWithoutModerationReportsInput = { - id?: string - slug: string - title: string - description: string - createdAt?: Date | string - updatedAt?: Date | string - founder: Prisma.UserCreateNestedOneWithoutFoundedWorldsInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexCreateNestedManyWithoutWorldInput -} - -export type WorldUncheckedCreateWithoutModerationReportsInput = { - id?: string - slug: string - title: string - description: string - founderId: string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutWorldInput - searchIndexes?: Prisma.SearchIndexUncheckedCreateNestedManyWithoutWorldInput -} - -export type WorldCreateOrConnectWithoutModerationReportsInput = { - where: Prisma.WorldWhereUniqueInput - create: Prisma.XOR -} - -export type WorldUpsertWithoutModerationReportsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.WorldWhereInput -} - -export type WorldUpdateToOneWithWhereWithoutModerationReportsInput = { - where?: Prisma.WorldWhereInput - data: Prisma.XOR -} - -export type WorldUpdateWithoutModerationReportsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - founder?: Prisma.UserUpdateOneRequiredWithoutFoundedWorldsNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUpdateManyWithoutWorldNestedInput -} - -export type WorldUncheckedUpdateWithoutModerationReportsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - founderId?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUncheckedUpdateManyWithoutWorldNestedInput -} - -export type WorldCreateWithoutSearchIndexesInput = { - id?: string - slug: string - title: string - description: string - createdAt?: Date | string - updatedAt?: Date | string - founder: Prisma.UserCreateNestedOneWithoutFoundedWorldsInput - bibleVersions?: Prisma.WorldBibleVersionCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportCreateNestedManyWithoutWorldInput -} - -export type WorldUncheckedCreateWithoutSearchIndexesInput = { - id?: string - slug: string - title: string - description: string - founderId: string - createdAt?: Date | string - updatedAt?: Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedCreateNestedManyWithoutWorldInput - loreEntries?: Prisma.LoreEntryUncheckedCreateNestedManyWithoutWorldInput - loreRelationships?: Prisma.LoreRelationshipUncheckedCreateNestedManyWithoutWorldInput - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutWorldInput - moderationReports?: Prisma.ModerationReportUncheckedCreateNestedManyWithoutWorldInput -} - -export type WorldCreateOrConnectWithoutSearchIndexesInput = { - where: Prisma.WorldWhereUniqueInput - create: Prisma.XOR -} - -export type WorldUpsertWithoutSearchIndexesInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.WorldWhereInput -} - -export type WorldUpdateToOneWithWhereWithoutSearchIndexesInput = { - where?: Prisma.WorldWhereInput - data: Prisma.XOR -} - -export type WorldUpdateWithoutSearchIndexesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - founder?: Prisma.UserUpdateOneRequiredWithoutFoundedWorldsNestedInput - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutWorldNestedInput -} - -export type WorldUncheckedUpdateWithoutSearchIndexesInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - founderId?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutWorldNestedInput -} - -export type WorldCreateManyFounderInput = { - id?: string - slug: string - title: string - description: string - createdAt?: Date | string - updatedAt?: Date | string -} - -export type WorldUpdateWithoutFounderInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersions?: Prisma.WorldBibleVersionUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUpdateManyWithoutWorldNestedInput -} - -export type WorldUncheckedUpdateWithoutFounderInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - bibleVersions?: Prisma.WorldBibleVersionUncheckedUpdateManyWithoutWorldNestedInput - loreEntries?: Prisma.LoreEntryUncheckedUpdateManyWithoutWorldNestedInput - loreRelationships?: Prisma.LoreRelationshipUncheckedUpdateManyWithoutWorldNestedInput - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutWorldNestedInput - moderationReports?: Prisma.ModerationReportUncheckedUpdateManyWithoutWorldNestedInput - searchIndexes?: Prisma.SearchIndexUncheckedUpdateManyWithoutWorldNestedInput -} - -export type WorldUncheckedUpdateManyWithoutFounderInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - slug?: Prisma.StringFieldUpdateOperationsInput | string - title?: Prisma.StringFieldUpdateOperationsInput | string - description?: Prisma.StringFieldUpdateOperationsInput | string - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - -/** - * Count Type WorldCountOutputType - */ - -export type WorldCountOutputType = { - bibleVersions: number - loreEntries: number - loreRelationships: number - proposals: number - moderationReports: number - searchIndexes: number -} - -export type WorldCountOutputTypeSelect = { - bibleVersions?: boolean | WorldCountOutputTypeCountBibleVersionsArgs - loreEntries?: boolean | WorldCountOutputTypeCountLoreEntriesArgs - loreRelationships?: boolean | WorldCountOutputTypeCountLoreRelationshipsArgs - proposals?: boolean | WorldCountOutputTypeCountProposalsArgs - moderationReports?: boolean | WorldCountOutputTypeCountModerationReportsArgs - searchIndexes?: boolean | WorldCountOutputTypeCountSearchIndexesArgs -} - -/** - * WorldCountOutputType without action - */ -export type WorldCountOutputTypeDefaultArgs = { - /** - * Select specific fields to fetch from the WorldCountOutputType - */ - select?: Prisma.WorldCountOutputTypeSelect | null -} - -/** - * WorldCountOutputType without action - */ -export type WorldCountOutputTypeCountBibleVersionsArgs = { - where?: Prisma.WorldBibleVersionWhereInput -} - -/** - * WorldCountOutputType without action - */ -export type WorldCountOutputTypeCountLoreEntriesArgs = { - where?: Prisma.LoreEntryWhereInput -} - -/** - * WorldCountOutputType without action - */ -export type WorldCountOutputTypeCountLoreRelationshipsArgs = { - where?: Prisma.LoreRelationshipWhereInput -} - -/** - * WorldCountOutputType without action - */ -export type WorldCountOutputTypeCountProposalsArgs = { - where?: Prisma.ProposalWhereInput -} - -/** - * WorldCountOutputType without action - */ -export type WorldCountOutputTypeCountModerationReportsArgs = { - where?: Prisma.ModerationReportWhereInput -} - -/** - * WorldCountOutputType without action - */ -export type WorldCountOutputTypeCountSearchIndexesArgs = { - where?: Prisma.SearchIndexWhereInput -} - - -export type WorldSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - slug?: boolean - title?: boolean - description?: boolean - founderId?: boolean - createdAt?: boolean - updatedAt?: boolean - founder?: boolean | Prisma.UserDefaultArgs - bibleVersions?: boolean | Prisma.World$bibleVersionsArgs - loreEntries?: boolean | Prisma.World$loreEntriesArgs - loreRelationships?: boolean | Prisma.World$loreRelationshipsArgs - proposals?: boolean | Prisma.World$proposalsArgs - moderationReports?: boolean | Prisma.World$moderationReportsArgs - searchIndexes?: boolean | Prisma.World$searchIndexesArgs - _count?: boolean | Prisma.WorldCountOutputTypeDefaultArgs -}, ExtArgs["result"]["world"]> - -export type WorldSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - slug?: boolean - title?: boolean - description?: boolean - founderId?: boolean - createdAt?: boolean - updatedAt?: boolean - founder?: boolean | Prisma.UserDefaultArgs -}, ExtArgs["result"]["world"]> - -export type WorldSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - slug?: boolean - title?: boolean - description?: boolean - founderId?: boolean - createdAt?: boolean - updatedAt?: boolean - founder?: boolean | Prisma.UserDefaultArgs -}, ExtArgs["result"]["world"]> - -export type WorldSelectScalar = { - id?: boolean - slug?: boolean - title?: boolean - description?: boolean - founderId?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type WorldOmit = runtime.Types.Extensions.GetOmit<"id" | "slug" | "title" | "description" | "founderId" | "createdAt" | "updatedAt", ExtArgs["result"]["world"]> -export type WorldInclude = { - founder?: boolean | Prisma.UserDefaultArgs - bibleVersions?: boolean | Prisma.World$bibleVersionsArgs - loreEntries?: boolean | Prisma.World$loreEntriesArgs - loreRelationships?: boolean | Prisma.World$loreRelationshipsArgs - proposals?: boolean | Prisma.World$proposalsArgs - moderationReports?: boolean | Prisma.World$moderationReportsArgs - searchIndexes?: boolean | Prisma.World$searchIndexesArgs - _count?: boolean | Prisma.WorldCountOutputTypeDefaultArgs -} -export type WorldIncludeCreateManyAndReturn = { - founder?: boolean | Prisma.UserDefaultArgs -} -export type WorldIncludeUpdateManyAndReturn = { - founder?: boolean | Prisma.UserDefaultArgs -} - -export type $WorldPayload = { - name: "World" - objects: { - founder: Prisma.$UserPayload - bibleVersions: Prisma.$WorldBibleVersionPayload[] - loreEntries: Prisma.$LoreEntryPayload[] - loreRelationships: Prisma.$LoreRelationshipPayload[] - proposals: Prisma.$ProposalPayload[] - moderationReports: Prisma.$ModerationReportPayload[] - searchIndexes: Prisma.$SearchIndexPayload[] - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - slug: string - title: string - description: string - founderId: string - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["world"]> - composites: {} -} - -export type WorldGetPayload = runtime.Types.Result.GetResult - -export type WorldCountArgs = - Omit & { - select?: WorldCountAggregateInputType | true - } - -export interface WorldDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['World'], meta: { name: 'World' } } - /** - * Find zero or one World that matches the filter. - * @param {WorldFindUniqueArgs} args - Arguments to find a World - * @example - * // Get one World - * const world = await prisma.world.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__WorldClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one World that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {WorldFindUniqueOrThrowArgs} args - Arguments to find a World - * @example - * // Get one World - * const world = await prisma.world.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__WorldClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first World 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 {WorldFindFirstArgs} args - Arguments to find a World - * @example - * // Get one World - * const world = await prisma.world.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__WorldClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first World 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 {WorldFindFirstOrThrowArgs} args - Arguments to find a World - * @example - * // Get one World - * const world = await prisma.world.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__WorldClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more Worlds 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 {WorldFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all Worlds - * const worlds = await prisma.world.findMany() - * - * // Get first 10 Worlds - * const worlds = await prisma.world.findMany({ take: 10 }) - * - * // Only select the `id` - * const worldWithIdOnly = await prisma.world.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a World. - * @param {WorldCreateArgs} args - Arguments to create a World. - * @example - * // Create one World - * const World = await prisma.world.create({ - * data: { - * // ... data to create a World - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__WorldClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many Worlds. - * @param {WorldCreateManyArgs} args - Arguments to create many Worlds. - * @example - * // Create many Worlds - * const world = await prisma.world.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many Worlds and returns the data saved in the database. - * @param {WorldCreateManyAndReturnArgs} args - Arguments to create many Worlds. - * @example - * // Create many Worlds - * const world = await prisma.world.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many Worlds and only return the `id` - * const worldWithIdOnly = await prisma.world.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 World. - * @param {WorldDeleteArgs} args - Arguments to delete one World. - * @example - * // Delete one World - * const World = await prisma.world.delete({ - * where: { - * // ... filter to delete one World - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__WorldClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one World. - * @param {WorldUpdateArgs} args - Arguments to update one World. - * @example - * // Update one World - * const world = await prisma.world.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__WorldClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more Worlds. - * @param {WorldDeleteManyArgs} args - Arguments to filter Worlds to delete. - * @example - * // Delete a few Worlds - * const { count } = await prisma.world.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more Worlds. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {WorldUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many Worlds - * const world = await prisma.world.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more Worlds and returns the data updated in the database. - * @param {WorldUpdateManyAndReturnArgs} args - Arguments to update many Worlds. - * @example - * // Update many Worlds - * const world = await prisma.world.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more Worlds and only return the `id` - * const worldWithIdOnly = await prisma.world.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 World. - * @param {WorldUpsertArgs} args - Arguments to update or create a World. - * @example - * // Update or create a World - * const world = await prisma.world.upsert({ - * create: { - * // ... data to create a World - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the World we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__WorldClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of Worlds. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {WorldCountArgs} args - Arguments to filter Worlds to count. - * @example - * // Count the number of Worlds - * const count = await prisma.world.count({ - * where: { - * // ... the filter for the Worlds 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 World. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {WorldAggregateArgs} 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 World. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {WorldGroupByArgs} 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 WorldGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: WorldGroupByArgs['orderBy'] } - : { orderBy?: WorldGroupByArgs['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 ? GetWorldGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the World model - */ -readonly fields: WorldFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for World. - * 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__WorldClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - founder = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - bibleVersions = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - loreEntries = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - loreRelationships = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - proposals = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - moderationReports = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> - searchIndexes = {}>(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 World model - */ -export interface WorldFieldRefs { - readonly id: Prisma.FieldRef<"World", 'String'> - readonly slug: Prisma.FieldRef<"World", 'String'> - readonly title: Prisma.FieldRef<"World", 'String'> - readonly description: Prisma.FieldRef<"World", 'String'> - readonly founderId: Prisma.FieldRef<"World", 'String'> - readonly createdAt: Prisma.FieldRef<"World", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"World", 'DateTime'> -} - - -// Custom InputTypes -/** - * World findUnique - */ -export type WorldFindUniqueArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - /** - * Filter, which World to fetch. - */ - where: Prisma.WorldWhereUniqueInput -} - -/** - * World findUniqueOrThrow - */ -export type WorldFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - /** - * Filter, which World to fetch. - */ - where: Prisma.WorldWhereUniqueInput -} - -/** - * World findFirst - */ -export type WorldFindFirstArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - /** - * Filter, which World to fetch. - */ - where?: Prisma.WorldWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of Worlds to fetch. - */ - orderBy?: Prisma.WorldOrderByWithRelationInput | Prisma.WorldOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for Worlds. - */ - cursor?: Prisma.WorldWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` Worlds 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` Worlds. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of Worlds. - */ - distinct?: Prisma.WorldScalarFieldEnum | Prisma.WorldScalarFieldEnum[] -} - -/** - * World findFirstOrThrow - */ -export type WorldFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - /** - * Filter, which World to fetch. - */ - where?: Prisma.WorldWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of Worlds to fetch. - */ - orderBy?: Prisma.WorldOrderByWithRelationInput | Prisma.WorldOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for Worlds. - */ - cursor?: Prisma.WorldWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` Worlds 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` Worlds. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of Worlds. - */ - distinct?: Prisma.WorldScalarFieldEnum | Prisma.WorldScalarFieldEnum[] -} - -/** - * World findMany - */ -export type WorldFindManyArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - /** - * Filter, which Worlds to fetch. - */ - where?: Prisma.WorldWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of Worlds to fetch. - */ - orderBy?: Prisma.WorldOrderByWithRelationInput | Prisma.WorldOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing Worlds. - */ - cursor?: Prisma.WorldWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` Worlds 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` Worlds. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of Worlds. - */ - distinct?: Prisma.WorldScalarFieldEnum | Prisma.WorldScalarFieldEnum[] -} - -/** - * World create - */ -export type WorldCreateArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - /** - * The data needed to create a World. - */ - data: Prisma.XOR -} - -/** - * World createMany - */ -export type WorldCreateManyArgs = { - /** - * The data used to create many Worlds. - */ - data: Prisma.WorldCreateManyInput | Prisma.WorldCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * World createManyAndReturn - */ -export type WorldCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelectCreateManyAndReturn | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * The data used to create many Worlds. - */ - data: Prisma.WorldCreateManyInput | Prisma.WorldCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldIncludeCreateManyAndReturn | null -} - -/** - * World update - */ -export type WorldUpdateArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - /** - * The data needed to update a World. - */ - data: Prisma.XOR - /** - * Choose, which World to update. - */ - where: Prisma.WorldWhereUniqueInput -} - -/** - * World updateMany - */ -export type WorldUpdateManyArgs = { - /** - * The data used to update Worlds. - */ - data: Prisma.XOR - /** - * Filter which Worlds to update - */ - where?: Prisma.WorldWhereInput - /** - * Limit how many Worlds to update. - */ - limit?: number -} - -/** - * World updateManyAndReturn - */ -export type WorldUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * The data used to update Worlds. - */ - data: Prisma.XOR - /** - * Filter which Worlds to update - */ - where?: Prisma.WorldWhereInput - /** - * Limit how many Worlds to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldIncludeUpdateManyAndReturn | null -} - -/** - * World upsert - */ -export type WorldUpsertArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - /** - * The filter to search for the World to update in case it exists. - */ - where: Prisma.WorldWhereUniqueInput - /** - * In case the World found by the `where` argument doesn't exist, create a new World with this data. - */ - create: Prisma.XOR - /** - * In case the World was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * World delete - */ -export type WorldDeleteArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null - /** - * Filter which World to delete. - */ - where: Prisma.WorldWhereUniqueInput -} - -/** - * World deleteMany - */ -export type WorldDeleteManyArgs = { - /** - * Filter which Worlds to delete - */ - where?: Prisma.WorldWhereInput - /** - * Limit how many Worlds to delete. - */ - limit?: number -} - -/** - * World.bibleVersions - */ -export type World$bibleVersionsArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - where?: Prisma.WorldBibleVersionWhereInput - orderBy?: Prisma.WorldBibleVersionOrderByWithRelationInput | Prisma.WorldBibleVersionOrderByWithRelationInput[] - cursor?: Prisma.WorldBibleVersionWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.WorldBibleVersionScalarFieldEnum | Prisma.WorldBibleVersionScalarFieldEnum[] -} - -/** - * World.loreEntries - */ -export type World$loreEntriesArgs = { - /** - * Select specific fields to fetch from the LoreEntry - */ - select?: Prisma.LoreEntrySelect | null - /** - * Omit specific fields from the LoreEntry - */ - omit?: Prisma.LoreEntryOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreEntryInclude | null - where?: Prisma.LoreEntryWhereInput - orderBy?: Prisma.LoreEntryOrderByWithRelationInput | Prisma.LoreEntryOrderByWithRelationInput[] - cursor?: Prisma.LoreEntryWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.LoreEntryScalarFieldEnum | Prisma.LoreEntryScalarFieldEnum[] -} - -/** - * World.loreRelationships - */ -export type World$loreRelationshipsArgs = { - /** - * Select specific fields to fetch from the LoreRelationship - */ - select?: Prisma.LoreRelationshipSelect | null - /** - * Omit specific fields from the LoreRelationship - */ - omit?: Prisma.LoreRelationshipOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.LoreRelationshipInclude | null - where?: Prisma.LoreRelationshipWhereInput - orderBy?: Prisma.LoreRelationshipOrderByWithRelationInput | Prisma.LoreRelationshipOrderByWithRelationInput[] - cursor?: Prisma.LoreRelationshipWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.LoreRelationshipScalarFieldEnum | Prisma.LoreRelationshipScalarFieldEnum[] -} - -/** - * World.proposals - */ -export type World$proposalsArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - where?: Prisma.ProposalWhereInput - orderBy?: Prisma.ProposalOrderByWithRelationInput | Prisma.ProposalOrderByWithRelationInput[] - cursor?: Prisma.ProposalWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.ProposalScalarFieldEnum | Prisma.ProposalScalarFieldEnum[] -} - -/** - * World.moderationReports - */ -export type World$moderationReportsArgs = { - /** - * Select specific fields to fetch from the ModerationReport - */ - select?: Prisma.ModerationReportSelect | null - /** - * Omit specific fields from the ModerationReport - */ - omit?: Prisma.ModerationReportOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ModerationReportInclude | null - where?: Prisma.ModerationReportWhereInput - orderBy?: Prisma.ModerationReportOrderByWithRelationInput | Prisma.ModerationReportOrderByWithRelationInput[] - cursor?: Prisma.ModerationReportWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.ModerationReportScalarFieldEnum | Prisma.ModerationReportScalarFieldEnum[] -} - -/** - * World.searchIndexes - */ -export type World$searchIndexesArgs = { - /** - * Select specific fields to fetch from the SearchIndex - */ - select?: Prisma.SearchIndexSelect | null - /** - * Omit specific fields from the SearchIndex - */ - omit?: Prisma.SearchIndexOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.SearchIndexInclude | null - where?: Prisma.SearchIndexWhereInput - orderBy?: Prisma.SearchIndexOrderByWithRelationInput | Prisma.SearchIndexOrderByWithRelationInput[] - cursor?: Prisma.SearchIndexWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.SearchIndexScalarFieldEnum | Prisma.SearchIndexScalarFieldEnum[] -} - -/** - * World without action - */ -export type WorldDefaultArgs = { - /** - * Select specific fields to fetch from the World - */ - select?: Prisma.WorldSelect | null - /** - * Omit specific fields from the World - */ - omit?: Prisma.WorldOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldInclude | null -} diff --git a/apps/api/src/generated/prisma/models/WorldBibleVersion.ts b/apps/api/src/generated/prisma/models/WorldBibleVersion.ts deleted file mode 100644 index 10ae534..0000000 --- a/apps/api/src/generated/prisma/models/WorldBibleVersion.ts +++ /dev/null @@ -1,2021 +0,0 @@ - -/* !!! This is code generated by Prisma. Do not edit directly. !!! */ -/* eslint-disable */ -// biome-ignore-all lint: generated file -// @ts-nocheck -/* - * This file exports the `WorldBibleVersion` 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 WorldBibleVersion - * - */ -export type WorldBibleVersionModel = runtime.Types.Result.DefaultSelection - -export type AggregateWorldBibleVersion = { - _count: WorldBibleVersionCountAggregateOutputType | null - _avg: WorldBibleVersionAvgAggregateOutputType | null - _sum: WorldBibleVersionSumAggregateOutputType | null - _min: WorldBibleVersionMinAggregateOutputType | null - _max: WorldBibleVersionMaxAggregateOutputType | null -} - -export type WorldBibleVersionAvgAggregateOutputType = { - versionNumber: number | null -} - -export type WorldBibleVersionSumAggregateOutputType = { - versionNumber: number | null -} - -export type WorldBibleVersionMinAggregateOutputType = { - id: string | null - worldId: string | null - versionNumber: number | null - creatorId: string | null - changeSummary: string | null - publishedAt: Date | null - hiveReferenceId: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type WorldBibleVersionMaxAggregateOutputType = { - id: string | null - worldId: string | null - versionNumber: number | null - creatorId: string | null - changeSummary: string | null - publishedAt: Date | null - hiveReferenceId: string | null - createdAt: Date | null - updatedAt: Date | null -} - -export type WorldBibleVersionCountAggregateOutputType = { - id: number - worldId: number - versionNumber: number - creatorId: number - content: number - changeSummary: number - publishedAt: number - hiveReferenceId: number - createdAt: number - updatedAt: number - _all: number -} - - -export type WorldBibleVersionAvgAggregateInputType = { - versionNumber?: true -} - -export type WorldBibleVersionSumAggregateInputType = { - versionNumber?: true -} - -export type WorldBibleVersionMinAggregateInputType = { - id?: true - worldId?: true - versionNumber?: true - creatorId?: true - changeSummary?: true - publishedAt?: true - hiveReferenceId?: true - createdAt?: true - updatedAt?: true -} - -export type WorldBibleVersionMaxAggregateInputType = { - id?: true - worldId?: true - versionNumber?: true - creatorId?: true - changeSummary?: true - publishedAt?: true - hiveReferenceId?: true - createdAt?: true - updatedAt?: true -} - -export type WorldBibleVersionCountAggregateInputType = { - id?: true - worldId?: true - versionNumber?: true - creatorId?: true - content?: true - changeSummary?: true - publishedAt?: true - hiveReferenceId?: true - createdAt?: true - updatedAt?: true - _all?: true -} - -export type WorldBibleVersionAggregateArgs = { - /** - * Filter which WorldBibleVersion to aggregate. - */ - where?: Prisma.WorldBibleVersionWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of WorldBibleVersions to fetch. - */ - orderBy?: Prisma.WorldBibleVersionOrderByWithRelationInput | Prisma.WorldBibleVersionOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the start position - */ - cursor?: Prisma.WorldBibleVersionWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` WorldBibleVersions 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` WorldBibleVersions. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Count returned WorldBibleVersions - **/ - _count?: true | WorldBibleVersionCountAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to average - **/ - _avg?: WorldBibleVersionAvgAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to sum - **/ - _sum?: WorldBibleVersionSumAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the minimum value - **/ - _min?: WorldBibleVersionMinAggregateInputType - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} - * - * Select which fields to find the maximum value - **/ - _max?: WorldBibleVersionMaxAggregateInputType -} - -export type GetWorldBibleVersionAggregateType = { - [P in keyof T & keyof AggregateWorldBibleVersion]: P extends '_count' | 'count' - ? T[P] extends true - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType -} - - - - -export type WorldBibleVersionGroupByArgs = { - where?: Prisma.WorldBibleVersionWhereInput - orderBy?: Prisma.WorldBibleVersionOrderByWithAggregationInput | Prisma.WorldBibleVersionOrderByWithAggregationInput[] - by: Prisma.WorldBibleVersionScalarFieldEnum[] | Prisma.WorldBibleVersionScalarFieldEnum - having?: Prisma.WorldBibleVersionScalarWhereWithAggregatesInput - take?: number - skip?: number - _count?: WorldBibleVersionCountAggregateInputType | true - _avg?: WorldBibleVersionAvgAggregateInputType - _sum?: WorldBibleVersionSumAggregateInputType - _min?: WorldBibleVersionMinAggregateInputType - _max?: WorldBibleVersionMaxAggregateInputType -} - -export type WorldBibleVersionGroupByOutputType = { - id: string - worldId: string - versionNumber: number - creatorId: string - content: runtime.JsonValue - changeSummary: string | null - publishedAt: Date | null - hiveReferenceId: string | null - createdAt: Date - updatedAt: Date - _count: WorldBibleVersionCountAggregateOutputType | null - _avg: WorldBibleVersionAvgAggregateOutputType | null - _sum: WorldBibleVersionSumAggregateOutputType | null - _min: WorldBibleVersionMinAggregateOutputType | null - _max: WorldBibleVersionMaxAggregateOutputType | null -} - -export type GetWorldBibleVersionGroupByPayload = Prisma.PrismaPromise< - Array< - Prisma.PickEnumerable & - { - [P in ((keyof T) & (keyof WorldBibleVersionGroupByOutputType))]: P extends '_count' - ? T[P] extends boolean - ? number - : Prisma.GetScalarType - : Prisma.GetScalarType - } - > - > - - - -export type WorldBibleVersionWhereInput = { - AND?: Prisma.WorldBibleVersionWhereInput | Prisma.WorldBibleVersionWhereInput[] - OR?: Prisma.WorldBibleVersionWhereInput[] - NOT?: Prisma.WorldBibleVersionWhereInput | Prisma.WorldBibleVersionWhereInput[] - id?: Prisma.StringFilter<"WorldBibleVersion"> | string - worldId?: Prisma.StringFilter<"WorldBibleVersion"> | string - versionNumber?: Prisma.IntFilter<"WorldBibleVersion"> | number - creatorId?: Prisma.StringFilter<"WorldBibleVersion"> | string - content?: Prisma.JsonFilter<"WorldBibleVersion"> - changeSummary?: Prisma.StringNullableFilter<"WorldBibleVersion"> | string | null - publishedAt?: Prisma.DateTimeNullableFilter<"WorldBibleVersion"> | Date | string | null - hiveReferenceId?: Prisma.StringNullableFilter<"WorldBibleVersion"> | string | null - createdAt?: Prisma.DateTimeFilter<"WorldBibleVersion"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"WorldBibleVersion"> | Date | string - world?: Prisma.XOR - creator?: Prisma.XOR - hiveReference?: Prisma.XOR | null - proposals?: Prisma.ProposalListRelationFilter -} - -export type WorldBibleVersionOrderByWithRelationInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - versionNumber?: Prisma.SortOrder - creatorId?: Prisma.SortOrder - content?: Prisma.SortOrder - changeSummary?: Prisma.SortOrderInput | Prisma.SortOrder - publishedAt?: Prisma.SortOrderInput | Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - world?: Prisma.WorldOrderByWithRelationInput - creator?: Prisma.UserOrderByWithRelationInput - hiveReference?: Prisma.HiveReferenceOrderByWithRelationInput - proposals?: Prisma.ProposalOrderByRelationAggregateInput -} - -export type WorldBibleVersionWhereUniqueInput = Prisma.AtLeast<{ - id?: string - hiveReferenceId?: string - worldId_versionNumber?: Prisma.WorldBibleVersionWorldIdVersionNumberCompoundUniqueInput - AND?: Prisma.WorldBibleVersionWhereInput | Prisma.WorldBibleVersionWhereInput[] - OR?: Prisma.WorldBibleVersionWhereInput[] - NOT?: Prisma.WorldBibleVersionWhereInput | Prisma.WorldBibleVersionWhereInput[] - worldId?: Prisma.StringFilter<"WorldBibleVersion"> | string - versionNumber?: Prisma.IntFilter<"WorldBibleVersion"> | number - creatorId?: Prisma.StringFilter<"WorldBibleVersion"> | string - content?: Prisma.JsonFilter<"WorldBibleVersion"> - changeSummary?: Prisma.StringNullableFilter<"WorldBibleVersion"> | string | null - publishedAt?: Prisma.DateTimeNullableFilter<"WorldBibleVersion"> | Date | string | null - createdAt?: Prisma.DateTimeFilter<"WorldBibleVersion"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"WorldBibleVersion"> | Date | string - world?: Prisma.XOR - creator?: Prisma.XOR - hiveReference?: Prisma.XOR | null - proposals?: Prisma.ProposalListRelationFilter -}, "id" | "hiveReferenceId" | "worldId_versionNumber"> - -export type WorldBibleVersionOrderByWithAggregationInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - versionNumber?: Prisma.SortOrder - creatorId?: Prisma.SortOrder - content?: Prisma.SortOrder - changeSummary?: Prisma.SortOrderInput | Prisma.SortOrder - publishedAt?: Prisma.SortOrderInput | Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrderInput | Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder - _count?: Prisma.WorldBibleVersionCountOrderByAggregateInput - _avg?: Prisma.WorldBibleVersionAvgOrderByAggregateInput - _max?: Prisma.WorldBibleVersionMaxOrderByAggregateInput - _min?: Prisma.WorldBibleVersionMinOrderByAggregateInput - _sum?: Prisma.WorldBibleVersionSumOrderByAggregateInput -} - -export type WorldBibleVersionScalarWhereWithAggregatesInput = { - AND?: Prisma.WorldBibleVersionScalarWhereWithAggregatesInput | Prisma.WorldBibleVersionScalarWhereWithAggregatesInput[] - OR?: Prisma.WorldBibleVersionScalarWhereWithAggregatesInput[] - NOT?: Prisma.WorldBibleVersionScalarWhereWithAggregatesInput | Prisma.WorldBibleVersionScalarWhereWithAggregatesInput[] - id?: Prisma.StringWithAggregatesFilter<"WorldBibleVersion"> | string - worldId?: Prisma.StringWithAggregatesFilter<"WorldBibleVersion"> | string - versionNumber?: Prisma.IntWithAggregatesFilter<"WorldBibleVersion"> | number - creatorId?: Prisma.StringWithAggregatesFilter<"WorldBibleVersion"> | string - content?: Prisma.JsonWithAggregatesFilter<"WorldBibleVersion"> - changeSummary?: Prisma.StringNullableWithAggregatesFilter<"WorldBibleVersion"> | string | null - publishedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"WorldBibleVersion"> | Date | string | null - hiveReferenceId?: Prisma.StringNullableWithAggregatesFilter<"WorldBibleVersion"> | string | null - createdAt?: Prisma.DateTimeWithAggregatesFilter<"WorldBibleVersion"> | Date | string - updatedAt?: Prisma.DateTimeWithAggregatesFilter<"WorldBibleVersion"> | Date | string -} - -export type WorldBibleVersionCreateInput = { - id?: string - versionNumber: number - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutBibleVersionsInput - creator: Prisma.UserCreateNestedOneWithoutBibleVersionsInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutBibleVersionInput - proposals?: Prisma.ProposalCreateNestedManyWithoutResultingBibleVersionInput -} - -export type WorldBibleVersionUncheckedCreateInput = { - id?: string - worldId: string - versionNumber: number - creatorId: string - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingBibleVersionInput -} - -export type WorldBibleVersionUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutBibleVersionsNestedInput - creator?: Prisma.UserUpdateOneRequiredWithoutBibleVersionsNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutBibleVersionNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutResultingBibleVersionNestedInput -} - -export type WorldBibleVersionUncheckedUpdateInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - creatorId?: Prisma.StringFieldUpdateOperationsInput | string - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingBibleVersionNestedInput -} - -export type WorldBibleVersionCreateManyInput = { - id?: string - worldId: string - versionNumber: number - creatorId: string - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type WorldBibleVersionUpdateManyMutationInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type WorldBibleVersionUncheckedUpdateManyInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - creatorId?: Prisma.StringFieldUpdateOperationsInput | string - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type WorldBibleVersionListRelationFilter = { - every?: Prisma.WorldBibleVersionWhereInput - some?: Prisma.WorldBibleVersionWhereInput - none?: Prisma.WorldBibleVersionWhereInput -} - -export type WorldBibleVersionOrderByRelationAggregateInput = { - _count?: Prisma.SortOrder -} - -export type WorldBibleVersionWorldIdVersionNumberCompoundUniqueInput = { - worldId: string - versionNumber: number -} - -export type WorldBibleVersionCountOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - versionNumber?: Prisma.SortOrder - creatorId?: Prisma.SortOrder - content?: Prisma.SortOrder - changeSummary?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type WorldBibleVersionAvgOrderByAggregateInput = { - versionNumber?: Prisma.SortOrder -} - -export type WorldBibleVersionMaxOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - versionNumber?: Prisma.SortOrder - creatorId?: Prisma.SortOrder - changeSummary?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type WorldBibleVersionMinOrderByAggregateInput = { - id?: Prisma.SortOrder - worldId?: Prisma.SortOrder - versionNumber?: Prisma.SortOrder - creatorId?: Prisma.SortOrder - changeSummary?: Prisma.SortOrder - publishedAt?: Prisma.SortOrder - hiveReferenceId?: Prisma.SortOrder - createdAt?: Prisma.SortOrder - updatedAt?: Prisma.SortOrder -} - -export type WorldBibleVersionSumOrderByAggregateInput = { - versionNumber?: Prisma.SortOrder -} - -export type WorldBibleVersionNullableScalarRelationFilter = { - is?: Prisma.WorldBibleVersionWhereInput | null - isNot?: Prisma.WorldBibleVersionWhereInput | null -} - -export type WorldBibleVersionCreateNestedManyWithoutCreatorInput = { - create?: Prisma.XOR | Prisma.WorldBibleVersionCreateWithoutCreatorInput[] | Prisma.WorldBibleVersionUncheckedCreateWithoutCreatorInput[] - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutCreatorInput | Prisma.WorldBibleVersionCreateOrConnectWithoutCreatorInput[] - createMany?: Prisma.WorldBibleVersionCreateManyCreatorInputEnvelope - connect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] -} - -export type WorldBibleVersionUncheckedCreateNestedManyWithoutCreatorInput = { - create?: Prisma.XOR | Prisma.WorldBibleVersionCreateWithoutCreatorInput[] | Prisma.WorldBibleVersionUncheckedCreateWithoutCreatorInput[] - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutCreatorInput | Prisma.WorldBibleVersionCreateOrConnectWithoutCreatorInput[] - createMany?: Prisma.WorldBibleVersionCreateManyCreatorInputEnvelope - connect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] -} - -export type WorldBibleVersionUpdateManyWithoutCreatorNestedInput = { - create?: Prisma.XOR | Prisma.WorldBibleVersionCreateWithoutCreatorInput[] | Prisma.WorldBibleVersionUncheckedCreateWithoutCreatorInput[] - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutCreatorInput | Prisma.WorldBibleVersionCreateOrConnectWithoutCreatorInput[] - upsert?: Prisma.WorldBibleVersionUpsertWithWhereUniqueWithoutCreatorInput | Prisma.WorldBibleVersionUpsertWithWhereUniqueWithoutCreatorInput[] - createMany?: Prisma.WorldBibleVersionCreateManyCreatorInputEnvelope - set?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - disconnect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - delete?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - connect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - update?: Prisma.WorldBibleVersionUpdateWithWhereUniqueWithoutCreatorInput | Prisma.WorldBibleVersionUpdateWithWhereUniqueWithoutCreatorInput[] - updateMany?: Prisma.WorldBibleVersionUpdateManyWithWhereWithoutCreatorInput | Prisma.WorldBibleVersionUpdateManyWithWhereWithoutCreatorInput[] - deleteMany?: Prisma.WorldBibleVersionScalarWhereInput | Prisma.WorldBibleVersionScalarWhereInput[] -} - -export type WorldBibleVersionUncheckedUpdateManyWithoutCreatorNestedInput = { - create?: Prisma.XOR | Prisma.WorldBibleVersionCreateWithoutCreatorInput[] | Prisma.WorldBibleVersionUncheckedCreateWithoutCreatorInput[] - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutCreatorInput | Prisma.WorldBibleVersionCreateOrConnectWithoutCreatorInput[] - upsert?: Prisma.WorldBibleVersionUpsertWithWhereUniqueWithoutCreatorInput | Prisma.WorldBibleVersionUpsertWithWhereUniqueWithoutCreatorInput[] - createMany?: Prisma.WorldBibleVersionCreateManyCreatorInputEnvelope - set?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - disconnect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - delete?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - connect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - update?: Prisma.WorldBibleVersionUpdateWithWhereUniqueWithoutCreatorInput | Prisma.WorldBibleVersionUpdateWithWhereUniqueWithoutCreatorInput[] - updateMany?: Prisma.WorldBibleVersionUpdateManyWithWhereWithoutCreatorInput | Prisma.WorldBibleVersionUpdateManyWithWhereWithoutCreatorInput[] - deleteMany?: Prisma.WorldBibleVersionScalarWhereInput | Prisma.WorldBibleVersionScalarWhereInput[] -} - -export type WorldBibleVersionCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.WorldBibleVersionCreateWithoutWorldInput[] | Prisma.WorldBibleVersionUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutWorldInput | Prisma.WorldBibleVersionCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.WorldBibleVersionCreateManyWorldInputEnvelope - connect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] -} - -export type WorldBibleVersionUncheckedCreateNestedManyWithoutWorldInput = { - create?: Prisma.XOR | Prisma.WorldBibleVersionCreateWithoutWorldInput[] | Prisma.WorldBibleVersionUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutWorldInput | Prisma.WorldBibleVersionCreateOrConnectWithoutWorldInput[] - createMany?: Prisma.WorldBibleVersionCreateManyWorldInputEnvelope - connect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] -} - -export type WorldBibleVersionUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.WorldBibleVersionCreateWithoutWorldInput[] | Prisma.WorldBibleVersionUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutWorldInput | Prisma.WorldBibleVersionCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.WorldBibleVersionUpsertWithWhereUniqueWithoutWorldInput | Prisma.WorldBibleVersionUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.WorldBibleVersionCreateManyWorldInputEnvelope - set?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - disconnect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - delete?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - connect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - update?: Prisma.WorldBibleVersionUpdateWithWhereUniqueWithoutWorldInput | Prisma.WorldBibleVersionUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.WorldBibleVersionUpdateManyWithWhereWithoutWorldInput | Prisma.WorldBibleVersionUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.WorldBibleVersionScalarWhereInput | Prisma.WorldBibleVersionScalarWhereInput[] -} - -export type WorldBibleVersionUncheckedUpdateManyWithoutWorldNestedInput = { - create?: Prisma.XOR | Prisma.WorldBibleVersionCreateWithoutWorldInput[] | Prisma.WorldBibleVersionUncheckedCreateWithoutWorldInput[] - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutWorldInput | Prisma.WorldBibleVersionCreateOrConnectWithoutWorldInput[] - upsert?: Prisma.WorldBibleVersionUpsertWithWhereUniqueWithoutWorldInput | Prisma.WorldBibleVersionUpsertWithWhereUniqueWithoutWorldInput[] - createMany?: Prisma.WorldBibleVersionCreateManyWorldInputEnvelope - set?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - disconnect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - delete?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - connect?: Prisma.WorldBibleVersionWhereUniqueInput | Prisma.WorldBibleVersionWhereUniqueInput[] - update?: Prisma.WorldBibleVersionUpdateWithWhereUniqueWithoutWorldInput | Prisma.WorldBibleVersionUpdateWithWhereUniqueWithoutWorldInput[] - updateMany?: Prisma.WorldBibleVersionUpdateManyWithWhereWithoutWorldInput | Prisma.WorldBibleVersionUpdateManyWithWhereWithoutWorldInput[] - deleteMany?: Prisma.WorldBibleVersionScalarWhereInput | Prisma.WorldBibleVersionScalarWhereInput[] -} - -export type IntFieldUpdateOperationsInput = { - set?: number - increment?: number - decrement?: number - multiply?: number - divide?: number -} - -export type NullableDateTimeFieldUpdateOperationsInput = { - set?: Date | string | null -} - -export type WorldBibleVersionCreateNestedOneWithoutProposalsInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutProposalsInput - connect?: Prisma.WorldBibleVersionWhereUniqueInput -} - -export type WorldBibleVersionUpdateOneWithoutProposalsNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutProposalsInput - upsert?: Prisma.WorldBibleVersionUpsertWithoutProposalsInput - disconnect?: Prisma.WorldBibleVersionWhereInput | boolean - delete?: Prisma.WorldBibleVersionWhereInput | boolean - connect?: Prisma.WorldBibleVersionWhereUniqueInput - update?: Prisma.XOR, Prisma.WorldBibleVersionUncheckedUpdateWithoutProposalsInput> -} - -export type WorldBibleVersionCreateNestedOneWithoutHiveReferenceInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutHiveReferenceInput - connect?: Prisma.WorldBibleVersionWhereUniqueInput -} - -export type WorldBibleVersionUncheckedCreateNestedOneWithoutHiveReferenceInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutHiveReferenceInput - connect?: Prisma.WorldBibleVersionWhereUniqueInput -} - -export type WorldBibleVersionUpdateOneWithoutHiveReferenceNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutHiveReferenceInput - upsert?: Prisma.WorldBibleVersionUpsertWithoutHiveReferenceInput - disconnect?: Prisma.WorldBibleVersionWhereInput | boolean - delete?: Prisma.WorldBibleVersionWhereInput | boolean - connect?: Prisma.WorldBibleVersionWhereUniqueInput - update?: Prisma.XOR, Prisma.WorldBibleVersionUncheckedUpdateWithoutHiveReferenceInput> -} - -export type WorldBibleVersionUncheckedUpdateOneWithoutHiveReferenceNestedInput = { - create?: Prisma.XOR - connectOrCreate?: Prisma.WorldBibleVersionCreateOrConnectWithoutHiveReferenceInput - upsert?: Prisma.WorldBibleVersionUpsertWithoutHiveReferenceInput - disconnect?: Prisma.WorldBibleVersionWhereInput | boolean - delete?: Prisma.WorldBibleVersionWhereInput | boolean - connect?: Prisma.WorldBibleVersionWhereUniqueInput - update?: Prisma.XOR, Prisma.WorldBibleVersionUncheckedUpdateWithoutHiveReferenceInput> -} - -export type WorldBibleVersionCreateWithoutCreatorInput = { - id?: string - versionNumber: number - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutBibleVersionsInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutBibleVersionInput - proposals?: Prisma.ProposalCreateNestedManyWithoutResultingBibleVersionInput -} - -export type WorldBibleVersionUncheckedCreateWithoutCreatorInput = { - id?: string - worldId: string - versionNumber: number - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingBibleVersionInput -} - -export type WorldBibleVersionCreateOrConnectWithoutCreatorInput = { - where: Prisma.WorldBibleVersionWhereUniqueInput - create: Prisma.XOR -} - -export type WorldBibleVersionCreateManyCreatorInputEnvelope = { - data: Prisma.WorldBibleVersionCreateManyCreatorInput | Prisma.WorldBibleVersionCreateManyCreatorInput[] - skipDuplicates?: boolean -} - -export type WorldBibleVersionUpsertWithWhereUniqueWithoutCreatorInput = { - where: Prisma.WorldBibleVersionWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type WorldBibleVersionUpdateWithWhereUniqueWithoutCreatorInput = { - where: Prisma.WorldBibleVersionWhereUniqueInput - data: Prisma.XOR -} - -export type WorldBibleVersionUpdateManyWithWhereWithoutCreatorInput = { - where: Prisma.WorldBibleVersionScalarWhereInput - data: Prisma.XOR -} - -export type WorldBibleVersionScalarWhereInput = { - AND?: Prisma.WorldBibleVersionScalarWhereInput | Prisma.WorldBibleVersionScalarWhereInput[] - OR?: Prisma.WorldBibleVersionScalarWhereInput[] - NOT?: Prisma.WorldBibleVersionScalarWhereInput | Prisma.WorldBibleVersionScalarWhereInput[] - id?: Prisma.StringFilter<"WorldBibleVersion"> | string - worldId?: Prisma.StringFilter<"WorldBibleVersion"> | string - versionNumber?: Prisma.IntFilter<"WorldBibleVersion"> | number - creatorId?: Prisma.StringFilter<"WorldBibleVersion"> | string - content?: Prisma.JsonFilter<"WorldBibleVersion"> - changeSummary?: Prisma.StringNullableFilter<"WorldBibleVersion"> | string | null - publishedAt?: Prisma.DateTimeNullableFilter<"WorldBibleVersion"> | Date | string | null - hiveReferenceId?: Prisma.StringNullableFilter<"WorldBibleVersion"> | string | null - createdAt?: Prisma.DateTimeFilter<"WorldBibleVersion"> | Date | string - updatedAt?: Prisma.DateTimeFilter<"WorldBibleVersion"> | Date | string -} - -export type WorldBibleVersionCreateWithoutWorldInput = { - id?: string - versionNumber: number - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - creator: Prisma.UserCreateNestedOneWithoutBibleVersionsInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutBibleVersionInput - proposals?: Prisma.ProposalCreateNestedManyWithoutResultingBibleVersionInput -} - -export type WorldBibleVersionUncheckedCreateWithoutWorldInput = { - id?: string - versionNumber: number - creatorId: string - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingBibleVersionInput -} - -export type WorldBibleVersionCreateOrConnectWithoutWorldInput = { - where: Prisma.WorldBibleVersionWhereUniqueInput - create: Prisma.XOR -} - -export type WorldBibleVersionCreateManyWorldInputEnvelope = { - data: Prisma.WorldBibleVersionCreateManyWorldInput | Prisma.WorldBibleVersionCreateManyWorldInput[] - skipDuplicates?: boolean -} - -export type WorldBibleVersionUpsertWithWhereUniqueWithoutWorldInput = { - where: Prisma.WorldBibleVersionWhereUniqueInput - update: Prisma.XOR - create: Prisma.XOR -} - -export type WorldBibleVersionUpdateWithWhereUniqueWithoutWorldInput = { - where: Prisma.WorldBibleVersionWhereUniqueInput - data: Prisma.XOR -} - -export type WorldBibleVersionUpdateManyWithWhereWithoutWorldInput = { - where: Prisma.WorldBibleVersionScalarWhereInput - data: Prisma.XOR -} - -export type WorldBibleVersionCreateWithoutProposalsInput = { - id?: string - versionNumber: number - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutBibleVersionsInput - creator: Prisma.UserCreateNestedOneWithoutBibleVersionsInput - hiveReference?: Prisma.HiveReferenceCreateNestedOneWithoutBibleVersionInput -} - -export type WorldBibleVersionUncheckedCreateWithoutProposalsInput = { - id?: string - worldId: string - versionNumber: number - creatorId: string - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type WorldBibleVersionCreateOrConnectWithoutProposalsInput = { - where: Prisma.WorldBibleVersionWhereUniqueInput - create: Prisma.XOR -} - -export type WorldBibleVersionUpsertWithoutProposalsInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.WorldBibleVersionWhereInput -} - -export type WorldBibleVersionUpdateToOneWithWhereWithoutProposalsInput = { - where?: Prisma.WorldBibleVersionWhereInput - data: Prisma.XOR -} - -export type WorldBibleVersionUpdateWithoutProposalsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutBibleVersionsNestedInput - creator?: Prisma.UserUpdateOneRequiredWithoutBibleVersionsNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutBibleVersionNestedInput -} - -export type WorldBibleVersionUncheckedUpdateWithoutProposalsInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - creatorId?: Prisma.StringFieldUpdateOperationsInput | string - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type WorldBibleVersionCreateWithoutHiveReferenceInput = { - id?: string - versionNumber: number - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - world: Prisma.WorldCreateNestedOneWithoutBibleVersionsInput - creator: Prisma.UserCreateNestedOneWithoutBibleVersionsInput - proposals?: Prisma.ProposalCreateNestedManyWithoutResultingBibleVersionInput -} - -export type WorldBibleVersionUncheckedCreateWithoutHiveReferenceInput = { - id?: string - worldId: string - versionNumber: number - creatorId: string - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - createdAt?: Date | string - updatedAt?: Date | string - proposals?: Prisma.ProposalUncheckedCreateNestedManyWithoutResultingBibleVersionInput -} - -export type WorldBibleVersionCreateOrConnectWithoutHiveReferenceInput = { - where: Prisma.WorldBibleVersionWhereUniqueInput - create: Prisma.XOR -} - -export type WorldBibleVersionUpsertWithoutHiveReferenceInput = { - update: Prisma.XOR - create: Prisma.XOR - where?: Prisma.WorldBibleVersionWhereInput -} - -export type WorldBibleVersionUpdateToOneWithWhereWithoutHiveReferenceInput = { - where?: Prisma.WorldBibleVersionWhereInput - data: Prisma.XOR -} - -export type WorldBibleVersionUpdateWithoutHiveReferenceInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutBibleVersionsNestedInput - creator?: Prisma.UserUpdateOneRequiredWithoutBibleVersionsNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutResultingBibleVersionNestedInput -} - -export type WorldBibleVersionUncheckedUpdateWithoutHiveReferenceInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - creatorId?: Prisma.StringFieldUpdateOperationsInput | string - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingBibleVersionNestedInput -} - -export type WorldBibleVersionCreateManyCreatorInput = { - id?: string - worldId: string - versionNumber: number - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type WorldBibleVersionUpdateWithoutCreatorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - world?: Prisma.WorldUpdateOneRequiredWithoutBibleVersionsNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutBibleVersionNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutResultingBibleVersionNestedInput -} - -export type WorldBibleVersionUncheckedUpdateWithoutCreatorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingBibleVersionNestedInput -} - -export type WorldBibleVersionUncheckedUpdateManyWithoutCreatorInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - worldId?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - -export type WorldBibleVersionCreateManyWorldInput = { - id?: string - versionNumber: number - creatorId: string - content: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: string | null - publishedAt?: Date | string | null - hiveReferenceId?: string | null - createdAt?: Date | string - updatedAt?: Date | string -} - -export type WorldBibleVersionUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - creator?: Prisma.UserUpdateOneRequiredWithoutBibleVersionsNestedInput - hiveReference?: Prisma.HiveReferenceUpdateOneWithoutBibleVersionNestedInput - proposals?: Prisma.ProposalUpdateManyWithoutResultingBibleVersionNestedInput -} - -export type WorldBibleVersionUncheckedUpdateWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - creatorId?: Prisma.StringFieldUpdateOperationsInput | string - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - proposals?: Prisma.ProposalUncheckedUpdateManyWithoutResultingBibleVersionNestedInput -} - -export type WorldBibleVersionUncheckedUpdateManyWithoutWorldInput = { - id?: Prisma.StringFieldUpdateOperationsInput | string - versionNumber?: Prisma.IntFieldUpdateOperationsInput | number - creatorId?: Prisma.StringFieldUpdateOperationsInput | string - content?: Prisma.JsonNullValueInput | runtime.InputJsonValue - changeSummary?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - publishedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null - hiveReferenceId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string - updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string -} - - -/** - * Count Type WorldBibleVersionCountOutputType - */ - -export type WorldBibleVersionCountOutputType = { - proposals: number -} - -export type WorldBibleVersionCountOutputTypeSelect = { - proposals?: boolean | WorldBibleVersionCountOutputTypeCountProposalsArgs -} - -/** - * WorldBibleVersionCountOutputType without action - */ -export type WorldBibleVersionCountOutputTypeDefaultArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersionCountOutputType - */ - select?: Prisma.WorldBibleVersionCountOutputTypeSelect | null -} - -/** - * WorldBibleVersionCountOutputType without action - */ -export type WorldBibleVersionCountOutputTypeCountProposalsArgs = { - where?: Prisma.ProposalWhereInput -} - - -export type WorldBibleVersionSelect = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - versionNumber?: boolean - creatorId?: boolean - content?: boolean - changeSummary?: boolean - publishedAt?: boolean - hiveReferenceId?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - creator?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.WorldBibleVersion$hiveReferenceArgs - proposals?: boolean | Prisma.WorldBibleVersion$proposalsArgs - _count?: boolean | Prisma.WorldBibleVersionCountOutputTypeDefaultArgs -}, ExtArgs["result"]["worldBibleVersion"]> - -export type WorldBibleVersionSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - versionNumber?: boolean - creatorId?: boolean - content?: boolean - changeSummary?: boolean - publishedAt?: boolean - hiveReferenceId?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - creator?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.WorldBibleVersion$hiveReferenceArgs -}, ExtArgs["result"]["worldBibleVersion"]> - -export type WorldBibleVersionSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ - id?: boolean - worldId?: boolean - versionNumber?: boolean - creatorId?: boolean - content?: boolean - changeSummary?: boolean - publishedAt?: boolean - hiveReferenceId?: boolean - createdAt?: boolean - updatedAt?: boolean - world?: boolean | Prisma.WorldDefaultArgs - creator?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.WorldBibleVersion$hiveReferenceArgs -}, ExtArgs["result"]["worldBibleVersion"]> - -export type WorldBibleVersionSelectScalar = { - id?: boolean - worldId?: boolean - versionNumber?: boolean - creatorId?: boolean - content?: boolean - changeSummary?: boolean - publishedAt?: boolean - hiveReferenceId?: boolean - createdAt?: boolean - updatedAt?: boolean -} - -export type WorldBibleVersionOmit = runtime.Types.Extensions.GetOmit<"id" | "worldId" | "versionNumber" | "creatorId" | "content" | "changeSummary" | "publishedAt" | "hiveReferenceId" | "createdAt" | "updatedAt", ExtArgs["result"]["worldBibleVersion"]> -export type WorldBibleVersionInclude = { - world?: boolean | Prisma.WorldDefaultArgs - creator?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.WorldBibleVersion$hiveReferenceArgs - proposals?: boolean | Prisma.WorldBibleVersion$proposalsArgs - _count?: boolean | Prisma.WorldBibleVersionCountOutputTypeDefaultArgs -} -export type WorldBibleVersionIncludeCreateManyAndReturn = { - world?: boolean | Prisma.WorldDefaultArgs - creator?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.WorldBibleVersion$hiveReferenceArgs -} -export type WorldBibleVersionIncludeUpdateManyAndReturn = { - world?: boolean | Prisma.WorldDefaultArgs - creator?: boolean | Prisma.UserDefaultArgs - hiveReference?: boolean | Prisma.WorldBibleVersion$hiveReferenceArgs -} - -export type $WorldBibleVersionPayload = { - name: "WorldBibleVersion" - objects: { - world: Prisma.$WorldPayload - creator: Prisma.$UserPayload - /** - * A local publishedAt value is not proof of canon; verified canon requires an indexed HiveReference. - */ - hiveReference: Prisma.$HiveReferencePayload | null - proposals: Prisma.$ProposalPayload[] - } - scalars: runtime.Types.Extensions.GetPayloadResult<{ - id: string - worldId: string - versionNumber: number - creatorId: string - content: runtime.JsonValue - changeSummary: string | null - publishedAt: Date | null - hiveReferenceId: string | null - createdAt: Date - updatedAt: Date - }, ExtArgs["result"]["worldBibleVersion"]> - composites: {} -} - -export type WorldBibleVersionGetPayload = runtime.Types.Result.GetResult - -export type WorldBibleVersionCountArgs = - Omit & { - select?: WorldBibleVersionCountAggregateInputType | true - } - -export interface WorldBibleVersionDelegate { - [K: symbol]: { types: Prisma.TypeMap['model']['WorldBibleVersion'], meta: { name: 'WorldBibleVersion' } } - /** - * Find zero or one WorldBibleVersion that matches the filter. - * @param {WorldBibleVersionFindUniqueArgs} args - Arguments to find a WorldBibleVersion - * @example - * // Get one WorldBibleVersion - * const worldBibleVersion = await prisma.worldBibleVersion.findUnique({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__WorldBibleVersionClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find one WorldBibleVersion that matches the filter or throw an error with `error.code='P2025'` - * if no matches were found. - * @param {WorldBibleVersionFindUniqueOrThrowArgs} args - Arguments to find a WorldBibleVersion - * @example - * // Get one WorldBibleVersion - * const worldBibleVersion = await prisma.worldBibleVersion.findUniqueOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__WorldBibleVersionClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find the first WorldBibleVersion 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 {WorldBibleVersionFindFirstArgs} args - Arguments to find a WorldBibleVersion - * @example - * // Get one WorldBibleVersion - * const worldBibleVersion = await prisma.worldBibleVersion.findFirst({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__WorldBibleVersionClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - - /** - * Find the first WorldBibleVersion 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 {WorldBibleVersionFindFirstOrThrowArgs} args - Arguments to find a WorldBibleVersion - * @example - * // Get one WorldBibleVersion - * const worldBibleVersion = await prisma.worldBibleVersion.findFirstOrThrow({ - * where: { - * // ... provide filter here - * } - * }) - */ - findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__WorldBibleVersionClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Find zero or more WorldBibleVersions 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 {WorldBibleVersionFindManyArgs} args - Arguments to filter and select certain fields only. - * @example - * // Get all WorldBibleVersions - * const worldBibleVersions = await prisma.worldBibleVersion.findMany() - * - * // Get first 10 WorldBibleVersions - * const worldBibleVersions = await prisma.worldBibleVersion.findMany({ take: 10 }) - * - * // Only select the `id` - * const worldBibleVersionWithIdOnly = await prisma.worldBibleVersion.findMany({ select: { id: true } }) - * - */ - findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> - - /** - * Create a WorldBibleVersion. - * @param {WorldBibleVersionCreateArgs} args - Arguments to create a WorldBibleVersion. - * @example - * // Create one WorldBibleVersion - * const WorldBibleVersion = await prisma.worldBibleVersion.create({ - * data: { - * // ... data to create a WorldBibleVersion - * } - * }) - * - */ - create(args: Prisma.SelectSubset>): Prisma.Prisma__WorldBibleVersionClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Create many WorldBibleVersions. - * @param {WorldBibleVersionCreateManyArgs} args - Arguments to create many WorldBibleVersions. - * @example - * // Create many WorldBibleVersions - * const worldBibleVersion = await prisma.worldBibleVersion.createMany({ - * data: [ - * // ... provide data here - * ] - * }) - * - */ - createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Create many WorldBibleVersions and returns the data saved in the database. - * @param {WorldBibleVersionCreateManyAndReturnArgs} args - Arguments to create many WorldBibleVersions. - * @example - * // Create many WorldBibleVersions - * const worldBibleVersion = await prisma.worldBibleVersion.createManyAndReturn({ - * data: [ - * // ... provide data here - * ] - * }) - * - * // Create many WorldBibleVersions and only return the `id` - * const worldBibleVersionWithIdOnly = await prisma.worldBibleVersion.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 WorldBibleVersion. - * @param {WorldBibleVersionDeleteArgs} args - Arguments to delete one WorldBibleVersion. - * @example - * // Delete one WorldBibleVersion - * const WorldBibleVersion = await prisma.worldBibleVersion.delete({ - * where: { - * // ... filter to delete one WorldBibleVersion - * } - * }) - * - */ - delete(args: Prisma.SelectSubset>): Prisma.Prisma__WorldBibleVersionClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Update one WorldBibleVersion. - * @param {WorldBibleVersionUpdateArgs} args - Arguments to update one WorldBibleVersion. - * @example - * // Update one WorldBibleVersion - * const worldBibleVersion = await prisma.worldBibleVersion.update({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - update(args: Prisma.SelectSubset>): Prisma.Prisma__WorldBibleVersionClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - /** - * Delete zero or more WorldBibleVersions. - * @param {WorldBibleVersionDeleteManyArgs} args - Arguments to filter WorldBibleVersions to delete. - * @example - * // Delete a few WorldBibleVersions - * const { count } = await prisma.worldBibleVersion.deleteMany({ - * where: { - * // ... provide filter here - * } - * }) - * - */ - deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more WorldBibleVersions. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {WorldBibleVersionUpdateManyArgs} args - Arguments to update one or more rows. - * @example - * // Update many WorldBibleVersions - * const worldBibleVersion = await prisma.worldBibleVersion.updateMany({ - * where: { - * // ... provide filter here - * }, - * data: { - * // ... provide data here - * } - * }) - * - */ - updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise - - /** - * Update zero or more WorldBibleVersions and returns the data updated in the database. - * @param {WorldBibleVersionUpdateManyAndReturnArgs} args - Arguments to update many WorldBibleVersions. - * @example - * // Update many WorldBibleVersions - * const worldBibleVersion = await prisma.worldBibleVersion.updateManyAndReturn({ - * where: { - * // ... provide filter here - * }, - * data: [ - * // ... provide data here - * ] - * }) - * - * // Update zero or more WorldBibleVersions and only return the `id` - * const worldBibleVersionWithIdOnly = await prisma.worldBibleVersion.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 WorldBibleVersion. - * @param {WorldBibleVersionUpsertArgs} args - Arguments to update or create a WorldBibleVersion. - * @example - * // Update or create a WorldBibleVersion - * const worldBibleVersion = await prisma.worldBibleVersion.upsert({ - * create: { - * // ... data to create a WorldBibleVersion - * }, - * update: { - * // ... in case it already exists, update - * }, - * where: { - * // ... the filter for the WorldBibleVersion we want to update - * } - * }) - */ - upsert(args: Prisma.SelectSubset>): Prisma.Prisma__WorldBibleVersionClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> - - - /** - * Count the number of WorldBibleVersions. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {WorldBibleVersionCountArgs} args - Arguments to filter WorldBibleVersions to count. - * @example - * // Count the number of WorldBibleVersions - * const count = await prisma.worldBibleVersion.count({ - * where: { - * // ... the filter for the WorldBibleVersions 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 WorldBibleVersion. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {WorldBibleVersionAggregateArgs} 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 WorldBibleVersion. - * Note, that providing `undefined` is treated as the value not being there. - * Read more here: https://pris.ly/d/null-undefined - * @param {WorldBibleVersionGroupByArgs} 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 WorldBibleVersionGroupByArgs, - HasSelectOrTake extends Prisma.Or< - Prisma.Extends<'skip', Prisma.Keys>, - Prisma.Extends<'take', Prisma.Keys> - >, - OrderByArg extends Prisma.True extends HasSelectOrTake - ? { orderBy: WorldBibleVersionGroupByArgs['orderBy'] } - : { orderBy?: WorldBibleVersionGroupByArgs['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 ? GetWorldBibleVersionGroupByPayload : Prisma.PrismaPromise -/** - * Fields of the WorldBibleVersion model - */ -readonly fields: WorldBibleVersionFieldRefs; -} - -/** - * The delegate class that acts as a "Promise-like" for WorldBibleVersion. - * 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__WorldBibleVersionClient extends Prisma.PrismaPromise { - readonly [Symbol.toStringTag]: "PrismaPromise" - world = {}>(args?: Prisma.Subset>): Prisma.Prisma__WorldClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - creator = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> - hiveReference = {}>(args?: Prisma.Subset>): Prisma.Prisma__HiveReferenceClient, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> - proposals = {}>(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 WorldBibleVersion model - */ -export interface WorldBibleVersionFieldRefs { - readonly id: Prisma.FieldRef<"WorldBibleVersion", 'String'> - readonly worldId: Prisma.FieldRef<"WorldBibleVersion", 'String'> - readonly versionNumber: Prisma.FieldRef<"WorldBibleVersion", 'Int'> - readonly creatorId: Prisma.FieldRef<"WorldBibleVersion", 'String'> - readonly content: Prisma.FieldRef<"WorldBibleVersion", 'Json'> - readonly changeSummary: Prisma.FieldRef<"WorldBibleVersion", 'String'> - readonly publishedAt: Prisma.FieldRef<"WorldBibleVersion", 'DateTime'> - readonly hiveReferenceId: Prisma.FieldRef<"WorldBibleVersion", 'String'> - readonly createdAt: Prisma.FieldRef<"WorldBibleVersion", 'DateTime'> - readonly updatedAt: Prisma.FieldRef<"WorldBibleVersion", 'DateTime'> -} - - -// Custom InputTypes -/** - * WorldBibleVersion findUnique - */ -export type WorldBibleVersionFindUniqueArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - /** - * Filter, which WorldBibleVersion to fetch. - */ - where: Prisma.WorldBibleVersionWhereUniqueInput -} - -/** - * WorldBibleVersion findUniqueOrThrow - */ -export type WorldBibleVersionFindUniqueOrThrowArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - /** - * Filter, which WorldBibleVersion to fetch. - */ - where: Prisma.WorldBibleVersionWhereUniqueInput -} - -/** - * WorldBibleVersion findFirst - */ -export type WorldBibleVersionFindFirstArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - /** - * Filter, which WorldBibleVersion to fetch. - */ - where?: Prisma.WorldBibleVersionWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of WorldBibleVersions to fetch. - */ - orderBy?: Prisma.WorldBibleVersionOrderByWithRelationInput | Prisma.WorldBibleVersionOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for WorldBibleVersions. - */ - cursor?: Prisma.WorldBibleVersionWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` WorldBibleVersions 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` WorldBibleVersions. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of WorldBibleVersions. - */ - distinct?: Prisma.WorldBibleVersionScalarFieldEnum | Prisma.WorldBibleVersionScalarFieldEnum[] -} - -/** - * WorldBibleVersion findFirstOrThrow - */ -export type WorldBibleVersionFindFirstOrThrowArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - /** - * Filter, which WorldBibleVersion to fetch. - */ - where?: Prisma.WorldBibleVersionWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of WorldBibleVersions to fetch. - */ - orderBy?: Prisma.WorldBibleVersionOrderByWithRelationInput | Prisma.WorldBibleVersionOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for searching for WorldBibleVersions. - */ - cursor?: Prisma.WorldBibleVersionWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` WorldBibleVersions 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` WorldBibleVersions. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of WorldBibleVersions. - */ - distinct?: Prisma.WorldBibleVersionScalarFieldEnum | Prisma.WorldBibleVersionScalarFieldEnum[] -} - -/** - * WorldBibleVersion findMany - */ -export type WorldBibleVersionFindManyArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - /** - * Filter, which WorldBibleVersions to fetch. - */ - where?: Prisma.WorldBibleVersionWhereInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} - * - * Determine the order of WorldBibleVersions to fetch. - */ - orderBy?: Prisma.WorldBibleVersionOrderByWithRelationInput | Prisma.WorldBibleVersionOrderByWithRelationInput[] - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} - * - * Sets the position for listing WorldBibleVersions. - */ - cursor?: Prisma.WorldBibleVersionWhereUniqueInput - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} - * - * Take `±n` WorldBibleVersions 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` WorldBibleVersions. - */ - skip?: number - /** - * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} - * - * Filter by unique combinations of WorldBibleVersions. - */ - distinct?: Prisma.WorldBibleVersionScalarFieldEnum | Prisma.WorldBibleVersionScalarFieldEnum[] -} - -/** - * WorldBibleVersion create - */ -export type WorldBibleVersionCreateArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - /** - * The data needed to create a WorldBibleVersion. - */ - data: Prisma.XOR -} - -/** - * WorldBibleVersion createMany - */ -export type WorldBibleVersionCreateManyArgs = { - /** - * The data used to create many WorldBibleVersions. - */ - data: Prisma.WorldBibleVersionCreateManyInput | Prisma.WorldBibleVersionCreateManyInput[] - skipDuplicates?: boolean -} - -/** - * WorldBibleVersion createManyAndReturn - */ -export type WorldBibleVersionCreateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelectCreateManyAndReturn | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * The data used to create many WorldBibleVersions. - */ - data: Prisma.WorldBibleVersionCreateManyInput | Prisma.WorldBibleVersionCreateManyInput[] - skipDuplicates?: boolean - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionIncludeCreateManyAndReturn | null -} - -/** - * WorldBibleVersion update - */ -export type WorldBibleVersionUpdateArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - /** - * The data needed to update a WorldBibleVersion. - */ - data: Prisma.XOR - /** - * Choose, which WorldBibleVersion to update. - */ - where: Prisma.WorldBibleVersionWhereUniqueInput -} - -/** - * WorldBibleVersion updateMany - */ -export type WorldBibleVersionUpdateManyArgs = { - /** - * The data used to update WorldBibleVersions. - */ - data: Prisma.XOR - /** - * Filter which WorldBibleVersions to update - */ - where?: Prisma.WorldBibleVersionWhereInput - /** - * Limit how many WorldBibleVersions to update. - */ - limit?: number -} - -/** - * WorldBibleVersion updateManyAndReturn - */ -export type WorldBibleVersionUpdateManyAndReturnArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelectUpdateManyAndReturn | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * The data used to update WorldBibleVersions. - */ - data: Prisma.XOR - /** - * Filter which WorldBibleVersions to update - */ - where?: Prisma.WorldBibleVersionWhereInput - /** - * Limit how many WorldBibleVersions to update. - */ - limit?: number - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionIncludeUpdateManyAndReturn | null -} - -/** - * WorldBibleVersion upsert - */ -export type WorldBibleVersionUpsertArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - /** - * The filter to search for the WorldBibleVersion to update in case it exists. - */ - where: Prisma.WorldBibleVersionWhereUniqueInput - /** - * In case the WorldBibleVersion found by the `where` argument doesn't exist, create a new WorldBibleVersion with this data. - */ - create: Prisma.XOR - /** - * In case the WorldBibleVersion was found with the provided `where` argument, update it with this data. - */ - update: Prisma.XOR -} - -/** - * WorldBibleVersion delete - */ -export type WorldBibleVersionDeleteArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null - /** - * Filter which WorldBibleVersion to delete. - */ - where: Prisma.WorldBibleVersionWhereUniqueInput -} - -/** - * WorldBibleVersion deleteMany - */ -export type WorldBibleVersionDeleteManyArgs = { - /** - * Filter which WorldBibleVersions to delete - */ - where?: Prisma.WorldBibleVersionWhereInput - /** - * Limit how many WorldBibleVersions to delete. - */ - limit?: number -} - -/** - * WorldBibleVersion.hiveReference - */ -export type WorldBibleVersion$hiveReferenceArgs = { - /** - * Select specific fields to fetch from the HiveReference - */ - select?: Prisma.HiveReferenceSelect | null - /** - * Omit specific fields from the HiveReference - */ - omit?: Prisma.HiveReferenceOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.HiveReferenceInclude | null - where?: Prisma.HiveReferenceWhereInput -} - -/** - * WorldBibleVersion.proposals - */ -export type WorldBibleVersion$proposalsArgs = { - /** - * Select specific fields to fetch from the Proposal - */ - select?: Prisma.ProposalSelect | null - /** - * Omit specific fields from the Proposal - */ - omit?: Prisma.ProposalOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.ProposalInclude | null - where?: Prisma.ProposalWhereInput - orderBy?: Prisma.ProposalOrderByWithRelationInput | Prisma.ProposalOrderByWithRelationInput[] - cursor?: Prisma.ProposalWhereUniqueInput - take?: number - skip?: number - distinct?: Prisma.ProposalScalarFieldEnum | Prisma.ProposalScalarFieldEnum[] -} - -/** - * WorldBibleVersion without action - */ -export type WorldBibleVersionDefaultArgs = { - /** - * Select specific fields to fetch from the WorldBibleVersion - */ - select?: Prisma.WorldBibleVersionSelect | null - /** - * Omit specific fields from the WorldBibleVersion - */ - omit?: Prisma.WorldBibleVersionOmit | null - /** - * Choose, which related nodes to fetch as well - */ - include?: Prisma.WorldBibleVersionInclude | null -} diff --git a/apps/api/src/indexer/haf-sync.test.ts b/apps/api/src/indexer/haf-sync.test.ts new file mode 100644 index 0000000..381fb0f --- /dev/null +++ b/apps/api/src/indexer/haf-sync.test.ts @@ -0,0 +1,97 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { buildHiveLoreCommentOperation } from '../lib/hive/operations.js'; +import { HafSyncService, type HafSyncDatabase } from './haf-sync.js'; + +describe('HAF sync service', () => { + test('projects new rows and advances the durable watermark', async () => { + const projectedEvents: unknown[] = []; + const watermarkUpdates: unknown[] = []; + const operation = buildHiveLoreCommentOperation({ + author: 'emberquill.dev', + permlink: 'canon-lore', + title: 'Canon Lore', + body: 'A verified entry.', + kind: 'canon_lore', + entityType: 'LORE_ENTRY', + entityId: 'lore-1', + }); + const database: HafSyncDatabase = { + hiveEvent: { + async upsert(args) { + projectedEvents.push(args); + }, + }, + indexerWatermark: { + async findUnique() { + return { + lastProcessedBlock: 100n, + lastProcessedOperationIndex: 1, + }; + }, + async upsert(args) { + watermarkUpdates.push(args); + }, + }, + }; + const service = new HafSyncService( + { + async getHeadBlock() { + return 105; + }, + async searchBlocks() { + return { + operations: [ + { + block: 100, + trx_id: 'skip-me', + op_pos: 1, + timestamp: '2026-07-30T08:00:00.000Z', + op: { + type: 'comment_operation', + value: operation.comment_operation, + }, + }, + { + block: 100, + trx_id: 'project-me', + op_pos: 2, + timestamp: '2026-07-30T08:01:00.000Z', + op: { + type: 'comment_operation', + value: operation.comment_operation, + }, + }, + ], + page: 1, + totalPages: 1, + }; + }, + }, + database, + { + startBlock: 100, + maxBlocksPerRun: 10, + }, + ); + + const result = await service.runOnce(new Date('2026-07-30T09:00:00.000Z')); + + assert.equal(result.projectedOperations, 1); + assert.equal(projectedEvents.length, 1); + assert.equal( + ( + watermarkUpdates.find( + (update) => + typeof update === 'object' && + update !== null && + 'update' in update && + (update.update as { lastProcessedOperationIndex?: number }) + .lastProcessedOperationIndex === 2, + ) as { update: { lastProcessedBlock: bigint; lastProcessedOperationIndex: number } } + ).update.lastProcessedBlock, + 100n, + ); + }); +}); diff --git a/apps/api/src/indexer/haf-sync.ts b/apps/api/src/indexer/haf-sync.ts new file mode 100644 index 0000000..263b277 --- /dev/null +++ b/apps/api/src/indexer/haf-sync.ts @@ -0,0 +1,246 @@ +import type { HafClient } from '../lib/hive/haf-client.js'; +import { normalizeHafOperation, projectHiveOperation } from '../lib/hive/projection.js'; +import type { HafOperationRow } from '../lib/hive/types.js'; + +export interface HafSyncDatabase { + hiveEvent: Parameters[0]['hiveEvent']; + indexerWatermark: { + upsert(args: { + where: { + name: string; + }; + create: { + name: string; + lastProcessedBlock: bigint; + lastProcessedOperationIndex: number; + lastRunStartedAt?: Date; + lastRunFinishedAt?: Date; + }; + update: Partial<{ + lastProcessedBlock: bigint; + lastProcessedOperationIndex: number; + lastRunStartedAt: Date; + lastRunFinishedAt: Date; + }>; + }): Promise; + findUnique(args: { + where: { + name: string; + }; + select: { + lastProcessedBlock: true; + lastProcessedOperationIndex: true; + }; + }): Promise<{ + lastProcessedBlock: bigint; + lastProcessedOperationIndex: number; + } | null>; + }; +} + +export interface HafSyncOptions { + name?: string; + startBlock?: number; + batchSize?: number; + maxBlocksPerRun?: number; + operationTypes?: number[]; +} + +export interface HafSyncResult { + fromBlock: number; + toBlock: number; + headBlock: number; + projectedOperations: number; +} + +const DEFAULT_INDEXER_NAME = 'hivelore-haf'; +const DEFAULT_START_BLOCK = 1; +const DEFAULT_BATCH_SIZE = 100; +const DEFAULT_MAX_BLOCKS_PER_RUN = 1_000; + +export class HafSyncService { + private readonly name: string; + private readonly startBlock: number; + private readonly batchSize: number; + private readonly maxBlocksPerRun: number; + private readonly operationTypes: number[] | undefined; + + constructor( + private readonly hafClient: Pick, + private readonly database: HafSyncDatabase, + options: HafSyncOptions = {}, + ) { + this.name = options.name ?? DEFAULT_INDEXER_NAME; + this.startBlock = options.startBlock ?? DEFAULT_START_BLOCK; + this.batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE; + this.maxBlocksPerRun = options.maxBlocksPerRun ?? DEFAULT_MAX_BLOCKS_PER_RUN; + this.operationTypes = options.operationTypes; + } + + async runOnce(now = new Date()): Promise { + await this.markStarted(now); + + const [headBlock, watermark] = await Promise.all([ + this.hafClient.getHeadBlock(), + this.getWatermark(), + ]); + const fromBlock = Math.max(Number(watermark.lastProcessedBlock), this.startBlock); + const toBlock = Math.min(headBlock, fromBlock + this.maxBlocksPerRun - 1); + + if (toBlock < fromBlock) { + await this.markFinished(new Date()); + + return { + fromBlock, + toBlock, + headBlock, + projectedOperations: 0, + }; + } + + let projectedOperations = 0; + let page = 1; + + while (true) { + const response = await this.hafClient.searchBlocks({ + ...(this.operationTypes === undefined ? {} : { operationTypes: this.operationTypes }), + fromBlock, + toBlock, + page, + pageSize: this.batchSize, + }); + const rows = response.operations.filter((row) => shouldProcessRow(row, watermark)); + + for (const row of rows) { + const operation = normalizeHafOperation(row); + + await projectHiveOperation(this.database, operation); + await this.saveWatermark(operation.blockNumber, operation.operationIndex); + projectedOperations += 1; + } + + if (!hasNextPage(response.page ?? page, response.totalPages, response.operations.length)) { + break; + } + + page += 1; + } + + await this.markFinished(new Date()); + + return { + fromBlock, + toBlock, + headBlock, + projectedOperations, + }; + } + + private async getWatermark(): Promise<{ + lastProcessedBlock: bigint; + lastProcessedOperationIndex: number; + }> { + return ( + (await this.database.indexerWatermark.findUnique({ + where: { + name: this.name, + }, + select: { + lastProcessedBlock: true, + lastProcessedOperationIndex: true, + }, + })) ?? { + lastProcessedBlock: BigInt(this.startBlock), + lastProcessedOperationIndex: -1, + } + ); + } + + private async markStarted(startedAt: Date): Promise { + await this.database.indexerWatermark.upsert({ + where: { + name: this.name, + }, + create: { + name: this.name, + lastProcessedBlock: BigInt(this.startBlock), + lastProcessedOperationIndex: -1, + lastRunStartedAt: startedAt, + }, + update: { + lastRunStartedAt: startedAt, + }, + }); + } + + private async markFinished(finishedAt: Date): Promise { + await this.database.indexerWatermark.upsert({ + where: { + name: this.name, + }, + create: { + name: this.name, + lastProcessedBlock: BigInt(this.startBlock), + lastProcessedOperationIndex: -1, + lastRunFinishedAt: finishedAt, + }, + update: { + lastRunFinishedAt: finishedAt, + }, + }); + } + + private async saveWatermark(blockNumber: bigint, operationIndex: number): Promise { + await this.database.indexerWatermark.upsert({ + where: { + name: this.name, + }, + create: { + name: this.name, + lastProcessedBlock: blockNumber, + lastProcessedOperationIndex: operationIndex, + }, + update: { + lastProcessedBlock: blockNumber, + lastProcessedOperationIndex: operationIndex, + }, + }); + } +} + +function shouldProcessRow( + row: HafOperationRow, + watermark: { lastProcessedBlock: bigint; lastProcessedOperationIndex: number }, +): boolean { + const blockNumber = getNumeric(row.block_num ?? row.blockNumber ?? row.block); + const operationIndex = getNumeric(row.operation_id ?? row.operationIndex ?? row.op_pos); + + if (blockNumber === undefined || operationIndex === undefined) { + return true; + } + + if (BigInt(blockNumber) > watermark.lastProcessedBlock) { + return true; + } + + return ( + BigInt(blockNumber) === watermark.lastProcessedBlock && + operationIndex > watermark.lastProcessedOperationIndex + ); +} + +function hasNextPage(page: number, totalPages: number | undefined, rowCount: number): boolean { + if (totalPages !== undefined) { + return page < totalPages; + } + + return rowCount > 0; +} + +function getNumeric(value: unknown): number | undefined { + const numericValue = typeof value === 'string' ? Number(value) : value; + + return typeof numericValue === 'number' && Number.isInteger(numericValue) + ? numericValue + : undefined; +} diff --git a/apps/api/src/indexer/index.ts b/apps/api/src/indexer/index.ts new file mode 100644 index 0000000..f7f9279 --- /dev/null +++ b/apps/api/src/indexer/index.ts @@ -0,0 +1,3 @@ +export * from './haf-sync.js'; +export * from './reputation.js'; +export * from './rewards.js'; diff --git a/apps/api/src/indexer/reputation.test.ts b/apps/api/src/indexer/reputation.test.ts new file mode 100644 index 0000000..1168c37 --- /dev/null +++ b/apps/api/src/indexer/reputation.test.ts @@ -0,0 +1,41 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { + calculateReputation, + emptyReputationSignals, + REPUTATION_CALCULATION_VERSION, +} from './reputation.js'; + +describe('reputation calculator', () => { + test('uses the product scoring constants for deterministic snapshots', () => { + const result = calculateReputation({ + ...emptyReputationSignals(), + canonizedContributions: 2, + approvedProposals: 1, + highApprovalRatioProposals: 1, + repeatedRejectedSpamEvents: 1, + resolvedReports: 3, + helpfulComments: 4, + voteBrigadingOrSpamEvents: 1, + }); + + assert.equal(result.score, 63); + assert.equal(result.breakdown.calculationVersion, REPUTATION_CALCULATION_VERSION); + assert.deepEqual(result.breakdown.components, { + canonizedContributions: 50, + approvedProposals: 10, + highApprovalRatioProposals: 5, + repeatedRejectedSpamEvents: -10, + worldsReachingTenCanonEntries: 0, + highContributorRetentionWorlds: 0, + clearWorldBibles: 0, + resolvedReports: 15, + helpfulAcceptedReviews: 0, + abusiveModerationEvents: 0, + helpfulComments: 8, + accurateFlags: 0, + voteBrigadingOrSpamEvents: -15, + }); + }); +}); diff --git a/apps/api/src/indexer/reputation.ts b/apps/api/src/indexer/reputation.ts new file mode 100644 index 0000000..00cc50c --- /dev/null +++ b/apps/api/src/indexer/reputation.ts @@ -0,0 +1,248 @@ +export const REPUTATION_CALCULATION_VERSION = 'hivelore-reputation-v1'; + +export const REPUTATION_SCORING = { + canonizedContribution: 25, + approvedProposal: 10, + highApprovalRatio: 5, + repeatedRejectedSpam: -10, + worldReachesTenCanonEntries: 20, + highContributorRetention: 15, + clearWorldBible: 10, + resolvedReport: 5, + helpfulReviewAccepted: 3, + abusiveModeration: -20, + helpfulComment: 2, + accurateFlag: 3, + voteBrigadingOrSpam: -15, +} as const; + +export interface ReputationSignals { + canonizedContributions: number; + approvedProposals: number; + highApprovalRatioProposals: number; + repeatedRejectedSpamEvents: number; + worldsReachingTenCanonEntries: number; + highContributorRetentionWorlds: number; + clearWorldBibles: number; + resolvedReports: number; + helpfulAcceptedReviews: number; + abusiveModerationEvents: number; + helpfulComments: number; + accurateFlags: number; + voteBrigadingOrSpamEvents: number; +} + +export interface ReputationBreakdown { + calculationVersion: typeof REPUTATION_CALCULATION_VERSION; + signals: ReputationSignals; + components: Record; +} + +export interface ReputationDatabase { + loreEntry: { + count(args: unknown): Promise; + }; + proposal: { + count(args: unknown): Promise; + findMany(args: unknown): Promise< + { + id: string; + votes: { choice: 'APPROVE' | 'REJECT' | 'ABSTAIN' }[]; + }[] + >; + }; + moderationReport: { + count(args: unknown): Promise; + }; + userReputationSnapshot: { + create(args: { + data: { + userId: string; + score: number; + calculationVersion: string; + breakdown: ReputationBreakdown; + }; + }): Promise; + }; +} + +export function emptyReputationSignals(): ReputationSignals { + return { + canonizedContributions: 0, + approvedProposals: 0, + highApprovalRatioProposals: 0, + repeatedRejectedSpamEvents: 0, + worldsReachingTenCanonEntries: 0, + highContributorRetentionWorlds: 0, + clearWorldBibles: 0, + resolvedReports: 0, + helpfulAcceptedReviews: 0, + abusiveModerationEvents: 0, + helpfulComments: 0, + accurateFlags: 0, + voteBrigadingOrSpamEvents: 0, + }; +} + +export function calculateReputation(signals: ReputationSignals): { + score: number; + breakdown: ReputationBreakdown; +} { + const components: ReputationBreakdown['components'] = { + canonizedContributions: scoreComponent( + signals.canonizedContributions, + REPUTATION_SCORING.canonizedContribution, + ), + approvedProposals: scoreComponent( + signals.approvedProposals, + REPUTATION_SCORING.approvedProposal, + ), + highApprovalRatioProposals: scoreComponent( + signals.highApprovalRatioProposals, + REPUTATION_SCORING.highApprovalRatio, + ), + repeatedRejectedSpamEvents: scoreComponent( + signals.repeatedRejectedSpamEvents, + REPUTATION_SCORING.repeatedRejectedSpam, + ), + worldsReachingTenCanonEntries: scoreComponent( + signals.worldsReachingTenCanonEntries, + REPUTATION_SCORING.worldReachesTenCanonEntries, + ), + highContributorRetentionWorlds: scoreComponent( + signals.highContributorRetentionWorlds, + REPUTATION_SCORING.highContributorRetention, + ), + clearWorldBibles: scoreComponent(signals.clearWorldBibles, REPUTATION_SCORING.clearWorldBible), + resolvedReports: scoreComponent(signals.resolvedReports, REPUTATION_SCORING.resolvedReport), + helpfulAcceptedReviews: scoreComponent( + signals.helpfulAcceptedReviews, + REPUTATION_SCORING.helpfulReviewAccepted, + ), + abusiveModerationEvents: scoreComponent( + signals.abusiveModerationEvents, + REPUTATION_SCORING.abusiveModeration, + ), + helpfulComments: scoreComponent(signals.helpfulComments, REPUTATION_SCORING.helpfulComment), + accurateFlags: scoreComponent(signals.accurateFlags, REPUTATION_SCORING.accurateFlag), + voteBrigadingOrSpamEvents: scoreComponent( + signals.voteBrigadingOrSpamEvents, + REPUTATION_SCORING.voteBrigadingOrSpam, + ), + }; + + return { + score: Object.values(components).reduce((total, value) => total + value, 0), + breakdown: { + calculationVersion: REPUTATION_CALCULATION_VERSION, + signals, + components, + }, + }; +} + +function scoreComponent(count: number, weight: number): number { + const score = count * weight; + + return Object.is(score, -0) ? 0 : score; +} + +export async function collectReputationSignals( + database: ReputationDatabase, + userId: string, +): Promise { + const approvedStatuses = ['APPROVED_FOR_PUBLICATION', 'PUBLISHED']; + const signals = emptyReputationSignals(); + + const [canonizedContributions, approvedProposals, resolvedReports, rejectedSpam] = + await Promise.all([ + database.loreEntry.count({ + where: { + authorId: userId, + status: 'PUBLISHED_CANON', + }, + }), + database.proposal.count({ + where: { + authorId: userId, + status: { + in: approvedStatuses, + }, + }, + }), + database.moderationReport.count({ + where: { + reviewerId: userId, + status: 'RESOLVED', + }, + }), + database.moderationReport.count({ + where: { + reporterId: userId, + status: 'DISMISSED', + reason: { + contains: 'spam', + mode: 'insensitive', + }, + }, + }), + ]); + + const votedProposals = await database.proposal.findMany({ + where: { + authorId: userId, + status: { + in: approvedStatuses, + }, + }, + select: { + id: true, + votes: { + select: { + choice: true, + }, + }, + }, + }); + + signals.canonizedContributions = canonizedContributions; + signals.approvedProposals = approvedProposals; + signals.resolvedReports = resolvedReports; + signals.repeatedRejectedSpamEvents = rejectedSpam; + signals.highApprovalRatioProposals = votedProposals.filter(hasHighApprovalRatio).length; + + return signals; +} + +export async function refreshUserReputationSnapshot( + database: ReputationDatabase, + userId: string, +): Promise<{ score: number; breakdown: ReputationBreakdown }> { + const signals = await collectReputationSignals(database, userId); + const result = calculateReputation(signals); + + await database.userReputationSnapshot.create({ + data: { + userId, + score: result.score, + calculationVersion: REPUTATION_CALCULATION_VERSION, + breakdown: result.breakdown, + }, + }); + + return result; +} + +function hasHighApprovalRatio(proposal: { + votes: { choice: 'APPROVE' | 'REJECT' | 'ABSTAIN' }[]; +}): boolean { + const decisiveVotes = proposal.votes.filter((vote) => vote.choice !== 'ABSTAIN'); + + if (decisiveVotes.length < 5) { + return false; + } + + const approvals = decisiveVotes.filter((vote) => vote.choice === 'APPROVE').length; + + return approvals / decisiveVotes.length >= 0.7; +} diff --git a/apps/api/src/indexer/rewards.test.ts b/apps/api/src/indexer/rewards.test.ts new file mode 100644 index 0000000..7455bee --- /dev/null +++ b/apps/api/src/indexer/rewards.test.ts @@ -0,0 +1,62 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { HIVELORE_REWARD_SPLIT, refreshUserRewardSummaries } from './rewards.js'; + +describe('reward aggregation', () => { + test('documents the MVP 90/10/0 split constants', () => { + assert.deepEqual(HIVELORE_REWARD_SPLIT, { + authorPercent: 90, + beneficiaryPercent: 10, + platformPercent: 0, + }); + }); + + test('rebuilds user reward summaries from reward records', async () => { + const upserts: unknown[] = []; + const calculatedAt = new Date('2026-07-30T08:00:00.000Z'); + const summaries = await refreshUserRewardSummaries( + { + rewardRecord: { + async groupBy() { + return [ + { assetSymbol: 'HIVE', _sum: { amount: '12.500' } }, + { assetSymbol: 'HBD', _sum: { amount: 3 } }, + ]; + }, + }, + userRewardSummary: { + async upsert(args) { + upserts.push(args); + }, + }, + }, + 'user-1', + calculatedAt, + ); + + assert.deepEqual(summaries, [ + { assetSymbol: 'HIVE', totalAmount: '12.500' }, + { assetSymbol: 'HBD', totalAmount: '3' }, + ]); + assert.equal(upserts.length, 2); + assert.deepEqual(upserts[0], { + where: { + userId_assetSymbol: { + userId: 'user-1', + assetSymbol: 'HIVE', + }, + }, + create: { + userId: 'user-1', + assetSymbol: 'HIVE', + totalAmount: '12.500', + lastCalculatedAt: calculatedAt, + }, + update: { + totalAmount: '12.500', + lastCalculatedAt: calculatedAt, + }, + }); + }); +}); diff --git a/apps/api/src/indexer/rewards.ts b/apps/api/src/indexer/rewards.ts new file mode 100644 index 0000000..6e47e40 --- /dev/null +++ b/apps/api/src/indexer/rewards.ts @@ -0,0 +1,101 @@ +export const HIVELORE_REWARD_SPLIT = { + authorPercent: 90, + beneficiaryPercent: 10, + platformPercent: 0, +} as const; + +export interface RewardSummaryDatabase { + rewardRecord: { + groupBy(args: { + by: ['assetSymbol']; + where: { + userId: string; + }; + _sum: { + amount: true; + }; + }): Promise<{ assetSymbol: string; _sum: { amount: unknown } }[]>; + }; + userRewardSummary: { + upsert(args: { + where: { + userId_assetSymbol: { + userId: string; + assetSymbol: string; + }; + }; + create: { + userId: string; + assetSymbol: string; + totalAmount: string; + lastCalculatedAt: Date; + }; + update: { + totalAmount: string; + lastCalculatedAt: Date; + }; + }): Promise; + }; +} + +export async function refreshUserRewardSummaries( + database: RewardSummaryDatabase, + userId: string, + calculatedAt = new Date(), +): Promise<{ assetSymbol: string; totalAmount: string }[]> { + const totals = await database.rewardRecord.groupBy({ + by: ['assetSymbol'], + where: { + userId, + }, + _sum: { + amount: true, + }, + }); + + const summaries = totals.map((total) => ({ + assetSymbol: total.assetSymbol, + totalAmount: decimalLikeToString(total._sum.amount), + })); + + await Promise.all( + summaries.map((summary) => + database.userRewardSummary.upsert({ + where: { + userId_assetSymbol: { + userId, + assetSymbol: summary.assetSymbol, + }, + }, + create: { + userId, + assetSymbol: summary.assetSymbol, + totalAmount: summary.totalAmount, + lastCalculatedAt: calculatedAt, + }, + update: { + totalAmount: summary.totalAmount, + lastCalculatedAt: calculatedAt, + }, + }), + ), + ); + + return summaries; +} + +function decimalLikeToString(value: unknown): string { + if (value === null || value === undefined) { + return '0'; + } + + if (typeof value === 'number' || typeof value === 'bigint' || typeof value === 'string') { + return value.toString(); + } + + if (typeof value === 'object' && 'toString' in value && typeof value.toString === 'function') { + return value.toString(); + } + + throw new Error('Reward summary amount could not be converted to a decimal string.'); +} diff --git a/apps/api/src/indexer/runner.ts b/apps/api/src/indexer/runner.ts new file mode 100644 index 0000000..8bb0075 --- /dev/null +++ b/apps/api/src/indexer/runner.ts @@ -0,0 +1,50 @@ +import { env } from '../config/env.js'; +import type { Prisma } from '../generated/prisma/client.js'; +import { createHafClient } from '../lib/hive/client.js'; +import { prisma } from '../lib/prisma.js'; +import { HafSyncService, type HafSyncDatabase } from './haf-sync.js'; + +const prismaWithIndexer = prisma as typeof prisma & { + indexerWatermark: HafSyncDatabase['indexerWatermark']; +}; + +const database: HafSyncDatabase = { + hiveEvent: { + async upsert(args) { + await prisma.hiveEvent.upsert({ + ...args, + create: { + ...args.create, + payload: args.create.payload as Prisma.InputJsonValue, + }, + update: { + ...args.update, + payload: args.update.payload as Prisma.InputJsonValue, + }, + }); + }, + }, + indexerWatermark: { + async findUnique(args) { + return prismaWithIndexer.indexerWatermark.findUnique(args); + }, + async upsert(args) { + await prismaWithIndexer.indexerWatermark.upsert(args); + }, + }, +}; + +const syncService = new HafSyncService(createHafClient(), database, { + name: env.INDEXER_NAME, + startBlock: env.INDEXER_START_BLOCK, + batchSize: env.INDEXER_BATCH_SIZE, + maxBlocksPerRun: env.INDEXER_MAX_BLOCKS_PER_RUN, +}); + +try { + const result = await syncService.runOnce(); + + console.info('HAF indexer run completed', result); +} finally { + await prisma.$disconnect(); +} diff --git a/apps/api/src/lib/auth-challenges.test.ts b/apps/api/src/lib/auth-challenges.test.ts new file mode 100644 index 0000000..20f3df8 --- /dev/null +++ b/apps/api/src/lib/auth-challenges.test.ts @@ -0,0 +1,212 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { AuthProvider } from '../generated/prisma/enums.js'; +import { + AuthChallengeError, + consumeAuthChallenge, + createAuthChallenge, + type AuthChallengeDatabase, +} from './auth-challenges.js'; + +type ChallengeRecord = { + id: string; + normalizedHiveUsername: string; + provider: AuthProvider; + challengeHash: string; + nonceHash: string; + issuedAt: Date; + expiresAt: Date; + consumedAt: Date | null; +}; + +function createChallengeDatabase() { + const records = new Map(); + let nextId = 1; + + const database = { + authChallenge: { + async create(args: { + data: Omit; + select: { id: true; expiresAt: true }; + }) { + const record: ChallengeRecord = { + ...args.data, + consumedAt: null, + id: `challenge-${nextId}`, + }; + nextId += 1; + records.set(record.id, record); + + return { + expiresAt: record.expiresAt, + id: record.id, + }; + }, + async deleteMany(args: { where: { expiresAt: { lt: Date } } }) { + let count = 0; + + for (const [id, record] of records.entries()) { + if (record.expiresAt < args.where.expiresAt.lt) { + records.delete(id); + count += 1; + } + } + + return { count }; + }, + async findUnique(args: { + where: { id: string }; + select: { + challengeHash: true; + consumedAt: true; + expiresAt: true; + normalizedHiveUsername: true; + provider: true; + }; + }) { + const record = records.get(args.where.id); + + if (!record) { + return null; + } + + return { + challengeHash: record.challengeHash, + consumedAt: record.consumedAt, + expiresAt: record.expiresAt, + normalizedHiveUsername: record.normalizedHiveUsername, + provider: record.provider, + }; + }, + async updateMany(args: { + where: { id: string; consumedAt: null; expiresAt: { gt: Date } }; + data: { consumedAt: Date }; + }) { + const record = records.get(args.where.id); + + if (!record || record.consumedAt || record.expiresAt <= args.where.expiresAt.gt) { + return { count: 0 }; + } + + record.consumedAt = args.data.consumedAt; + + return { count: 1 }; + }, + }, + } as unknown as AuthChallengeDatabase; + + return database; +} + +const baseInput = { + audience: 'hivelore-test', + hmacSecret: 'test-secret-that-is-long-enough-for-hmac', + nonce: 'nonce-1', + provider: 'keychain' as const, + ttlSeconds: 300, + username: 'alice', +}; + +describe('authentication challenges', () => { + test('creates a deterministic human-readable challenge', async () => { + const challenge = await createAuthChallenge(createChallengeDatabase(), { + ...baseInput, + now: new Date('2026-08-01T00:00:00.000Z'), + }); + + assert.equal(challenge.challengeId, 'challenge-1'); + assert.equal(challenge.username, 'alice'); + assert.match(challenge.message, /HiveLore Authentication/); + assert.match(challenge.message, /Username: alice/); + assert.match(challenge.message, /does not authorize a Hive transaction or transfer/); + }); + + test('consumes a valid challenge once', async () => { + const database = createChallengeDatabase(); + const challenge = await createAuthChallenge(database, { + ...baseInput, + now: new Date('2026-08-01T00:00:00.000Z'), + }); + + const username = await consumeAuthChallenge(database, { + challengeId: challenge.challengeId, + hmacSecret: baseInput.hmacSecret, + message: challenge.message, + provider: 'keychain', + username: 'alice', + now: new Date('2026-08-01T00:01:00.000Z'), + }); + + assert.equal(username, 'alice'); + await assert.rejects( + () => + consumeAuthChallenge(database, { + challengeId: challenge.challengeId, + hmacSecret: baseInput.hmacSecret, + message: challenge.message, + provider: 'keychain', + username: 'alice', + now: new Date('2026-08-01T00:01:01.000Z'), + }), + AuthChallengeError, + ); + }); + + test('rejects expired, mismatched username, mismatched message, and wrong provider', async () => { + const database = createChallengeDatabase(); + const challenge = await createAuthChallenge(database, { + ...baseInput, + now: new Date('2026-08-01T00:00:00.000Z'), + }); + + await assert.rejects( + () => + consumeAuthChallenge(database, { + challengeId: challenge.challengeId, + hmacSecret: baseInput.hmacSecret, + message: challenge.message, + provider: 'keychain', + username: 'alice', + now: new Date('2026-08-01T00:06:00.000Z'), + }), + AuthChallengeError, + ); + await assert.rejects( + () => + consumeAuthChallenge(database, { + challengeId: challenge.challengeId, + hmacSecret: baseInput.hmacSecret, + message: challenge.message, + provider: 'keychain', + username: 'bob', + now: new Date('2026-08-01T00:01:00.000Z'), + }), + AuthChallengeError, + ); + await assert.rejects( + () => + consumeAuthChallenge(database, { + challengeId: challenge.challengeId, + hmacSecret: baseInput.hmacSecret, + message: `${challenge.message}\nextra`, + provider: 'keychain', + username: 'alice', + now: new Date('2026-08-01T00:01:00.000Z'), + }), + AuthChallengeError, + ); + await assert.rejects( + () => + consumeAuthChallenge(database, { + challengeId: challenge.challengeId, + hmacSecret: baseInput.hmacSecret, + message: challenge.message, + provider: 'hivesigner', + username: 'alice', + now: new Date('2026-08-01T00:01:00.000Z'), + }), + AuthChallengeError, + ); + }); +}); diff --git a/apps/api/src/lib/auth-challenges.ts b/apps/api/src/lib/auth-challenges.ts new file mode 100644 index 0000000..55ce514 --- /dev/null +++ b/apps/api/src/lib/auth-challenges.ts @@ -0,0 +1,153 @@ +import { AuthProvider } from '../generated/prisma/enums.js'; +import type { PrismaClient } from '../generated/prisma/client.js'; +import { sha256Hmac } from './auth-crypto.js'; +import type { HiveAuthProvider } from './hive-signature.js'; +import { normalizeHiveUsername } from './hive-username.js'; + +export type AuthChallengeDatabase = Pick; + +const providerToDatabase: Record = { + hivesigner: AuthProvider.HIVESIGNER, + keychain: AuthProvider.KEYCHAIN, +}; + +export class AuthChallengeError extends Error { + constructor(message: string) { + super(message); + } +} + +export function toDatabaseAuthProvider(provider: HiveAuthProvider) { + return providerToDatabase[provider]; +} + +export function buildAuthChallengeMessage(input: { + audience: string; + expiresAt: Date; + issuedAt: Date; + nonce: string; + username: string; +}) { + return [ + 'HiveLore Authentication', + '', + `Username: ${input.username}`, + `Nonce: ${input.nonce}`, + `Issued At: ${input.issuedAt.toISOString()}`, + `Expires At: ${input.expiresAt.toISOString()}`, + `Audience: ${input.audience}`, + '', + 'Signing this message authenticates you to HiveLore.', + 'It does not authorize a Hive transaction or transfer.', + ].join('\n'); +} + +export async function createAuthChallenge( + database: AuthChallengeDatabase, + input: { + audience: string; + hmacSecret: string; + nonce: string; + provider: HiveAuthProvider; + ttlSeconds: number; + username: string; + now?: Date; + }, +) { + const normalizedHiveUsername = normalizeHiveUsername(input.username); + const issuedAt = input.now ?? new Date(); + const expiresAt = new Date(issuedAt.getTime() + input.ttlSeconds * 1000); + const message = buildAuthChallengeMessage({ + audience: input.audience, + expiresAt, + issuedAt, + nonce: input.nonce, + username: normalizedHiveUsername, + }); + await database.authChallenge.deleteMany({ + where: { + expiresAt: { + lt: issuedAt, + }, + }, + }); + + const challenge = await database.authChallenge.create({ + data: { + challengeHash: sha256Hmac(message, input.hmacSecret), + expiresAt, + issuedAt, + nonceHash: sha256Hmac(input.nonce, input.hmacSecret), + normalizedHiveUsername, + provider: toDatabaseAuthProvider(input.provider), + }, + select: { + id: true, + expiresAt: true, + }, + }); + + return { + challengeId: challenge.id, + expiresAt: challenge.expiresAt, + message, + username: normalizedHiveUsername, + }; +} + +export async function consumeAuthChallenge( + database: AuthChallengeDatabase, + input: { + challengeId: string; + hmacSecret: string; + message: string; + provider: HiveAuthProvider; + username: string; + now?: Date; + }, +) { + const normalizedHiveUsername = normalizeHiveUsername(input.username); + const now = input.now ?? new Date(); + const challenge = await database.authChallenge.findUnique({ + where: { + id: input.challengeId, + }, + select: { + challengeHash: true, + consumedAt: true, + expiresAt: true, + normalizedHiveUsername: true, + provider: true, + }, + }); + + if ( + !challenge || + challenge.consumedAt || + challenge.expiresAt <= now || + challenge.normalizedHiveUsername !== normalizedHiveUsername || + challenge.provider !== toDatabaseAuthProvider(input.provider) || + challenge.challengeHash !== sha256Hmac(input.message, input.hmacSecret) + ) { + throw new AuthChallengeError('Invalid or expired authentication challenge.'); + } + + const result = await database.authChallenge.updateMany({ + where: { + id: input.challengeId, + consumedAt: null, + expiresAt: { + gt: now, + }, + }, + data: { + consumedAt: now, + }, + }); + + if (result.count !== 1) { + throw new AuthChallengeError('Invalid or expired authentication challenge.'); + } + + return normalizedHiveUsername; +} diff --git a/apps/api/src/lib/auth-cookies.ts b/apps/api/src/lib/auth-cookies.ts new file mode 100644 index 0000000..fd08bcf --- /dev/null +++ b/apps/api/src/lib/auth-cookies.ts @@ -0,0 +1,67 @@ +import type { FastifyReply, FastifyRequest } from 'fastify'; + +const REFRESH_COOKIE_NAME = 'hivelore_refresh'; + +export function getRefreshCookieName() { + return REFRESH_COOKIE_NAME; +} + +export function readCookie(request: FastifyRequest, name: string) { + const cookieHeader = request.headers.cookie; + + if (!cookieHeader) { + return null; + } + + for (const cookie of cookieHeader.split(';')) { + const [rawName, ...rawValue] = cookie.trim().split('='); + + if (rawName === name) { + return decodeURIComponent(rawValue.join('=')); + } + } + + return null; +} + +export function setRefreshCookie( + reply: FastifyReply, + token: string, + options: { + domain?: string | undefined; + maxAgeSeconds: number; + secure: boolean; + }, +) { + const attributes = [ + `${REFRESH_COOKIE_NAME}=${encodeURIComponent(token)}`, + 'Path=/auth', + 'HttpOnly', + `Max-Age=${options.maxAgeSeconds}`, + `SameSite=${options.secure ? 'None' : 'Lax'}`, + ]; + + if (options.secure) { + attributes.push('Secure'); + } + + if (options.domain) { + attributes.push(`Domain=${options.domain}`); + } + + reply.header('Set-Cookie', attributes.join('; ')); +} + +export function clearRefreshCookie( + reply: FastifyReply, + options: { + domain?: string | undefined; + secure: boolean; + }, +) { + setRefreshCookie(reply, '', { + domain: options.domain, + maxAgeSeconds: 0, + secure: options.secure, + }); +} diff --git a/apps/api/src/lib/auth-crypto.test.ts b/apps/api/src/lib/auth-crypto.test.ts new file mode 100644 index 0000000..fbb54de --- /dev/null +++ b/apps/api/src/lib/auth-crypto.test.ts @@ -0,0 +1,104 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { JwtVerificationError, signAccessToken, verifyAccessToken } from './auth-crypto.js'; +import { PlatformRole } from '../generated/prisma/enums.js'; + +const jwtOptions = { + audience: 'hivelore-web', + issuer: 'hivelore', + secret: 'test-secret-that-is-long-enough-for-hmac', +}; + +describe('access JWTs', () => { + test('creates and validates necessary claims', () => { + const token = signAccessToken( + { + hiveUsername: 'alice', + normalizedHiveUsername: 'alice', + platformRole: PlatformRole.ADMIN, + sid: 'session-1', + sub: 'user-1', + }, + { + ...jwtOptions, + now: new Date('2026-08-01T00:00:00.000Z'), + ttlSeconds: 900, + }, + ); + + const claims = verifyAccessToken(token, { + ...jwtOptions, + now: new Date('2026-08-01T00:10:00.000Z'), + }); + + assert.equal(claims.sub, 'user-1'); + assert.equal(claims.sid, 'session-1'); + assert.equal(claims.normalizedHiveUsername, 'alice'); + assert.equal(claims.platformRole, PlatformRole.ADMIN); + }); + + test('rejects expired tokens', () => { + const token = signAccessToken( + { + hiveUsername: 'alice', + normalizedHiveUsername: 'alice', + platformRole: PlatformRole.USER, + sid: 'session-1', + sub: 'user-1', + }, + { + ...jwtOptions, + now: new Date('2026-08-01T00:00:00.000Z'), + ttlSeconds: 60, + }, + ); + + assert.throws( + () => + verifyAccessToken(token, { + ...jwtOptions, + now: new Date('2026-08-01T00:02:00.000Z'), + }), + JwtVerificationError, + ); + }); + + test('rejects invalid issuer and audience', () => { + const token = signAccessToken( + { + hiveUsername: 'alice', + normalizedHiveUsername: 'alice', + platformRole: PlatformRole.USER, + sid: 'session-1', + sub: 'user-1', + }, + { + ...jwtOptions, + now: new Date('2026-08-01T00:00:00.000Z'), + ttlSeconds: 900, + }, + ); + + assert.throws( + () => + verifyAccessToken(token, { + ...jwtOptions, + audience: 'other-app', + now: new Date('2026-08-01T00:01:00.000Z'), + }), + JwtVerificationError, + ); + }); + + test('rejects malformed token payloads', () => { + assert.throws( + () => + verifyAccessToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.not-json.signature', { + ...jwtOptions, + now: new Date('2026-08-01T00:01:00.000Z'), + }), + JwtVerificationError, + ); + }); +}); diff --git a/apps/api/src/lib/auth-crypto.ts b/apps/api/src/lib/auth-crypto.ts new file mode 100644 index 0000000..29f3763 --- /dev/null +++ b/apps/api/src/lib/auth-crypto.ts @@ -0,0 +1,136 @@ +import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto'; + +import { PlatformRole } from '../generated/prisma/enums.js'; + +function base64UrlEncode(input: Buffer | string) { + return Buffer.from(input).toString('base64url'); +} + +function base64UrlDecode(input: string) { + return Buffer.from(input, 'base64url').toString('utf8'); +} + +export function randomToken(byteLength = 32) { + return randomBytes(byteLength).toString('base64url'); +} + +export function sha256Hmac(value: string, secret: string) { + return createHmac('sha256', secret).update(value).digest('hex'); +} + +export function constantTimeEqual(left: string, right: string) { + const leftBuffer = Buffer.from(left); + const rightBuffer = Buffer.from(right); + + if (leftBuffer.length !== rightBuffer.length) { + return false; + } + + return timingSafeEqual(leftBuffer, rightBuffer); +} + +export type AccessTokenClaims = { + sub: string; + hiveUsername: string; + normalizedHiveUsername: string; + platformRole: PlatformRole; + sid: string; + iat: number; + exp: number; + iss: string; + aud: string; +}; + +export class JwtVerificationError extends Error { + constructor() { + super('Invalid access token.'); + } +} + +function parseJson(value: string): T { + try { + return JSON.parse(value) as T; + } catch { + throw new JwtVerificationError(); + } +} + +export function signAccessToken( + claims: Omit, + options: { + audience: string; + issuer: string; + secret: string; + ttlSeconds: number; + now?: Date; + }, +) { + const nowSeconds = Math.floor((options.now?.getTime() ?? Date.now()) / 1000); + const payload: AccessTokenClaims = { + ...claims, + aud: options.audience, + exp: nowSeconds + options.ttlSeconds, + iat: nowSeconds, + iss: options.issuer, + }; + const header = { + alg: 'HS256', + typ: 'JWT', + }; + const encodedHeader = base64UrlEncode(JSON.stringify(header)); + const encodedPayload = base64UrlEncode(JSON.stringify(payload)); + const signature = createHmac('sha256', options.secret) + .update(`${encodedHeader}.${encodedPayload}`) + .digest('base64url'); + + return `${encodedHeader}.${encodedPayload}.${signature}`; +} + +export function verifyAccessToken( + token: string, + options: { + audience: string; + issuer: string; + secret: string; + now?: Date; + }, +) { + const parts = token.split('.'); + + if (parts.length !== 3) { + throw new JwtVerificationError(); + } + + const [encodedHeader, encodedPayload, signature] = parts as [string, string, string]; + const expectedSignature = createHmac('sha256', options.secret) + .update(`${encodedHeader}.${encodedPayload}`) + .digest('base64url'); + + if (!constantTimeEqual(signature, expectedSignature)) { + throw new JwtVerificationError(); + } + + const header = parseJson<{ alg?: string; typ?: string }>(base64UrlDecode(encodedHeader)); + + if (header.alg !== 'HS256' || header.typ !== 'JWT') { + throw new JwtVerificationError(); + } + + const claims = parseJson(base64UrlDecode(encodedPayload)); + const nowSeconds = Math.floor((options.now?.getTime() ?? Date.now()) / 1000); + const platformRoles = new Set(Object.values(PlatformRole)); + + if ( + claims.iss !== options.issuer || + claims.aud !== options.audience || + claims.exp <= nowSeconds || + !claims.sub || + !claims.sid || + !claims.normalizedHiveUsername || + !platformRoles.has(claims.platformRole) + ) { + throw new JwtVerificationError(); + } + + return claims; +} diff --git a/apps/api/src/lib/auth-middleware.test.ts b/apps/api/src/lib/auth-middleware.test.ts new file mode 100644 index 0000000..3fd3ae8 --- /dev/null +++ b/apps/api/src/lib/auth-middleware.test.ts @@ -0,0 +1,99 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import type { FastifyRequest } from 'fastify'; + +import { PlatformRole } from '../generated/prisma/enums.js'; +import { signAccessToken } from './auth-crypto.js'; +import { authenticateRequest } from './auth-middleware.js'; + +const jwtOptions = { + audience: 'hivelore-web', + database: { + refreshSession: { + async findUnique(args: { where: { id: string }; select: unknown }) { + if (args.where.id !== 'session-1') { + return null; + } + + return { + expiresAt: new Date('2026-08-01T01:00:00.000Z'), + revokedAt: null, + userId: 'user-1', + }; + }, + }, + }, + issuer: 'hivelore', + jwtSecret: 'test-secret-that-is-long-enough-for-hmac', + now: new Date('2026-08-01T00:00:00.000Z'), +}; + +describe('auth middleware', () => { + test('decorates request.user from trusted JWT claims including platform role', async () => { + const token = signAccessToken( + { + hiveUsername: 'alice', + normalizedHiveUsername: 'alice', + platformRole: PlatformRole.ADMIN, + sid: 'session-1', + sub: 'user-1', + }, + { + audience: jwtOptions.audience, + issuer: jwtOptions.issuer, + secret: jwtOptions.jwtSecret, + ttlSeconds: 900, + }, + ); + const request = { + headers: { + authorization: `Bearer ${token}`, + }, + } as FastifyRequest; + + const user = await authenticateRequest(request, jwtOptions); + + assert.equal(user?.id, 'user-1'); + assert.equal(user?.platformRole, PlatformRole.ADMIN); + assert.equal(request.user?.platformRole, PlatformRole.ADMIN); + }); + + test('rejects missing or malformed bearer tokens', async () => { + const request = { + headers: { + authorization: 'Basic abc', + }, + } as FastifyRequest; + + assert.equal(await authenticateRequest(request, jwtOptions), null); + assert.equal(request.user, undefined); + }); + + test('rejects otherwise valid access tokens after session revocation', async () => { + const token = signAccessToken( + { + hiveUsername: 'alice', + normalizedHiveUsername: 'alice', + platformRole: PlatformRole.USER, + sid: 'revoked-session', + sub: 'user-1', + }, + { + audience: jwtOptions.audience, + issuer: jwtOptions.issuer, + now: jwtOptions.now, + secret: jwtOptions.jwtSecret, + ttlSeconds: 900, + }, + ); + const request = { + headers: { + authorization: `Bearer ${token}`, + }, + } as FastifyRequest; + + assert.equal(await authenticateRequest(request, jwtOptions), null); + assert.equal(request.user, undefined); + }); +}); diff --git a/apps/api/src/lib/auth-middleware.ts b/apps/api/src/lib/auth-middleware.ts new file mode 100644 index 0000000..4c88181 --- /dev/null +++ b/apps/api/src/lib/auth-middleware.ts @@ -0,0 +1,87 @@ +import type { FastifyReply, FastifyRequest, preHandlerHookHandler } from 'fastify'; + +import { verifyAccessToken } from './auth-crypto.js'; +import { isRefreshSessionActive, type SessionVerificationDatabase } from './auth-sessions.js'; +import type { AuthenticatedUser } from './world-authorization.js'; + +export function readBearerToken(request: FastifyRequest) { + const authorization = request.headers.authorization; + + if (!authorization) { + return null; + } + + const [scheme, token] = authorization.split(' '); + + if (scheme !== 'Bearer' || !token) { + return null; + } + + return token; +} + +export async function authenticateRequest( + request: FastifyRequest, + options: { + audience: string; + database: SessionVerificationDatabase; + issuer: string; + jwtSecret: string; + now?: Date; + }, +) { + const token = readBearerToken(request); + + if (!token) { + return null; + } + + try { + const claims = verifyAccessToken(token, { + audience: options.audience, + issuer: options.issuer, + secret: options.jwtSecret, + ...(options.now ? { now: options.now } : {}), + }); + + const hasActiveSession = await isRefreshSessionActive(options.database, { + sessionId: claims.sid, + userId: claims.sub, + ...(options.now ? { now: options.now } : {}), + }); + + if (!hasActiveSession) { + return null; + } + + const user: AuthenticatedUser = { + hiveUsername: claims.hiveUsername, + id: claims.sub, + normalizedHiveUsername: claims.normalizedHiveUsername, + platformRole: claims.platformRole, + }; + + request.user = user; + + return user; + } catch { + return null; + } +} + +export function requireSession(options: { + audience: string; + database: SessionVerificationDatabase; + issuer: string; + jwtSecret: string; +}): preHandlerHookHandler { + return async (request: FastifyRequest, reply: FastifyReply) => { + const user = await authenticateRequest(request, options); + + if (!user) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + }; +} diff --git a/apps/api/src/lib/auth-rate-limit-store.test.ts b/apps/api/src/lib/auth-rate-limit-store.test.ts new file mode 100644 index 0000000..681bd1d --- /dev/null +++ b/apps/api/src/lib/auth-rate-limit-store.test.ts @@ -0,0 +1,222 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import rateLimit from '@fastify/rate-limit'; +import Fastify from 'fastify'; + +import { AuthProvider } from '../generated/prisma/enums.js'; +import { registerAuthRoutes } from '../routes/auth.js'; +import { createPrismaRateLimitStore, extractRateLimitRouteInfo } from './auth-rate-limit-store.js'; + +function createDatabase() { + const buckets = new Map(); + + return { + authRateLimitBucket: { + async deleteMany(args: { where: { expiresAt: { lt: Date } } }) { + let count = 0; + + for (const [key, bucket] of buckets) { + if (bucket.expiresAt < args.where.expiresAt.lt) { + buckets.delete(key); + count += 1; + } + } + + return { count }; + }, + async findUnique(args: { select: { count: true; expiresAt: true }; where: { key: string } }) { + return buckets.get(args.where.key) ?? null; + }, + }, + async $queryRaw(_strings: TemplateStringsArray, ...values: unknown[]) { + const key = values[0] as string; + const nextExpiresAt = values[1] as Date; + const now = values[2] as Date; + const current = buckets.get(key); + const next = + !current || current.expiresAt <= now + ? { count: 1, expiresAt: nextExpiresAt } + : { count: current.count + 1, expiresAt: current.expiresAt }; + + buckets.set(key, next); + + return [next]; + }, + buckets, + }; +} + +function increment(store: { + incr( + key: string, + callback: (error: Error | null, result?: unknown) => void, + timeWindow: number, + ): void; +}) { + return new Promise<{ current: number; ttl: number }>((resolve, reject) => { + store.incr( + '127.0.0.1', + (error, result) => { + if (error) { + reject(error); + return; + } + + resolve(result as { current: number; ttl: number }); + }, + 60_000, + ); + }); +} + +function read(store: { + read( + key: string, + callback: (error: Error | null, result?: unknown) => void, + timeWindow: number, + ): void; +}) { + return new Promise<{ current: number; ttl: number }>((resolve, reject) => { + store.read( + '127.0.0.1', + (error, result) => { + if (error) { + reject(error); + return; + } + + resolve(result as { current: number; ttl: number }); + }, + 60_000, + ); + }); +} + +describe('Prisma auth rate-limit store', () => { + test('increments and reads counters from a shared database bucket', async () => { + const database = createDatabase(); + const Store = createPrismaRateLimitStore(database as never); + const store = new Store(); + + assert.equal((await increment(store)).current, 1); + assert.equal((await increment(store)).current, 2); + assert.equal((await read(store)).current, 2); + assert.equal(database.buckets.size, 1); + }); + + test('scopes counters by route child store', async () => { + const database = createDatabase(); + const Store = createPrismaRateLimitStore(database as never); + const store = new Store(); + const challengeStore = store.child({ + method: 'POST', + path: '/auth/challenge', + prefix: '', + url: '/auth/challenge', + } as never); + const verifyStore = store.child({ + method: 'POST', + path: '/auth/verify', + prefix: '', + url: '/auth/verify', + } as never); + + assert.equal((await increment(challengeStore)).current, 1); + assert.equal((await increment(verifyStore)).current, 1); + assert.equal(database.buckets.size, 2); + }); + + test('extracts nested Fastify routeInfo from child options', () => { + assert.deepEqual( + extractRateLimitRouteInfo({ + max: 40, + routeInfo: { + method: 'POST', + path: '/auth/refresh', + url: '/auth/refresh', + }, + } as never), + { + method: 'POST', + path: '/auth/refresh', + url: '/auth/refresh', + }, + ); + }); + + test('falls back safely when child options contain no route information', () => { + const routeInfo = extractRateLimitRouteInfo({} as never); + + assert.equal(routeInfo.method, undefined); + assert.equal(routeInfo.path, undefined); + assert.equal(routeInfo.url, undefined); + }); + + test('exhausting refresh does not rate-limit challenge', async () => { + const database = createDatabase(); + const Store = createPrismaRateLimitStore(database as never); + const app = Fastify(); + + await app.register(rateLimit, { + global: false, + skipOnError: false, + store: Store, + }); + await registerAuthRoutes(app, { + challengeDatabase: { + authChallenge: { + async create(args: { + data: { + challengeHash: string; + expiresAt: Date; + issuedAt: Date; + nonceHash: string; + normalizedHiveUsername: string; + provider: AuthProvider; + }; + select: { expiresAt: true; id: true }; + }) { + return { + expiresAt: args.data.expiresAt, + id: 'challenge-1', + }; + }, + async deleteMany() { + return { count: 0 }; + }, + }, + } as never, + signatureVerifier: { + async verifyPostingSignature() { + return false; + }, + }, + }); + + let refreshStatus = 0; + + for (let index = 0; index < 41; index += 1) { + const response = await app.inject({ + method: 'POST', + payload: {}, + url: '/auth/refresh', + }); + refreshStatus = response.statusCode; + } + + const challenge = await app.inject({ + method: 'POST', + payload: { + provider: 'keychain', + username: 'alice', + }, + url: '/auth/challenge', + }); + + assert.equal(refreshStatus, 429); + assert.equal(challenge.statusCode, 200, challenge.body); + assert.equal(challenge.json().hiveUsername, 'alice'); + await app.close(); + }); +}); diff --git a/apps/api/src/lib/auth-rate-limit-store.ts b/apps/api/src/lib/auth-rate-limit-store.ts new file mode 100644 index 0000000..1e5208b --- /dev/null +++ b/apps/api/src/lib/auth-rate-limit-store.ts @@ -0,0 +1,175 @@ +import type { PrismaClient } from '../generated/prisma/client.js'; + +type RateLimitBucketDatabase = Pick< + PrismaClient, + '$executeRaw' | '$queryRaw' | 'authRateLimitBucket' +>; + +type RateLimitResult = { + current: number; + ttl: number; +}; + +type RateLimitCallback = (error: Error | null, result?: RateLimitResult) => void; + +type RateLimitStoreOptions = { + nameSpace?: string | undefined; + routeInfo?: RateLimitRouteInfo | undefined; +}; + +type RateLimitRouteInfo = { + method?: unknown; + path?: string | undefined; + url?: string | undefined; +}; + +type RateLimitChildOptions = RateLimitRouteInfo & { + routeInfo?: RateLimitRouteInfo | undefined; +}; + +type RateLimitRow = { + count: number; + expiresAt: Date; +}; + +type RateLimitStore = { + child(routeOptions: RateLimitRouteInfo): RateLimitStore; + incr(key: string, callback: RateLimitCallback, timeWindow: number): void; + read(key: string, callback: RateLimitCallback, timeWindow: number): void; +}; + +type RateLimitStoreConstructor = new (options?: RateLimitStoreOptions) => RateLimitStore; + +const DEFAULT_NAMESPACE = 'hivelore-auth-rate-limit'; +const CLEANUP_INTERVAL_INCREMENTS = 100; + +export function extractRateLimitRouteInfo(options: RateLimitChildOptions): RateLimitRouteInfo { + const routeInfo = options.routeInfo ?? options; + + return { + method: routeInfo.method, + path: routeInfo.path, + url: routeInfo.url, + }; +} + +function routeScope(routeInfo: RateLimitStoreOptions['routeInfo']) { + if (!routeInfo) { + return 'global'; + } + + return `${String(routeInfo.method ?? 'ANY')}:${routeInfo.path ?? routeInfo.url ?? 'unknown'}`; +} + +function buildBucketKey(options: RateLimitStoreOptions, key: string) { + const namespace = options.nameSpace ?? DEFAULT_NAMESPACE; + + return `${namespace}:${routeScope(options.routeInfo)}:${key}`; +} + +export function createPrismaRateLimitStore( + database: RateLimitBucketDatabase, +): RateLimitStoreConstructor { + return class PrismaRateLimitStore { + cleanupCounter = 0; + + constructor(readonly options: RateLimitStoreOptions = {}) {} + + incr(key: string, callback: RateLimitCallback, timeWindow: number) { + void this.increment(key, timeWindow).then( + (result) => callback(null, result), + (error: unknown) => callback(error instanceof Error ? error : new Error(String(error))), + ); + } + + read(key: string, callback: RateLimitCallback, timeWindow: number) { + void this.get(key, timeWindow).then( + (result) => callback(null, result), + (error: unknown) => callback(error instanceof Error ? error : new Error(String(error))), + ); + } + + child(routeOptions: RateLimitChildOptions) { + return new PrismaRateLimitStore({ + ...this.options, + routeInfo: extractRateLimitRouteInfo(routeOptions), + }); + } + + async increment(key: string, timeWindow: number) { + const now = new Date(); + const nextExpiresAt = new Date(now.getTime() + timeWindow); + const bucketKey = buildBucketKey(this.options, key); + + await this.maybeDeleteExpiredBuckets(now); + + const rows = await database.$queryRaw` + INSERT INTO "AuthRateLimitBucket" ("key", "count", "expiresAt", "updatedAt") + VALUES (${bucketKey}, 1, ${nextExpiresAt}, ${now}) + ON CONFLICT ("key") DO UPDATE SET + "count" = CASE + WHEN "AuthRateLimitBucket"."expiresAt" <= ${now} THEN 1 + ELSE "AuthRateLimitBucket"."count" + 1 + END, + "expiresAt" = CASE + WHEN "AuthRateLimitBucket"."expiresAt" <= ${now} THEN ${nextExpiresAt} + ELSE "AuthRateLimitBucket"."expiresAt" + END, + "updatedAt" = ${now} + RETURNING "count", "expiresAt" + `; + const row = rows[0]; + + if (!row) { + throw new Error('Rate limit bucket update did not return a row.'); + } + + return toRateLimitResult(row, now); + } + + async get(key: string, timeWindow: number) { + const now = new Date(); + const bucket = await database.authRateLimitBucket.findUnique({ + where: { + key: buildBucketKey(this.options, key), + }, + select: { + count: true, + expiresAt: true, + }, + }); + + if (!bucket || bucket.expiresAt <= now) { + return { + current: 0, + ttl: timeWindow, + }; + } + + return toRateLimitResult(bucket, now); + } + + async maybeDeleteExpiredBuckets(now: Date) { + this.cleanupCounter += 1; + + if (this.cleanupCounter % CLEANUP_INTERVAL_INCREMENTS !== 0) { + return; + } + + await database.authRateLimitBucket.deleteMany({ + where: { + expiresAt: { + lt: now, + }, + }, + }); + } + }; +} + +function toRateLimitResult(row: Pick, now: Date) { + return { + current: row.count, + ttl: Math.max(0, row.expiresAt.getTime() - now.getTime()), + }; +} diff --git a/apps/api/src/lib/auth-sessions.test.ts b/apps/api/src/lib/auth-sessions.test.ts new file mode 100644 index 0000000..86443d4 --- /dev/null +++ b/apps/api/src/lib/auth-sessions.test.ts @@ -0,0 +1,261 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { PlatformRole } from '../generated/prisma/enums.js'; +import type { PrismaClient, RefreshSession, User } from '../generated/prisma/client.js'; +import { sha256Hmac, verifyAccessToken } from './auth-crypto.js'; +import { + issueSession, + RefreshTokenReuseError, + revokeRefreshToken, + rotateRefreshSession, + type SafeUser, +} from './auth-sessions.js'; + +const user: User = { + avatarUrl: null, + bio: null, + createdAt: new Date('2026-08-01T00:00:00.000Z'), + displayName: null, + hiveUsername: 'alice', + id: 'user-1', + normalizedHiveUsername: 'alice', + platformRole: PlatformRole.USER, + updatedAt: new Date('2026-08-01T00:00:00.000Z'), +}; + +const safeUser: SafeUser = { + avatarUrl: null, + displayName: null, + hiveUsername: 'alice', + id: 'user-1', + normalizedHiveUsername: 'alice', + platformRole: PlatformRole.USER, +}; + +const sessionOptions = { + accessTtlSeconds: 900, + audience: 'hivelore-web', + issuer: 'hivelore', + jwtSecret: 'test-secret-that-is-long-enough-for-hmac', + refreshSecret: 'test-secret-that-is-long-enough-for-hmac', + refreshTtlSeconds: 60 * 60, +}; + +type StoredRefreshSession = RefreshSession & { + user: User; +}; + +function createDatabase() { + const sessions = new Map(); + let nextId = 1; + + const database = { + refreshSession: { + async create(args: { + data: { + expiresAt: Date; + refreshTokenHash: string; + sessionFamilyId: string; + userId: string; + userAgent?: string; + ipAddress?: string; + }; + include?: { user: true }; + }) { + const session: StoredRefreshSession = { + createdAt: new Date('2026-08-01T00:00:00.000Z'), + expiresAt: args.data.expiresAt, + id: `session-${nextId}`, + ipAddress: args.data.ipAddress ?? null, + lastUsedAt: null, + refreshTokenHash: args.data.refreshTokenHash, + replacedById: null, + revokedAt: null, + rotatedAt: null, + sessionFamilyId: args.data.sessionFamilyId, + user, + userAgent: args.data.userAgent ?? null, + userId: args.data.userId, + }; + nextId += 1; + sessions.set(session.id, session); + + return args.include?.user ? session : (session as RefreshSession); + }, + async findUnique(args: { + where: { refreshTokenHash?: string; id?: string }; + include?: { user: true }; + select?: { + expiresAt?: true; + id?: true; + revokedAt?: true; + sessionFamilyId?: true; + userId?: true; + }; + }) { + const session = [...sessions.values()].find((candidate) => { + if (args.where.refreshTokenHash) { + return candidate.refreshTokenHash === args.where.refreshTokenHash; + } + + return candidate.id === args.where.id; + }); + + if (!session) { + return null; + } + + if (args.select) { + return { + ...(args.select.expiresAt ? { expiresAt: session.expiresAt } : {}), + ...(args.select.id ? { id: session.id } : {}), + ...(args.select.revokedAt ? { revokedAt: session.revokedAt } : {}), + ...(args.select.sessionFamilyId ? { sessionFamilyId: session.sessionFamilyId } : {}), + ...(args.select.userId ? { userId: session.userId } : {}), + }; + } + + return args.include?.user ? session : (session as RefreshSession); + }, + async update(args: { + where: { id: string }; + data: Partial< + Pick + >; + }) { + const session = sessions.get(args.where.id); + + if (!session) { + throw new Error('Missing session.'); + } + + Object.assign(session, args.data); + + return session; + }, + async updateMany(args: { + where: + | { sessionFamilyId: string; revokedAt: null } + | { + expiresAt: { gt: Date }; + id: string; + revokedAt: null; + rotatedAt: null; + }; + data: Partial< + Pick + >; + }) { + let count = 0; + + for (const session of sessions.values()) { + if ('sessionFamilyId' in args.where) { + if (session.sessionFamilyId !== args.where.sessionFamilyId || session.revokedAt) { + continue; + } + + Object.assign(session, args.data); + count += 1; + continue; + } + + if ( + session.id === args.where.id && + !session.revokedAt && + !session.rotatedAt && + session.expiresAt > args.where.expiresAt.gt + ) { + Object.assign(session, args.data); + count += 1; + } + } + + return { count }; + }, + }, + async $transaction(callback: (transaction: PrismaClient) => Promise) { + return callback(database as unknown as PrismaClient); + }, + sessions, + }; + + return database as unknown as PrismaClient & { sessions: Map }; +} + +describe('refresh sessions', () => { + test('issues access and refresh credentials', async () => { + const database = createDatabase(); + const issued = await issueSession(database, { + ...sessionOptions, + now: new Date('2026-08-01T00:00:00.000Z'), + user: safeUser, + }); + + const claims = verifyAccessToken(issued.accessToken, { + audience: sessionOptions.audience, + issuer: sessionOptions.issuer, + now: new Date('2026-08-01T00:01:00.000Z'), + secret: sessionOptions.jwtSecret, + }); + + assert.equal(claims.sub, user.id); + assert.equal(database.sessions.size, 1); + assert.equal( + [...database.sessions.values()][0]?.refreshTokenHash, + sha256Hmac(issued.refreshToken, sessionOptions.refreshSecret), + ); + }); + + test('rotates refresh tokens and rejects reuse by revoking the family', async () => { + const database = createDatabase(); + const issued = await issueSession(database, { + ...sessionOptions, + now: new Date('2026-08-01T00:00:00.000Z'), + user: safeUser, + }); + const rotated = await rotateRefreshSession(database, { + ...sessionOptions, + now: new Date('2026-08-01T00:05:00.000Z'), + refreshToken: issued.refreshToken, + }); + + assert.notEqual(rotated.refreshToken, issued.refreshToken); + assert.equal(database.sessions.size, 2); + + await assert.rejects( + () => + rotateRefreshSession(database, { + ...sessionOptions, + now: new Date('2026-08-01T00:06:00.000Z'), + refreshToken: issued.refreshToken, + }), + RefreshTokenReuseError, + ); + + assert.equal( + [...database.sessions.values()].every((session) => session.revokedAt), + true, + ); + }); + + test('logout revocation is idempotent', async () => { + const database = createDatabase(); + const issued = await issueSession(database, { + ...sessionOptions, + now: new Date('2026-08-01T00:00:00.000Z'), + user: safeUser, + }); + + await revokeRefreshToken(database, { + refreshSecret: sessionOptions.refreshSecret, + refreshToken: issued.refreshToken, + }); + await revokeRefreshToken(database, { + refreshSecret: sessionOptions.refreshSecret, + refreshToken: issued.refreshToken, + }); + + assert.equal([...database.sessions.values()][0]?.revokedAt instanceof Date, true); + }); +}); diff --git a/apps/api/src/lib/auth-sessions.ts b/apps/api/src/lib/auth-sessions.ts new file mode 100644 index 0000000..e4b170b --- /dev/null +++ b/apps/api/src/lib/auth-sessions.ts @@ -0,0 +1,343 @@ +import type { PlatformRole as PlatformRoleType } from '../generated/prisma/enums.js'; +import type { Prisma, PrismaClient, RefreshSession, User } from '../generated/prisma/client.js'; +import { randomToken, sha256Hmac, signAccessToken } from './auth-crypto.js'; + +export type SafeUser = { + id: string; + hiveUsername: string; + normalizedHiveUsername: string; + displayName: string | null; + avatarUrl: string | null; + platformRole: PlatformRoleType; +}; + +export type IssuedSession = { + accessToken: string; + refreshToken: string; + refreshSessionId: string; + user: SafeUser; +}; + +export class RefreshTokenReuseError extends Error { + constructor() { + super('Refresh token reuse detected.'); + } +} + +export class InvalidRefreshTokenError extends Error { + constructor() { + super('Invalid refresh token.'); + } +} + +function selectSafeUser(user: User): SafeUser { + return { + avatarUrl: user.avatarUrl, + displayName: user.displayName, + hiveUsername: user.hiveUsername, + id: user.id, + normalizedHiveUsername: user.normalizedHiveUsername, + platformRole: user.platformRole, + }; +} + +function buildAccessToken( + user: SafeUser, + refreshSessionId: string, + options: { + audience: string; + issuer: string; + jwtSecret: string; + ttlSeconds: number; + }, +) { + return signAccessToken( + { + hiveUsername: user.hiveUsername, + normalizedHiveUsername: user.normalizedHiveUsername, + platformRole: user.platformRole, + sid: refreshSessionId, + sub: user.id, + }, + { + audience: options.audience, + issuer: options.issuer, + secret: options.jwtSecret, + ttlSeconds: options.ttlSeconds, + }, + ); +} + +type UserProjectionDatabase = Pick; +type SessionIssueDatabase = Pick; +type SessionRotationDatabase = Pick; +type SessionRevocationDatabase = Pick; +export type SessionVerificationDatabase = { + refreshSession: { + findUnique(args: { + where: { + id: string; + }; + select: { + expiresAt: true; + revokedAt: true; + userId: true; + }; + }): Promise | null>; + }; +}; + +export async function upsertHiveUser( + database: UserProjectionDatabase, + input: { + normalizedHiveUsername: string; + }, +) { + const user = await database.user.upsert({ + where: { + normalizedHiveUsername: input.normalizedHiveUsername, + }, + update: { + hiveUsername: input.normalizedHiveUsername, + }, + create: { + hiveUsername: input.normalizedHiveUsername, + normalizedHiveUsername: input.normalizedHiveUsername, + }, + }); + + return selectSafeUser(user); +} + +export async function issueSession( + database: SessionIssueDatabase, + input: { + audience: string; + ipAddress?: string | undefined; + issuer: string; + jwtSecret: string; + refreshSecret: string; + refreshTtlSeconds: number; + accessTtlSeconds: number; + user: SafeUser; + userAgent?: string | undefined; + now?: Date; + }, +): Promise { + const now = input.now ?? new Date(); + const refreshToken = randomToken(48); + const sessionData = { + expiresAt: new Date(now.getTime() + input.refreshTtlSeconds * 1000), + refreshTokenHash: sha256Hmac(refreshToken, input.refreshSecret), + sessionFamilyId: randomToken(24), + userId: input.user.id, + ...(input.ipAddress ? { ipAddress: input.ipAddress } : {}), + ...(input.userAgent ? { userAgent: input.userAgent.slice(0, 300) } : {}), + }; + const refreshSession = await database.refreshSession.create({ + data: sessionData, + }); + + return { + accessToken: buildAccessToken(input.user, refreshSession.id, { + audience: input.audience, + issuer: input.issuer, + jwtSecret: input.jwtSecret, + ttlSeconds: input.accessTtlSeconds, + }), + refreshSessionId: refreshSession.id, + refreshToken, + user: input.user, + }; +} + +export async function rotateRefreshSession( + database: SessionRotationDatabase, + input: { + audience: string; + issuer: string; + jwtSecret: string; + refreshSecret: string; + refreshToken: string; + refreshTtlSeconds: number; + accessTtlSeconds: number; + now?: Date; + }, +) { + const now = input.now ?? new Date(); + const tokenHash = sha256Hmac(input.refreshToken, input.refreshSecret); + + return database.$transaction(async (transaction: Prisma.TransactionClient) => { + const session = await transaction.refreshSession.findUnique({ + where: { + refreshTokenHash: tokenHash, + }, + include: { + user: true, + }, + }); + + if (!session) { + throw new InvalidRefreshTokenError(); + } + + if (session.rotatedAt || session.revokedAt) { + await revokeSessionFamily(transaction, session.sessionFamilyId, now); + throw new RefreshTokenReuseError(); + } + + if (session.expiresAt <= now) { + await transaction.refreshSession.update({ + where: { + id: session.id, + }, + data: { + revokedAt: now, + }, + }); + throw new InvalidRefreshTokenError(); + } + + const claimed = await transaction.refreshSession.updateMany({ + where: { + expiresAt: { + gt: now, + }, + id: session.id, + revokedAt: null, + rotatedAt: null, + }, + data: { + lastUsedAt: now, + revokedAt: now, + rotatedAt: now, + }, + }); + + if (claimed.count !== 1) { + await revokeSessionFamily(transaction, session.sessionFamilyId, now); + throw new RefreshTokenReuseError(); + } + + const refreshToken = randomToken(48); + const replacement = await transaction.refreshSession.create({ + data: { + expiresAt: new Date(now.getTime() + input.refreshTtlSeconds * 1000), + refreshTokenHash: sha256Hmac(refreshToken, input.refreshSecret), + sessionFamilyId: session.sessionFamilyId, + userAgent: session.userAgent, + userId: session.userId, + }, + include: { + user: true, + }, + }); + + await transaction.refreshSession.update({ + where: { + id: session.id, + }, + data: { + replacedById: replacement.id, + }, + }); + + const user = selectSafeUser(replacement.user); + + return { + accessToken: buildAccessToken(user, replacement.id, { + audience: input.audience, + issuer: input.issuer, + jwtSecret: input.jwtSecret, + ttlSeconds: input.accessTtlSeconds, + }), + refreshSessionId: replacement.id, + refreshToken, + user, + }; + }); +} + +export async function revokeRefreshToken( + database: SessionRevocationDatabase, + input: { + refreshSecret: string; + refreshToken: string; + revokeFamily?: boolean; + now?: Date; + }, +) { + const now = input.now ?? new Date(); + const session = await database.refreshSession.findUnique({ + where: { + refreshTokenHash: sha256Hmac(input.refreshToken, input.refreshSecret), + }, + select: { + id: true, + sessionFamilyId: true, + }, + }); + + if (!session) { + return; + } + + if (input.revokeFamily) { + await revokeSessionFamily(database, session.sessionFamilyId, now); + return; + } + + await database.refreshSession.update({ + where: { + id: session.id, + }, + data: { + revokedAt: now, + }, + }); +} + +async function revokeSessionFamily( + database: SessionRevocationDatabase, + sessionFamilyId: string, + now: Date, +) { + await database.refreshSession.updateMany({ + where: { + sessionFamilyId, + revokedAt: null, + }, + data: { + revokedAt: now, + }, + }); +} + +export function isRefreshSessionValid(session: Pick) { + return !session.revokedAt && session.expiresAt > new Date(); +} + +export async function isRefreshSessionActive( + database: SessionVerificationDatabase, + input: { + sessionId: string; + userId: string; + now?: Date; + }, +) { + const now = input.now ?? new Date(); + const session = await database.refreshSession.findUnique({ + where: { + id: input.sessionId, + }, + select: { + expiresAt: true, + revokedAt: true, + userId: true, + }, + }); + + return Boolean( + session && session.userId === input.userId && !session.revokedAt && session.expiresAt > now, + ); +} diff --git a/apps/api/src/lib/canon-voting-concurrency.test.ts b/apps/api/src/lib/canon-voting-concurrency.test.ts new file mode 100644 index 0000000..ea7ce56 --- /dev/null +++ b/apps/api/src/lib/canon-voting-concurrency.test.ts @@ -0,0 +1,223 @@ +import assert from 'node:assert/strict'; +import { test } from 'node:test'; + +import { PrismaClient } from '../generated/prisma/client.js'; +import { + PlatformRole, + ProposalDecisionOutcome, + ProposalStatus, + ProposalType, + WorldAuditAction, + WorldRole, +} from '../generated/prisma/enums.js'; +import { confirmCanonTransaction, CanonVotingError } from './canon-voting.js'; +import { hashCanonicalJson } from './canon-voting-policy.js'; +import { HIVELORE_CUSTOM_JSON_ID } from './hive/constants.js'; +import { buildHiveLoreCustomJsonOperation } from './hive/operations.js'; +import { + createPrismaClient, + testDatabaseAdminUrl, + withDisposablePrismaDatabase, +} from '../test/integration-db.js'; + +function createBarrier(parties: number) { + let arrived = 0; + let release!: () => void; + const ready = new Promise((resolve) => { + release = resolve; + }); + + return async () => { + arrived += 1; + + if (arrived === parties) { + release(); + } + + await ready; + }; +} + +const decisionPayload = { + counts: { + alternateTimeline: 0, + approve: 7, + needsRevision: 0, + reject: 3, + total: 10, + }, + eventType: 'canon_decision', + outcome: ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION, + proposalId: 'proposal-race', + worldId: 'world-race', +}; + +function confirmedOperation(transactionId: string) { + return { + blockNumber: BigInt(120), + blockchainTimestamp: new Date('2026-08-12T12:05:00.000Z'), + operation: buildHiveLoreCustomJsonOperation({ + action: 'canon_approval', + entityId: 'decision-race', + entityType: 'CANON_DECISION', + payload: decisionPayload, + proposalId: 'proposal-race', + signer: 'mira-vale.dev', + worldId: 'world-race', + }), + operationIndex: 0, + transactionId, + }; +} + +async function seedConfirmedProposal(database: PrismaClient) { + await database.user.create({ + data: { + hiveUsername: 'mira-vale.dev', + id: 'author-race', + normalizedHiveUsername: 'mira-vale.dev', + platformRole: PlatformRole.USER, + }, + }); + await database.world.create({ + data: { + description: 'Race test world', + founderId: 'author-race', + id: 'world-race', + slug: 'race-test-world', + title: 'Race Test World', + }, + }); + await database.worldMembership.create({ + data: { + id: 'membership-race', + role: WorldRole.CONTRIBUTOR, + userId: 'author-race', + worldId: 'world-race', + }, + }); + await database.proposal.create({ + data: { + authorId: 'author-race', + contentHash: 'content-hash', + decidedAt: new Date('2026-08-12T12:00:00.000Z'), + id: 'proposal-race', + proposalType: ProposalType.ADD_LORE, + proposedContent: { text: 'canon proposal' }, + status: ProposalStatus.APPROVED_FOR_PUBLICATION, + summary: 'Race proposal', + title: 'Race proposal', + votingEndsAt: new Date('2026-08-12T12:00:00.000Z'), + votingStartedAt: new Date('2026-08-10T12:00:00.000Z'), + worldId: 'world-race', + }, + }); + await database.proposalDecision.create({ + data: { + aiWarningAcknowledged: false, + alternateTimelineCount: 0, + approvalDenominator: 10, + approvalNumerator: 7, + approvalPercentageBps: 7000, + approvalThresholdBps: 7000, + approveCount: 7, + contentHash: 'content-hash', + customJsonId: HIVELORE_CUSTOM_JSON_ID, + decidedAt: new Date('2026-08-12T12:00:00.000Z'), + decisionPayload, + decisionPayloadHash: hashCanonicalJson(decisionPayload), + expectedSigner: 'mira-vale.dev', + id: 'decision-race', + minimumVotes: 5, + needsRevisionCount: 0, + outcome: ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION, + payloadSchemaVersion: 2, + proposalId: 'proposal-race', + rejectCount: 3, + rulesVersion: 'canon-voting-mvp-2026-08-12', + totalVotes: 10, + votingWindowHours: 48, + }, + }); +} + +test( + 'canon decision confirmation is atomic across concurrent PostgreSQL clients', + { skip: !testDatabaseAdminUrl ? 'TEST_DATABASE_ADMIN_URL is not configured.' : false }, + async () => { + await withDisposablePrismaDatabase('hivelore_confirm_race', async (seedClient, directUrl) => { + await seedConfirmedProposal(seedClient); + const firstClient = createPrismaClient(directUrl); + const secondClient = createPrismaClient(directUrl); + const synchronizeLookup = createBarrier(2); + + const first = confirmCanonTransaction(firstClient, { + actorId: 'author-race', + hafClient: {} as never, + hiveBroadcaster: { + async confirmTransactionOperation() { + await synchronizeLookup(); + return confirmedOperation('tx-race-a'); + }, + } as never, + operationIndex: 0, + proposalId: 'proposal-race', + transactionId: 'tx-race-a', + worldId: 'world-race', + }); + const second = confirmCanonTransaction(secondClient, { + actorId: 'author-race', + hafClient: {} as never, + hiveBroadcaster: { + async confirmTransactionOperation() { + await synchronizeLookup(); + return confirmedOperation('tx-race-b'); + }, + } as never, + operationIndex: 0, + proposalId: 'proposal-race', + transactionId: 'tx-race-b', + worldId: 'world-race', + }); + + const results = await Promise.allSettled([first, second]); + const fulfilled = results.filter((result) => result.status === 'fulfilled'); + const rejected = results.filter((result) => result.status === 'rejected'); + + assert.equal(fulfilled.length, 1); + assert.equal(rejected.length, 1); + assert.ok( + rejected[0]?.status === 'rejected' && + rejected[0].reason instanceof CanonVotingError && + rejected[0].reason.code === 'DECISION_ALREADY_CONFIRMED', + ); + + const verificationClient = createPrismaClient(directUrl); + const [decision, eventCount, auditCount] = await Promise.all([ + verificationClient.proposalDecision.findUnique({ + where: { + id: 'decision-race', + }, + }), + verificationClient.hiveEvent.count(), + verificationClient.worldAuditLog.count({ + where: { + action: WorldAuditAction.CANON_DECISION_CONFIRMED, + }, + }), + ]); + + assert.ok(decision?.transactionId === 'tx-race-a' || decision?.transactionId === 'tx-race-b'); + assert.equal(decision?.operationIndex, 0); + assert.ok(decision?.hiveEventId); + assert.equal(eventCount, 1); + assert.equal(auditCount, 1); + + await Promise.all([ + firstClient.$disconnect(), + secondClient.$disconnect(), + verificationClient.$disconnect(), + ]); + }); + }, +); diff --git a/apps/api/src/lib/canon-voting-policy.test.ts b/apps/api/src/lib/canon-voting-policy.test.ts new file mode 100644 index 0000000..3a315cd --- /dev/null +++ b/apps/api/src/lib/canon-voting-policy.test.ts @@ -0,0 +1,219 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { ProposalDecisionOutcome, VoteChoice } from '../generated/prisma/enums.js'; +import { + addVotingWindow, + CANON_VOTING_RULES, + decideCanonOutcome, + getVotingWindowState, + hashCanonicalJson, + tallyCanonVotes, +} from './canon-voting-policy.js'; + +const startedAt = new Date('2026-08-10T00:00:00.000Z'); +const votingEndsAt = addVotingWindow(startedAt); +const afterEnd = new Date(votingEndsAt.getTime() + 1); + +function votes(...choices: VoteChoice[]) { + return choices.map((choice) => ({ choice })); +} + +function voterVotes(...entries: Array<[string, VoteChoice]>) { + return entries.map(([voterId, choice]) => ({ choice, voterId })); +} + +describe('canon voting policy', () => { + test('uses a 48 hour voting window and does not decide before the end', () => { + assert.equal(votingEndsAt.toISOString(), '2026-08-12T00:00:00.000Z'); + assert.equal( + getVotingWindowState({ + now: new Date(votingEndsAt.getTime() - 1), + votingEndsAt, + }), + 'BEFORE_END', + ); + assert.equal(getVotingWindowState({ now: votingEndsAt, votingEndsAt }), 'AT_OR_AFTER_END'); + assert.equal( + decideCanonOutcome({ + now: new Date(votingEndsAt.getTime() - 1), + tally: tallyCanonVotes(votes(VoteChoice.APPROVE, VoteChoice.APPROVE)), + votingEndsAt, + }), + null, + ); + }); + + test('exactly five votes and exactly 70 percent approval passes at the window boundary', () => { + const tally = tallyCanonVotes( + votes( + VoteChoice.APPROVE, + VoteChoice.APPROVE, + VoteChoice.APPROVE, + VoteChoice.APPROVE, + VoteChoice.APPROVE, + VoteChoice.APPROVE, + VoteChoice.APPROVE, + VoteChoice.REJECT, + VoteChoice.REJECT, + VoteChoice.REJECT, + ), + ); + + assert.equal(tally.totalVotes, 10); + assert.equal(tally.approvalPercentageBps, CANON_VOTING_RULES.approvalThresholdBps); + assert.equal( + decideCanonOutcome({ now: votingEndsAt, tally, votingEndsAt }), + ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION, + ); + }); + + test('fewer than five votes fails even at 100 percent approval', () => { + const tally = tallyCanonVotes( + votes(VoteChoice.APPROVE, VoteChoice.APPROVE, VoteChoice.APPROVE, VoteChoice.APPROVE), + ); + + assert.equal(tally.approvalPercentageBps, 10_000); + assert.equal( + decideCanonOutcome({ now: afterEnd, tally, votingEndsAt }), + ProposalDecisionOutcome.REJECTED, + ); + }); + + test('zero approve produces zero percent instead of NaN', () => { + const tally = tallyCanonVotes( + votes(VoteChoice.NEEDS_REVISION, VoteChoice.NEEDS_REVISION, VoteChoice.ALTERNATE_TIMELINE), + ); + + assert.equal(tally.totalVotes, 3); + assert.equal(tally.approvalDenominator, 3); + assert.equal(tally.approvalPercentageBps, 0); + assert.equal( + decideCanonOutcome({ now: afterEnd, tally, votingEndsAt }), + ProposalDecisionOutcome.NEEDS_REVISION, + ); + }); + + test('revision and alternate votes count toward participation and approval denominator', () => { + const tally = tallyCanonVotes( + votes( + VoteChoice.APPROVE, + VoteChoice.REJECT, + VoteChoice.NEEDS_REVISION, + VoteChoice.ALTERNATE_TIMELINE, + VoteChoice.ALTERNATE_TIMELINE, + ), + ); + + assert.equal(tally.totalVotes, 5); + assert.equal(tally.approvalDenominator, 5); + assert.equal(tally.approvalNumerator, 1); + assert.equal(tally.approvalPercentageBps, 2_000); + }); + + test('constructive dissent prevents approval instead of disappearing from the denominator', () => { + const tally = tallyCanonVotes( + votes( + VoteChoice.APPROVE, + VoteChoice.NEEDS_REVISION, + VoteChoice.NEEDS_REVISION, + VoteChoice.NEEDS_REVISION, + VoteChoice.NEEDS_REVISION, + ), + ); + + assert.equal(tally.totalVotes, 5); + assert.equal(tally.approvalDenominator, 5); + assert.equal(tally.approvalPercentageBps, 2_000); + assert.equal( + decideCanonOutcome({ now: afterEnd, tally, votingEndsAt }), + ProposalDecisionOutcome.NEEDS_REVISION, + ); + }); + + test('uses deterministic failed-outcome plurality with stable tie order', () => { + assert.equal( + decideCanonOutcome({ + now: afterEnd, + tally: tallyCanonVotes( + votes(VoteChoice.NEEDS_REVISION, VoteChoice.ALTERNATE_TIMELINE, VoteChoice.REJECT), + ), + votingEndsAt, + }), + ProposalDecisionOutcome.NEEDS_REVISION, + ); + + assert.equal( + decideCanonOutcome({ + now: afterEnd, + tally: tallyCanonVotes( + votes(VoteChoice.ALTERNATE_TIMELINE, VoteChoice.ALTERNATE_TIMELINE, VoteChoice.REJECT), + ), + votingEndsAt, + }), + ProposalDecisionOutcome.ALTERNATE_TIMELINE, + ); + }); + + test('stale base canon conflict is surfaced before applying a normal outcome', () => { + assert.equal( + decideCanonOutcome({ + now: afterEnd, + staleBaseAtDecision: true, + tally: tallyCanonVotes( + votes( + VoteChoice.APPROVE, + VoteChoice.APPROVE, + VoteChoice.APPROVE, + VoteChoice.APPROVE, + VoteChoice.APPROVE, + ), + ), + votingEndsAt, + }), + ProposalDecisionOutcome.STALE_BASE_CONFLICT, + ); + }); + + test('canonical json hashing is deterministic across object key order', () => { + assert.equal(hashCanonicalJson({ b: 2, a: 1 }), hashCanonicalJson({ a: 1, b: 2 })); + }); + + test('excludes proposal author votes from approval math and participation', () => { + const tally = tallyCanonVotes( + voterVotes( + ['author-1', VoteChoice.APPROVE], + ['reader-1', VoteChoice.APPROVE], + ['reader-2', VoteChoice.APPROVE], + ['reader-3', VoteChoice.APPROVE], + ['reader-4', VoteChoice.REJECT], + ['reader-5', VoteChoice.REJECT], + ), + { excludeVoterIds: new Set(['author-1']) }, + ); + + assert.equal(tally.totalVotes, 5); + assert.equal(tally.approve, 3); + assert.equal(tally.reject, 2); + assert.equal(tally.approvalPercentageBps, 6_000); + }); + + test('legacy author votes cannot satisfy the five-vote minimum', () => { + const tally = tallyCanonVotes( + voterVotes( + ['author-1', VoteChoice.APPROVE], + ['reader-1', VoteChoice.APPROVE], + ['reader-2', VoteChoice.APPROVE], + ['reader-3', VoteChoice.APPROVE], + ['reader-4', VoteChoice.APPROVE], + ), + { excludeVoterIds: new Set(['author-1']) }, + ); + + assert.equal(tally.totalVotes, 4); + assert.equal( + decideCanonOutcome({ now: afterEnd, tally, votingEndsAt }), + ProposalDecisionOutcome.REJECTED, + ); + }); +}); diff --git a/apps/api/src/lib/canon-voting-policy.ts b/apps/api/src/lib/canon-voting-policy.ts new file mode 100644 index 0000000..a035dc5 --- /dev/null +++ b/apps/api/src/lib/canon-voting-policy.ts @@ -0,0 +1,164 @@ +import { createHash } from 'node:crypto'; + +import { ProposalDecisionOutcome, VoteChoice } from '../generated/prisma/enums.js'; + +export const CANON_VOTING_RULES = { + approvalThresholdBps: 7_000, + minimumVotes: 5, + payloadSchemaVersion: 2, + rulesVersion: 'canon-voting-mvp-2026-08-12', + votingWindowHours: 48, +} as const; + +export type CanonVoteCounts = { + approve: number; + reject: number; + needsRevision: number; + alternateTimeline: number; +}; + +export type CanonTally = CanonVoteCounts & { + approvalDenominator: number; + approvalNumerator: number; + approvalPercentageBps: number; + totalVotes: number; +}; + +export type CanonVotingWindowState = 'BEFORE_END' | 'AT_OR_AFTER_END'; + +export function addVotingWindow(startedAt: Date) { + return new Date(startedAt.getTime() + CANON_VOTING_RULES.votingWindowHours * 60 * 60 * 1_000); +} + +export function getVotingWindowState(input: { now: Date; votingEndsAt: Date }) { + return input.now.getTime() < input.votingEndsAt.getTime() ? 'BEFORE_END' : 'AT_OR_AFTER_END'; +} + +export function tallyCanonVotes( + votes: Array<{ choice: VoteChoice; voterId?: string | null }>, + options: { excludeVoterIds?: ReadonlySet } = {}, +): CanonTally { + const counts: CanonVoteCounts = { + alternateTimeline: 0, + approve: 0, + needsRevision: 0, + reject: 0, + }; + + for (const vote of votes) { + if (vote.voterId && options.excludeVoterIds?.has(vote.voterId)) { + continue; + } + + if (vote.choice === VoteChoice.APPROVE) { + counts.approve += 1; + } else if (vote.choice === VoteChoice.REJECT) { + counts.reject += 1; + } else if (vote.choice === VoteChoice.NEEDS_REVISION) { + counts.needsRevision += 1; + } else if (vote.choice === VoteChoice.ALTERNATE_TIMELINE) { + counts.alternateTimeline += 1; + } + } + + const approvalDenominator = + counts.approve + counts.reject + counts.needsRevision + counts.alternateTimeline; + const totalVotes = approvalDenominator; + const approvalPercentageBps = + approvalDenominator > 0 ? Math.floor((counts.approve * 10_000) / approvalDenominator) : 0; + + return { + ...counts, + approvalDenominator, + approvalNumerator: counts.approve, + approvalPercentageBps, + totalVotes, + }; +} + +export function decideCanonOutcome(input: { + staleBaseAtDecision?: boolean; + tally: CanonTally; + votingEndsAt: Date; + now: Date; +}) { + if (getVotingWindowState(input) === 'BEFORE_END') { + return null; + } + + if (input.staleBaseAtDecision) { + return ProposalDecisionOutcome.STALE_BASE_CONFLICT; + } + + const passesApproval = + input.tally.totalVotes >= CANON_VOTING_RULES.minimumVotes && + input.tally.approvalPercentageBps >= CANON_VOTING_RULES.approvalThresholdBps; + + if (passesApproval) { + return ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION; + } + + const feedbackChoices = [ + { + choice: ProposalDecisionOutcome.NEEDS_REVISION, + count: input.tally.needsRevision, + rank: 1, + }, + { + choice: ProposalDecisionOutcome.ALTERNATE_TIMELINE, + count: input.tally.alternateTimeline, + rank: 2, + }, + { + choice: ProposalDecisionOutcome.REJECTED, + count: input.tally.reject, + rank: 3, + }, + ].sort((left, right) => right.count - left.count || left.rank - right.rank); + + if (feedbackChoices[0] && feedbackChoices[0].count > 0) { + return feedbackChoices[0].choice; + } + + return ProposalDecisionOutcome.REJECTED; +} + +export function proposalStatusForDecision(outcome: ProposalDecisionOutcome) { + if (outcome === ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION) { + return 'APPROVED_FOR_PUBLICATION' as const; + } + + if (outcome === ProposalDecisionOutcome.ALTERNATE_TIMELINE) { + return 'ALTERNATE_TIMELINE' as const; + } + + if ( + outcome === ProposalDecisionOutcome.NEEDS_REVISION || + outcome === ProposalDecisionOutcome.STALE_BASE_CONFLICT + ) { + return 'NEEDS_REVISION' as const; + } + + return 'REJECTED' as const; +} + +export function stableStringify(value: unknown): string { + if (Array.isArray(value)) { + return `[${value.map(stableStringify).join(',')}]`; + } + + if (value && typeof value === 'object') { + const record = value as Record; + + return `{${Object.keys(record) + .sort() + .map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`) + .join(',')}}`; + } + + return JSON.stringify(value); +} + +export function hashCanonicalJson(value: unknown) { + return createHash('sha256').update(stableStringify(value), 'utf8').digest('hex'); +} diff --git a/apps/api/src/lib/canon-voting.test.ts b/apps/api/src/lib/canon-voting.test.ts new file mode 100644 index 0000000..d994a65 --- /dev/null +++ b/apps/api/src/lib/canon-voting.test.ts @@ -0,0 +1,788 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { + ProposalDecisionOutcome, + ProposalStatus, + VoteChoice, + WorldRole, +} from '../generated/prisma/enums.js'; +import { HIVELORE_CUSTOM_JSON_ID } from './hive/constants.js'; +import { buildHiveLoreCustomJsonOperation } from './hive/operations.js'; +import { + acknowledgeProposalAiWarning, + CanonVotingError, + castCanonVote, + confirmCanonTransaction, + createCanonTransactionOperation, + finalizeCanonDecision, + getProposalDetail, +} from './canon-voting.js'; +import { hashCanonicalJson } from './canon-voting-policy.js'; + +const decisionPayload = { + eventType: 'canon_decision', + proposalId: 'proposal-1', + worldId: 'world-1', + outcome: ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION, + counts: { + alternateTimeline: 0, + approve: 7, + needsRevision: 0, + reject: 3, + total: 10, + }, +}; + +function createDecision(overrides: Record = {}) { + return { + aiWarningAcknowledged: false, + aiWarningSummary: null, + alternateTimelineCount: 0, + approvalDenominator: 10, + approvalNumerator: 7, + approvalPercentageBps: 7000, + approvalThresholdBps: 7000, + approveCount: 7, + baseCanonVersionId: null, + blockchainTimestamp: null, + blockNumber: null, + branchBaseLoreEntryId: null, + branchLabel: null, + branchParentProposalId: null, + conflictMetadata: null, + contentHash: 'content-hash', + createdAt: new Date('2026-08-10T12:00:00.000Z'), + customJsonId: HIVELORE_CUSTOM_JSON_ID, + decidedAt: new Date('2026-08-12T12:00:00.000Z'), + decisionPayload, + decisionPayloadHash: hashCanonicalJson(decisionPayload), + expectedSigner: 'mira-vale.dev', + hiveEventId: null, + id: 'decision-1', + minimumVotes: 5, + needsRevisionCount: 0, + operationIndex: null, + outcome: ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION, + payloadSchemaVersion: 1, + proposalId: 'proposal-1', + rejectCount: 3, + rulesVersion: 'canon-voting-mvp-2026-08-10', + staleBaseAtDecision: false, + totalVotes: 10, + transactionId: null, + updatedAt: new Date('2026-08-12T12:00:00.000Z'), + votingWindowHours: 48, + ...overrides, + }; +} + +function createOperation(input: { + authority?: 'active' | 'posting'; + proposalId?: string; + signer?: string; + transactionId?: string; +}) { + return { + block_num: 100, + operation_id: 0, + operation: buildHiveLoreCustomJsonOperation({ + action: 'canon_approval', + authority: input.authority ?? 'posting', + entityId: 'decision-1', + entityType: 'CANON_DECISION', + payload: decisionPayload, + proposalId: input.proposalId ?? 'proposal-1', + signer: input.signer ?? 'mira-vale.dev', + worldId: 'world-1', + }), + timestamp: '2026-08-12T12:05:00.000Z', + transaction_id: input.transactionId ?? 'tx-valid', + }; +} + +type ConfirmationMembership = { + revokedAt: Date | null; + role: WorldRole; + userId: string; + worldId: string; +}; + +function createDatabase( + decision = createDecision(), + memberships: ConfirmationMembership[] = [ + { + revokedAt: null, + role: WorldRole.CONTRIBUTOR, + userId: 'author-1', + worldId: 'world-1', + }, + ], +) { + const auditLogs: unknown[] = []; + const events: unknown[] = []; + const proposal = { + author: { + hiveUsername: 'mira-vale.dev', + id: 'author-1', + }, + authorId: 'author-1', + decision, + id: 'proposal-1', + worldId: 'world-1', + }; + + const database = { + hiveEvent: { + async upsert(args: { + create: { id?: string; operationIndex: number; transactionId: string }; + }) { + const event = { + id: `event-${events.length + 1}`, + ...args.create, + }; + events.push(event); + return event; + }, + }, + proposal: { + async findFirst(args: { where: { id: string; worldId: string } }) { + if (args.where.id !== proposal.id || args.where.worldId !== proposal.worldId) { + return null; + } + + return proposal; + }, + }, + proposalDecision: { + async findUnique() { + return decision; + }, + async update(args: { data: Record }) { + Object.assign(decision, args.data); + return decision; + }, + async updateMany(args: { + data: Record; + where: { hiveEventId?: null; id: string; operationIndex: null; transactionId: null }; + }) { + if ( + args.where.id !== decision.id || + ('hiveEventId' in args.where && decision.hiveEventId !== null) || + decision.operationIndex !== null || + decision.transactionId !== null + ) { + return { count: 0 }; + } + + Object.assign(decision, args.data); + return { count: 1 }; + }, + }, + worldMembership: { + async findUnique(args: { + where: { revokedAt: null; worldId_userId: { userId: string; worldId: string } }; + }) { + return ( + memberships.find( + (membership) => + membership.userId === args.where.worldId_userId.userId && + membership.worldId === args.where.worldId_userId.worldId && + membership.revokedAt === null, + ) ?? null + ); + }, + }, + worldAuditLog: { + async create(args: { data: unknown }) { + auditLogs.push(args.data); + return args.data; + }, + }, + $transaction(callback: (transaction: unknown) => Promise) { + return callback(database); + }, + }; + + return { + auditLogs, + database, + decision, + events, + }; +} + +function createHafClient(row: unknown) { + return { + async searchBlocks() { + return { + operations: [row], + }; + }, + }; +} + +const votingStartedAt = new Date('2026-08-10T12:00:00.000Z'); +const votingEndsAt = new Date('2026-08-12T12:00:00.000Z'); +const afterVotingEnds = new Date('2026-08-12T12:01:00.000Z'); + +type ServiceVote = { + choice: VoteChoice; + createdAt: Date; + id: string; + proposalId: string; + updatedAt: Date; + voterId: string; +}; + +type ServiceProposal = Record & { + aiReports: Array<{ findings: unknown; summary: string | null }>; + aiWarningAcknowledgedAt: Date | null; + authorId: string; + decision: unknown | null; + id: string; + votes: ServiceVote[]; + worldId: string; +}; + +function createServiceProposal(overrides: Partial = {}): ServiceProposal { + return { + aiReports: [], + aiWarningAcknowledgedAt: null, + approvedAt: null, + author: { + hiveUsername: 'mira-vale.dev', + id: 'author-1', + }, + authorId: 'author-1', + baseCanonVersionId: null, + branchBaseLoreEntryId: null, + branchLabel: null, + branchParentProposalId: null, + conflictMetadata: null, + contentHash: 'content-hash', + decidedAt: null, + decision: null, + id: 'proposal-1', + proposedContent: { text: 'canon proposal' }, + proposalType: 'LORE_ENTRY', + rejectedAt: null, + staleBaseAtDecision: false, + status: ProposalStatus.VOTING, + submittedAt: votingStartedAt, + summary: 'A proposal', + title: 'Proposal', + votes: [], + votingEndsAt, + votingStartedAt, + world: { + id: 'world-1', + title: 'World', + }, + worldId: 'world-1', + ...overrides, + }; +} + +function createVote(voterId: string, choice: VoteChoice = VoteChoice.APPROVE): ServiceVote { + return { + choice, + createdAt: votingStartedAt, + id: `vote-${voterId}`, + proposalId: 'proposal-1', + updatedAt: votingStartedAt, + voterId, + }; +} + +function createServiceDatabase(proposal = createServiceProposal()) { + const auditLogs: unknown[] = []; + const decisions: unknown[] = []; + + const database = { + appVote: { + async upsert(args: { + create: { choice: VoteChoice; proposalId: string; voterId: string }; + update: { choice: VoteChoice }; + where: { proposalId_voterId: { voterId: string } }; + }) { + const existing = proposal.votes.find( + (vote) => vote.voterId === args.where.proposalId_voterId.voterId, + ); + + if (existing) { + existing.choice = args.update.choice; + existing.updatedAt = afterVotingEnds; + return existing; + } + + const vote = { + ...createVote(args.create.voterId, args.create.choice), + createdAt: afterVotingEnds, + updatedAt: afterVotingEnds, + }; + proposal.votes.push(vote); + return vote; + }, + }, + proposal: { + async findFirst(args: { where: { id: string; worldId: string } }) { + if (args.where.id !== proposal.id || args.where.worldId !== proposal.worldId) { + return null; + } + + return proposal; + }, + async update(args: { data: Record }) { + Object.assign(proposal, args.data); + return proposal; + }, + }, + proposalDecision: { + async create(args: { data: Record }) { + const decision = { + blockchainTimestamp: null, + blockNumber: null, + createdAt: afterVotingEnds, + customJsonId: null, + expectedSigner: null, + hiveEventId: null, + id: `decision-${decisions.length + 1}`, + operationIndex: null, + transactionId: null, + updatedAt: afterVotingEnds, + ...args.data, + }; + decisions.push(decision); + proposal.decision = decision; + return decision; + }, + async findUnique() { + return decisions[0] ?? null; + }, + }, + worldAuditLog: { + async create(args: { data: unknown }) { + auditLogs.push(args.data); + return args.data; + }, + }, + worldBibleVersion: { + async findFirst() { + return null; + }, + }, + $transaction(callback: (transaction: unknown) => Promise) { + return callback(database); + }, + }; + + return { + auditLogs, + database, + decisions, + proposal, + }; +} + +describe('canon voting Hive confirmation', () => { + test('confirms a matching posting-authority custom_json and is idempotent for the same operation', async () => { + const state = createDatabase(); + const hafClient = createHafClient(createOperation({ transactionId: 'tx-valid' })); + + const confirmed = await confirmCanonTransaction(state.database as never, { + actorId: 'author-1', + blockNumber: 100, + hafClient: hafClient as never, + operationIndex: 0, + proposalId: 'proposal-1', + transactionId: 'tx-valid', + worldId: 'world-1', + }); + const repeated = await confirmCanonTransaction(state.database as never, { + actorId: 'author-1', + blockNumber: 100, + hafClient: hafClient as never, + operationIndex: 0, + proposalId: 'proposal-1', + transactionId: 'tx-valid', + worldId: 'world-1', + }); + + assert.equal(confirmed.idempotent, false); + assert.ok(confirmed.decision); + assert.equal(confirmed.decision.transactionId, 'tx-valid'); + assert.equal( + confirmed.decision.blockchainTimestamp, + new Date('2026-08-12T12:05:00.000Z').toISOString(), + ); + assert.equal(repeated.idempotent, true); + assert.equal(state.events.length, 1); + assert.equal( + (state.events[0] as { blockchainTimestamp: Date }).blockchainTimestamp.toISOString(), + '2026-08-12T12:05:00.000Z', + ); + assert.equal(state.auditLogs.length, 1); + }); + + test('rejects a different operation once the decision already has a Hive confirmation', async () => { + const state = createDatabase( + createDecision({ + operationIndex: 0, + transactionId: 'tx-original', + }), + ); + + await assert.rejects( + confirmCanonTransaction(state.database as never, { + actorId: 'author-1', + blockNumber: 101, + hafClient: createHafClient(createOperation({ transactionId: 'tx-other' })) as never, + operationIndex: 0, + proposalId: 'proposal-1', + transactionId: 'tx-other', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof CanonVotingError && error.code === 'DECISION_ALREADY_CONFIRMED', + ); + + assert.equal(state.decision.transactionId, 'tx-original'); + assert.equal(state.events.length, 0); + }); + + test('rejects active-authority custom_json for canon decision confirmation', async () => { + const state = createDatabase(); + + await assert.rejects( + confirmCanonTransaction(state.database as never, { + actorId: 'author-1', + blockNumber: 100, + hafClient: createHafClient( + createOperation({ authority: 'active', transactionId: 'tx-active' }), + ) as never, + operationIndex: 0, + proposalId: 'proposal-1', + transactionId: 'tx-active', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof CanonVotingError && error.code === 'HIVE_OPERATION_INVALID_AUTHORITY', + ); + + assert.equal(state.events.length, 0); + }); + + test('skips unrelated malformed HAF rows and confirms the matching operation', async () => { + const state = createDatabase(); + const hafClient = { + async searchBlocks() { + return { + operations: [ + { + block_num: 100, + operation_id: 0, + transaction_id: 'tx-unrelated', + }, + createOperation({ transactionId: 'tx-valid' }), + ], + }; + }, + }; + + const confirmed = await confirmCanonTransaction(state.database as never, { + actorId: 'author-1', + blockNumber: 100, + hafClient: hafClient as never, + operationIndex: 0, + proposalId: 'proposal-1', + transactionId: 'tx-valid', + worldId: 'world-1', + }); + + assert.equal(confirmed.decision?.transactionId, 'tx-valid'); + }); + + test('returns not found when a mixed Hive block does not contain the target operation', async () => { + const state = createDatabase(); + + await assert.rejects( + confirmCanonTransaction(state.database as never, { + actorId: 'author-1', + blockNumber: 100, + hafClient: createHafClient({ + block_num: 100, + operation_id: 0, + transaction_id: 'tx-other', + }) as never, + operationIndex: 0, + proposalId: 'proposal-1', + transactionId: 'tx-missing', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof CanonVotingError && error.code === 'HIVE_OPERATION_NOT_FOUND', + ); + }); + + test('rejects confirmations by users other than the proposal author', async () => { + const state = createDatabase(); + + await assert.rejects( + confirmCanonTransaction(state.database as never, { + actorId: 'other-user', + blockNumber: 100, + hafClient: createHafClient(createOperation({ transactionId: 'tx-valid' })) as never, + operationIndex: 0, + proposalId: 'proposal-1', + transactionId: 'tx-valid', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof CanonVotingError && error.code === 'CONFIRMER_NOT_AUTHOR', + ); + + assert.equal(state.events.length, 0); + assert.equal(state.auditLogs.length, 0); + }); + + test('rejects the proposal author when their world role cannot submit proposals', async () => { + const state = createDatabase(createDecision(), [ + { + revokedAt: null, + role: WorldRole.READER, + userId: 'author-1', + worldId: 'world-1', + }, + ]); + let hafLookups = 0; + + await assert.rejects( + confirmCanonTransaction(state.database as never, { + actorId: 'author-1', + blockNumber: 100, + hafClient: { + async searchBlocks() { + hafLookups += 1; + return { + operations: [createOperation({ transactionId: 'tx-valid' })], + }; + }, + } as never, + operationIndex: 0, + proposalId: 'proposal-1', + transactionId: 'tx-valid', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof CanonVotingError && error.code === 'INSUFFICIENT_WORLD_PERMISSIONS', + ); + + assert.equal(hafLookups, 0); + assert.equal(state.decision.transactionId, null); + assert.equal(state.events.length, 0); + assert.equal(state.auditLogs.length, 0); + }); + + test('rejects a stale concurrent confirmation claim without creating another permanent record', async () => { + const state = createDatabase( + createDecision({ + operationIndex: 0, + transactionId: 'tx-original', + }), + ); + + await assert.rejects( + confirmCanonTransaction(state.database as never, { + actorId: 'author-1', + blockNumber: 100, + hafClient: createHafClient(createOperation({ transactionId: 'tx-loser' })) as never, + operationIndex: 0, + proposalId: 'proposal-1', + transactionId: 'tx-loser', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof CanonVotingError && error.code === 'DECISION_ALREADY_CONFIRMED', + ); + + assert.equal(state.decision.transactionId, 'tx-original'); + assert.equal(state.events.length, 0); + assert.equal(state.auditLogs.length, 0); + }); + + test('does not reissue a signable canon transaction once a decision is confirmed', async () => { + const state = createDatabase( + createDecision({ + hiveEventId: 'event-1', + operationIndex: 0, + transactionId: 'tx-original', + }), + ); + + await assert.rejects( + createCanonTransactionOperation(state.database as never, { + proposalId: 'proposal-1', + signerId: 'author-1', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof CanonVotingError && error.code === 'DECISION_ALREADY_CONFIRMED', + ); + + assert.equal(state.decision.transactionId, 'tx-original'); + assert.equal(state.events.length, 0); + assert.equal(state.auditLogs.length, 0); + }); +}); + +describe('canon voting service invariants', () => { + test('rejects proposal author self-votes even when the author has voting permission upstream', async () => { + const state = createServiceDatabase(); + + await assert.rejects( + castCanonVote(state.database as never, { + choice: VoteChoice.APPROVE, + now: votingStartedAt, + proposalId: 'proposal-1', + voterId: 'author-1', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof CanonVotingError && error.code === 'PROPOSAL_AUTHOR_CANNOT_VOTE', + ); + }); + + test('allows non-author votes through the service path', async () => { + const state = createServiceDatabase(); + + const result = await castCanonVote(state.database as never, { + choice: VoteChoice.REJECT, + now: votingStartedAt, + proposalId: 'proposal-1', + voterId: 'reader-1', + worldId: 'world-1', + }); + + assert.equal(result.vote.choice, VoteChoice.REJECT); + assert.equal(state.proposal.votes.length, 1); + }); + + test('excludes legacy author votes when finalizing the frozen result', async () => { + const state = createServiceDatabase( + createServiceProposal({ + votes: [ + createVote('author-1', VoteChoice.APPROVE), + createVote('reader-1', VoteChoice.APPROVE), + createVote('reader-2', VoteChoice.APPROVE), + createVote('reader-3', VoteChoice.APPROVE), + createVote('reader-4', VoteChoice.APPROVE), + ], + }), + ); + + const result = await finalizeCanonDecision(state.database as never, { + actorId: 'founder-1', + now: afterVotingEnds, + proposalId: 'proposal-1', + worldId: 'world-1', + }); + + assert.equal(result.decision?.outcome, ProposalDecisionOutcome.REJECTED); + assert.equal(result.decision?.totalVotes, 4); + }); + + test('does not classify a negated contradiction summary as an AI warning', async () => { + const state = createServiceDatabase( + createServiceProposal({ + aiReports: [ + { + findings: { notes: 'Contradiction keyword appears in explanation only.' }, + summary: 'No contradiction found.', + }, + ], + }), + ); + + const detail = await getProposalDetail(state.database as never, { + proposalId: 'proposal-1', + worldId: 'world-1', + }); + + assert.equal(detail.aiWarning.acknowledgmentRequired, false); + assert.equal(detail.aiWarning.acknowledged, false); + }); + + test('requires explicit acknowledgment before finalizing a major AI warning', async () => { + const state = createServiceDatabase( + createServiceProposal({ + aiReports: [ + { + findings: [{ category: 'continuity', severity: 'major', summary: 'Major conflict.' }], + summary: 'Major continuity conflict.', + }, + ], + votes: [ + createVote('reader-1'), + createVote('reader-2'), + createVote('reader-3'), + createVote('reader-4'), + createVote('reader-5'), + ], + }), + ); + + await assert.rejects( + finalizeCanonDecision(state.database as never, { + actorId: 'founder-1', + now: afterVotingEnds, + proposalId: 'proposal-1', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof CanonVotingError && error.code === 'AI_WARNING_ACKNOWLEDGMENT_REQUIRED', + ); + }); + + test('records acknowledgment timestamp and freezes it into the decision payload', async () => { + const state = createServiceDatabase( + createServiceProposal({ + aiReports: [ + { + findings: [{ category: 'continuity', severity: 'major', summary: 'Major conflict.' }], + summary: 'Major continuity conflict.', + }, + ], + votes: [ + createVote('reader-1'), + createVote('reader-2'), + createVote('reader-3'), + createVote('reader-4'), + createVote('reader-5'), + ], + }), + ); + + const acknowledged = await acknowledgeProposalAiWarning(state.database as never, { + actorId: 'founder-1', + now: afterVotingEnds, + proposalId: 'proposal-1', + worldId: 'world-1', + }); + const finalized = await finalizeCanonDecision(state.database as never, { + actorId: 'founder-1', + now: new Date(afterVotingEnds.getTime() + 1), + proposalId: 'proposal-1', + worldId: 'world-1', + }); + + assert.equal(acknowledged.aiWarning.acknowledged, true); + assert.equal(state.auditLogs.length, 1); + assert.equal(finalized.decision?.aiWarningAcknowledged, true); + assert.equal( + (finalized.decision?.decisionPayload as { aiWarning?: { acknowledgedAt?: string } }).aiWarning + ?.acknowledgedAt, + afterVotingEnds.toISOString(), + ); + }); +}); diff --git a/apps/api/src/lib/canon-voting.ts b/apps/api/src/lib/canon-voting.ts new file mode 100644 index 0000000..cb0c465 --- /dev/null +++ b/apps/api/src/lib/canon-voting.ts @@ -0,0 +1,1261 @@ +import type { Prisma, PrismaClient } from '../generated/prisma/client.js'; +import { + HiveEventType, + ProposalDecisionOutcome, + ProposalStatus, + VoteChoice, + WorldAuditAction, +} from '../generated/prisma/enums.js'; +import { HiveBroadcastError, type HiveReliableBroadcaster } from './hive/broadcast-reliability.js'; +import { HIVELORE_CUSTOM_JSON_ID } from './hive/constants.js'; +import { + buildHiveLoreCustomJsonOperation, + parseHiveLoreCustomJsonPayload, +} from './hive/operations.js'; +import { normalizeHafOperation } from './hive/projection.js'; +import { verifyHiveLoreOperation } from './hive/verification.js'; +import type { HafClient } from './hive/haf-client.js'; +import type { HafOperationRow, NormalizedHiveOperation } from './hive/types.js'; +import { + addVotingWindow, + CANON_VOTING_RULES, + decideCanonOutcome, + hashCanonicalJson, + proposalStatusForDecision, + tallyCanonVotes, +} from './canon-voting-policy.js'; +import { roleHasWorldPermission, WORLD_PERMISSIONS } from './world-permissions.js'; + +export class CanonVotingError extends Error { + constructor( + public readonly statusCode: number, + public readonly code: string, + message: string, + ) { + super(message); + } +} + +export type CanonVotingDatabase = PrismaClient; + +const voteChoices = new Set([ + VoteChoice.APPROVE, + VoteChoice.REJECT, + VoteChoice.NEEDS_REVISION, + VoteChoice.ALTERNATE_TIMELINE, +]); + +type ProposalWithDetails = Prisma.ProposalGetPayload<{ + include: { + aiReports: true; + author: { select: { hiveUsername: true; id: true } }; + decision: true; + votes: { select: { choice: true; updatedAt: true; voterId: true } }; + world: { select: { id: true; title: true } }; + }; +}>; + +type AiWarningSnapshot = { + acknowledged: boolean; + acknowledgedAt: string | null; + acknowledgmentRequired: boolean; + category: string | null; + evidence: string | null; + severity: string | null; + summary: string | null; +}; + +function iso(value: Date | null | undefined) { + return value ? value.toISOString() : null; +} + +function assertVoteChoice(choice: string): VoteChoice { + if (!voteChoices.has(choice)) { + throw new CanonVotingError(400, 'INVALID_VOTE_CHOICE', 'Unsupported vote choice.'); + } + + return choice as VoteChoice; +} + +function readStringField(value: unknown, keys: string[]) { + if (!value || typeof value !== 'object') { + return null; + } + + const record = value as Record; + + for (const key of keys) { + const field = record[key]; + + if (typeof field === 'string' && field.trim()) { + return field.trim(); + } + } + + return null; +} + +function flattenAiFindings(value: unknown): Array> { + if (!value) { + return []; + } + + if (Array.isArray(value)) { + return value.flatMap(flattenAiFindings); + } + + if (typeof value !== 'object') { + return []; + } + + const record = value as Record; + const nested = ['findings', 'warnings', 'issues', 'conflicts', 'items'].flatMap((key) => + flattenAiFindings(record[key]), + ); + + return [record, ...nested]; +} + +function textIndicatesNoMajorWarning(source: string) { + const normalized = source.toLowerCase(); + + return [ + /\bno\s+(?:major\s+)?(?:warning|contradiction|conflict)s?\s+(?:found|detected|identified|present)?\b/, + /\bwithout\s+(?:a\s+)?(?:major\s+)?(?:warning|contradiction|conflict)\b/, + /\b(?:warning|contradiction|conflict)\s+free\b/, + ].some((pattern) => pattern.test(normalized)); +} + +function textIndicatesMajorWarning(source: string) { + const normalized = source.toLowerCase(); + + if (textIndicatesNoMajorWarning(normalized)) { + return false; + } + + return [ + /\b(?:major|critical|high)\s+(?:ai\s+)?(?:warning|contradiction|conflict|issue)\b/, + /\b(?:warning|contradiction|conflict|issue)\s+(?:severity|level)\s*[:=]\s*(?:major|critical|high)\b/, + ].some((pattern) => pattern.test(normalized)); +} + +function warningFromReport(report: { findings: unknown; summary: string | null }) { + for (const finding of flattenAiFindings(report.findings)) { + const severity = readStringField(finding, ['severity', 'level', 'risk']); + const category = readStringField(finding, ['category', 'type', 'kind']); + const summary = readStringField(finding, ['summary', 'message', 'description', 'text']); + const evidence = readStringField(finding, ['evidence', 'detail', 'details', 'excerpt']); + const source = [severity, category, summary, evidence].filter(Boolean).join(' '); + + if ( + severity && + ['major', 'critical', 'high'].includes(severity.toLowerCase()) && + !textIndicatesNoMajorWarning(source) + ) { + return { + category, + evidence, + severity, + summary: summary ?? report.summary, + }; + } + + if (textIndicatesMajorWarning(source)) { + return { + category, + evidence, + severity, + summary: summary ?? report.summary, + }; + } + } + + const source = `${report.summary ?? ''} ${JSON.stringify(report.findings ?? {})}`; + + if (!textIndicatesMajorWarning(source)) { + return null; + } + + return { + category: null, + evidence: null, + severity: null, + summary: report.summary, + }; +} + +function aiWarningSnapshot(proposal: { + aiReports: Array<{ findings: unknown; summary: string | null }>; + aiWarningAcknowledgedAt?: Date | null; +}): AiWarningSnapshot { + const warning = proposal.aiReports.map(warningFromReport).find(Boolean) ?? null; + const acknowledgedAt = iso(proposal.aiWarningAcknowledgedAt); + const acknowledgmentRequired = Boolean(warning); + + return { + acknowledged: acknowledgmentRequired && Boolean(acknowledgedAt), + acknowledgedAt, + acknowledgmentRequired, + category: warning?.category ?? null, + evidence: warning?.evidence ?? null, + severity: warning?.severity ?? null, + summary: warning?.summary ?? null, + }; +} + +function proposalAuthorExclusion(authorId: string) { + return new Set([authorId]); +} + +export function serializeDecision(decision: ProposalWithDetails['decision']) { + if (!decision) { + return null; + } + + return { + aiWarningAcknowledged: decision.aiWarningAcknowledged, + aiWarningSummary: decision.aiWarningSummary, + approvalDenominator: decision.approvalDenominator, + approvalNumerator: decision.approvalNumerator, + approvalPercentageBps: decision.approvalPercentageBps, + approvalThresholdBps: decision.approvalThresholdBps, + approveCount: decision.approveCount, + alternateTimelineCount: decision.alternateTimelineCount, + blockchainTimestamp: iso(decision.blockchainTimestamp), + blockNumber: decision.blockNumber?.toString() ?? null, + contentHash: decision.contentHash, + customJsonId: decision.customJsonId, + decidedAt: decision.decidedAt.toISOString(), + decisionPayload: decision.decisionPayload, + decisionPayloadHash: decision.decisionPayloadHash, + expectedSigner: decision.expectedSigner, + hiveEventId: decision.hiveEventId, + id: decision.id, + minimumVotes: decision.minimumVotes, + needsRevisionCount: decision.needsRevisionCount, + operationIndex: decision.operationIndex, + outcome: decision.outcome, + rejectCount: decision.rejectCount, + rulesVersion: decision.rulesVersion, + totalVotes: decision.totalVotes, + transactionId: decision.transactionId, + votingWindowHours: decision.votingWindowHours, + }; +} + +function tallyFromDecision(decision: NonNullable) { + return { + alternateTimeline: decision.alternateTimelineCount, + approvalDenominator: decision.approvalDenominator, + approvalNumerator: decision.approvalNumerator, + approvalPercentageBps: decision.approvalPercentageBps, + approve: decision.approveCount, + needsRevision: decision.needsRevisionCount, + reject: decision.rejectCount, + totalVotes: decision.totalVotes, + }; +} + +export function serializeProposalDetail( + proposal: ProposalWithDetails, + currentUserId?: string | undefined, +) { + const summary = proposal.decision + ? tallyFromDecision(proposal.decision) + : tallyCanonVotes(proposal.votes, { + excludeVoterIds: proposalAuthorExclusion(proposal.authorId), + }); + const currentVote = currentUserId + ? proposal.votes.find((vote: { voterId: string }) => vote.voterId === currentUserId) + : null; + const warning = aiWarningSnapshot(proposal); + + return { + aiWarning: warning, + author: proposal.author, + authorId: proposal.authorId, + baseCanonVersionId: proposal.baseCanonVersionId, + branchBaseLoreEntryId: proposal.branchBaseLoreEntryId, + branchLabel: proposal.branchLabel, + branchParentProposalId: proposal.branchParentProposalId, + conflictMetadata: proposal.conflictMetadata, + contentHash: proposal.contentHash, + currentUserVote: + currentVote && currentUserId !== proposal.authorId + ? { + choice: currentVote.choice, + updatedAt: currentVote.updatedAt.toISOString(), + } + : null, + decision: serializeDecision(proposal.decision), + id: proposal.id, + proposedContent: proposal.proposedContent, + proposalType: proposal.proposalType, + status: proposal.status, + submittedAt: iso(proposal.submittedAt), + summary: proposal.summary, + tally: summary, + title: proposal.title, + votingEndsAt: iso(proposal.votingEndsAt), + votingStartedAt: iso(proposal.votingStartedAt), + world: proposal.world, + worldId: proposal.worldId, + }; +} + +async function findProposal(database: CanonVotingDatabase, worldId: string, proposalId: string) { + return database.proposal.findFirst({ + include: { + aiReports: true, + author: { + select: { + hiveUsername: true, + id: true, + }, + }, + decision: true, + votes: { + select: { + choice: true, + updatedAt: true, + voterId: true, + }, + }, + world: { + select: { + id: true, + title: true, + }, + }, + }, + where: { + id: proposalId, + worldId, + }, + }); +} + +export async function getProposalDetail( + database: CanonVotingDatabase, + input: { currentUserId?: string; proposalId: string; worldId: string }, +) { + const proposal = await findProposal(database, input.worldId, input.proposalId); + + if (!proposal) { + throw new CanonVotingError(404, 'PROPOSAL_NOT_FOUND', 'Proposal not found.'); + } + + return serializeProposalDetail(proposal, input.currentUserId); +} + +export async function getVoteSummary( + database: CanonVotingDatabase, + input: { proposalId: string; worldId: string }, +) { + const proposal = await database.proposal.findFirst({ + select: { + id: true, + status: true, + votingEndsAt: true, + votingStartedAt: true, + votes: { + select: { + choice: true, + voterId: true, + }, + }, + authorId: true, + decision: true, + worldId: true, + }, + where: { + id: input.proposalId, + worldId: input.worldId, + }, + }); + + if (!proposal) { + throw new CanonVotingError(404, 'PROPOSAL_NOT_FOUND', 'Proposal not found.'); + } + + return { + rules: proposal.decision + ? { + approvalThresholdBps: proposal.decision.approvalThresholdBps, + minimumVotes: proposal.decision.minimumVotes, + payloadSchemaVersion: proposal.decision.payloadSchemaVersion, + rulesVersion: proposal.decision.rulesVersion, + votingWindowHours: proposal.decision.votingWindowHours, + } + : CANON_VOTING_RULES, + status: proposal.status, + tally: proposal.decision + ? tallyFromDecision(proposal.decision) + : tallyCanonVotes(proposal.votes, { + excludeVoterIds: proposalAuthorExclusion(proposal.authorId), + }), + votingEndsAt: iso(proposal.votingEndsAt), + votingStartedAt: iso(proposal.votingStartedAt), + }; +} + +export async function castCanonVote( + database: CanonVotingDatabase, + input: { + choice: string; + proposalId: string; + voterId: string; + worldId: string; + now?: Date; + }, +) { + const choice = assertVoteChoice(input.choice); + const now = input.now ?? new Date(); + + return database.$transaction(async (transaction: Prisma.TransactionClient) => { + const proposal = await transaction.proposal.findFirst({ + select: { + decision: { select: { id: true } }, + id: true, + authorId: true, + status: true, + votingEndsAt: true, + worldId: true, + }, + where: { + id: input.proposalId, + worldId: input.worldId, + }, + }); + + if (!proposal) { + throw new CanonVotingError(404, 'PROPOSAL_NOT_FOUND', 'Proposal not found.'); + } + + if (proposal.status !== ProposalStatus.VOTING || proposal.decision) { + throw new CanonVotingError(409, 'PROPOSAL_NOT_VOTING', 'Proposal is not open for voting.'); + } + + if (proposal.authorId === input.voterId) { + throw new CanonVotingError( + 403, + 'PROPOSAL_AUTHOR_CANNOT_VOTE', + 'Proposal authors cannot vote on their own canon proposals.', + ); + } + + if (!proposal.votingEndsAt || now.getTime() >= proposal.votingEndsAt.getTime()) { + throw new CanonVotingError(409, 'VOTING_CLOSED', 'Voting is closed for this proposal.'); + } + + const vote = await transaction.appVote.upsert({ + create: { + choice, + proposalId: input.proposalId, + voterId: input.voterId, + }, + update: { + choice, + }, + where: { + proposalId_voterId: { + proposalId: input.proposalId, + voterId: input.voterId, + }, + }, + }); + + return { + vote: { + choice: vote.choice, + createdAt: vote.createdAt.toISOString(), + id: vote.id, + proposalId: vote.proposalId, + updatedAt: vote.updatedAt.toISOString(), + voterId: vote.voterId, + }, + }; + }); +} + +export async function acknowledgeProposalAiWarning( + database: CanonVotingDatabase, + input: { actorId: string; proposalId: string; worldId: string; now?: Date }, +) { + const now = input.now ?? new Date(); + + return database.$transaction(async (transaction: Prisma.TransactionClient) => { + const proposal = await transaction.proposal.findFirst({ + include: { + aiReports: true, + }, + where: { + id: input.proposalId, + worldId: input.worldId, + }, + }); + + if (!proposal) { + throw new CanonVotingError(404, 'PROPOSAL_NOT_FOUND', 'Proposal not found.'); + } + + const warning = aiWarningSnapshot(proposal); + + if (!warning.acknowledgmentRequired) { + throw new CanonVotingError( + 409, + 'AI_WARNING_NOT_REQUIRED', + 'This proposal does not have a major AI warning to acknowledge.', + ); + } + + const updated = await transaction.proposal.update({ + data: { + aiWarningAcknowledgedAt: proposal.aiWarningAcknowledgedAt ?? now, + }, + where: { + id: proposal.id, + }, + }); + + const snapshot = aiWarningSnapshot({ + aiReports: proposal.aiReports, + aiWarningAcknowledgedAt: updated.aiWarningAcknowledgedAt, + }); + + if (!proposal.aiWarningAcknowledgedAt) { + await transaction.worldAuditLog.create({ + data: { + action: WorldAuditAction.AI_WARNING_RESOLVED, + actorId: input.actorId, + metadata: { + acknowledgedAt: snapshot.acknowledgedAt, + category: snapshot.category, + evidence: snapshot.evidence, + proposalId: proposal.id, + severity: snapshot.severity, + summary: snapshot.summary, + }, + targetId: proposal.id, + targetType: 'PROPOSAL', + worldId: input.worldId, + }, + }); + } + + return { + aiWarning: snapshot, + idempotent: Boolean(proposal.aiWarningAcknowledgedAt), + }; + }); +} + +function buildDecisionPayload(input: { + aiWarning: AiWarningSnapshot; + outcome: ProposalDecisionOutcome; + proposal: { + baseCanonVersionId: string | null; + branchBaseLoreEntryId: string | null; + branchLabel: string | null; + branchParentProposalId: string | null; + conflictMetadata: unknown; + contentHash: string | null; + decidedAt: Date; + id: string; + proposedContent: unknown; + staleBaseAtDecision: boolean; + votingEndsAt: Date; + votingStartedAt: Date; + worldId: string; + }; + tally: ReturnType; +}) { + const contentHash = + input.proposal.contentHash ?? hashCanonicalJson(input.proposal.proposedContent); + + return { + aiWarning: { + acknowledged: input.aiWarning.acknowledged, + acknowledgedAt: input.aiWarning.acknowledgedAt, + acknowledgmentRequired: input.aiWarning.acknowledgmentRequired, + category: input.aiWarning.category, + evidence: input.aiWarning.evidence, + severity: input.aiWarning.severity, + summary: input.aiWarning.summary, + }, + approval: { + denominator: input.tally.approvalDenominator, + numerator: input.tally.approvalNumerator, + percentageBps: input.tally.approvalPercentageBps, + }, + branch: { + baseCanonVersionId: input.proposal.baseCanonVersionId, + baseLoreEntryId: input.proposal.branchBaseLoreEntryId, + conflictMetadata: input.proposal.conflictMetadata ?? null, + label: input.proposal.branchLabel, + parentProposalId: input.proposal.branchParentProposalId, + staleBaseAtDecision: input.proposal.staleBaseAtDecision, + }, + contentHash, + counts: { + alternateTimeline: input.tally.alternateTimeline, + approve: input.tally.approve, + needsRevision: input.tally.needsRevision, + reject: input.tally.reject, + total: input.tally.totalVotes, + }, + eventType: 'canon_decision', + outcome: input.outcome, + proposalId: input.proposal.id, + rules: CANON_VOTING_RULES, + voting: { + decidedAt: input.proposal.decidedAt.toISOString(), + votingEndsAt: input.proposal.votingEndsAt.toISOString(), + votingStartedAt: input.proposal.votingStartedAt.toISOString(), + }, + worldId: input.proposal.worldId, + }; +} + +export async function finalizeCanonDecision( + database: CanonVotingDatabase, + input: { actorId: string; proposalId: string; worldId: string; now?: Date }, +) { + const now = input.now ?? new Date(); + + return database.$transaction(async (transaction: Prisma.TransactionClient) => { + const existing = await transaction.proposalDecision.findUnique({ + where: { + proposalId: input.proposalId, + }, + }); + + if (existing) { + return { + decision: serializeDecision(existing), + idempotent: true, + }; + } + + const proposal = await transaction.proposal.findFirst({ + include: { + aiReports: true, + author: { + select: { + id: true, + }, + }, + votes: { + select: { + choice: true, + voterId: true, + }, + }, + }, + where: { + id: input.proposalId, + worldId: input.worldId, + }, + }); + + if (!proposal) { + throw new CanonVotingError(404, 'PROPOSAL_NOT_FOUND', 'Proposal not found.'); + } + + if (proposal.status !== ProposalStatus.VOTING) { + throw new CanonVotingError( + 409, + 'PROPOSAL_NOT_VOTING', + 'Proposal is not open for finalization.', + ); + } + + if (!proposal.votingStartedAt || !proposal.votingEndsAt) { + throw new CanonVotingError(409, 'VOTING_WINDOW_MISSING', 'Proposal has no voting window.'); + } + + if (now.getTime() < proposal.votingEndsAt.getTime()) { + throw new CanonVotingError(409, 'VOTING_STILL_OPEN', 'Voting is still open.'); + } + + const currentBible = await transaction.worldBibleVersion.findFirst({ + orderBy: { + versionNumber: 'desc', + }, + select: { + id: true, + }, + where: { + worldId: input.worldId, + }, + }); + + const staleBaseAtDecision = Boolean( + proposal.baseCanonVersionId && + currentBible?.id && + proposal.baseCanonVersionId !== currentBible.id, + ); + const tally = tallyCanonVotes(proposal.votes, { + excludeVoterIds: proposalAuthorExclusion(proposal.authorId), + }); + const outcome = decideCanonOutcome({ + now, + staleBaseAtDecision, + tally, + votingEndsAt: proposal.votingEndsAt, + }); + + if (!outcome) { + throw new CanonVotingError(409, 'VOTING_STILL_OPEN', 'Voting is still open.'); + } + + const warning = aiWarningSnapshot(proposal); + + if (warning.acknowledgmentRequired && !warning.acknowledged) { + throw new CanonVotingError( + 409, + 'AI_WARNING_ACKNOWLEDGMENT_REQUIRED', + 'Major AI warnings must be explicitly acknowledged before finalization.', + ); + } + + const decidedAt = now; + const contentHash = proposal.contentHash ?? hashCanonicalJson(proposal.proposedContent); + const payload = buildDecisionPayload({ + aiWarning: warning, + outcome, + proposal: { + ...proposal, + contentHash, + decidedAt, + staleBaseAtDecision, + votingEndsAt: proposal.votingEndsAt, + votingStartedAt: proposal.votingStartedAt, + }, + tally, + }); + const payloadHash = hashCanonicalJson(payload); + const decision = await transaction.proposalDecision.create({ + data: { + aiWarningAcknowledged: warning.acknowledged, + aiWarningSummary: warning.summary, + alternateTimelineCount: tally.alternateTimeline, + approvalDenominator: tally.approvalDenominator, + approvalNumerator: tally.approvalNumerator, + approvalPercentageBps: tally.approvalPercentageBps, + approvalThresholdBps: CANON_VOTING_RULES.approvalThresholdBps, + approveCount: tally.approve, + baseCanonVersionId: proposal.baseCanonVersionId, + branchBaseLoreEntryId: proposal.branchBaseLoreEntryId, + branchLabel: proposal.branchLabel, + branchParentProposalId: proposal.branchParentProposalId, + conflictMetadata: proposal.conflictMetadata as Prisma.InputJsonValue, + contentHash, + decidedAt, + decisionPayload: payload as Prisma.InputJsonValue, + decisionPayloadHash: payloadHash, + minimumVotes: CANON_VOTING_RULES.minimumVotes, + needsRevisionCount: tally.needsRevision, + outcome, + payloadSchemaVersion: CANON_VOTING_RULES.payloadSchemaVersion, + proposalId: proposal.id, + rejectCount: tally.reject, + rulesVersion: CANON_VOTING_RULES.rulesVersion, + staleBaseAtDecision, + totalVotes: tally.totalVotes, + votingWindowHours: CANON_VOTING_RULES.votingWindowHours, + }, + }); + + await transaction.proposal.update({ + data: { + ...(outcome === ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION + ? { approvedAt: decidedAt } + : { rejectedAt: decidedAt }), + contentHash, + decidedAt, + staleBaseAtDecision, + status: proposalStatusForDecision(outcome), + }, + where: { + id: proposal.id, + }, + }); + + await transaction.worldAuditLog.create({ + data: { + action: WorldAuditAction.CANON_DECISION_FINALIZED, + actorId: input.actorId, + metadata: { + decisionId: decision.id, + outcome, + payloadHash, + tally, + }, + targetId: proposal.id, + targetType: 'PROPOSAL', + worldId: input.worldId, + }, + }); + + return { + decision: serializeDecision(decision), + idempotent: false, + }; + }); +} + +export async function createCanonTransactionOperation( + database: CanonVotingDatabase, + input: { proposalId: string; signerId: string; worldId: string }, +) { + const proposal = await database.proposal.findFirst({ + include: { + author: { + select: { + hiveUsername: true, + id: true, + }, + }, + decision: true, + }, + where: { + id: input.proposalId, + worldId: input.worldId, + }, + }); + + if (!proposal?.decision) { + throw new CanonVotingError( + 409, + 'DECISION_NOT_FINALIZED', + 'Proposal decision is not finalized.', + ); + } + + if (proposal.decision.outcome !== ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION) { + throw new CanonVotingError( + 409, + 'DECISION_NOT_APPROVED', + 'Only approved decisions go on-chain.', + ); + } + + if (proposal.decision.transactionId || proposal.decision.operationIndex !== null) { + throw new CanonVotingError( + 409, + 'DECISION_ALREADY_CONFIRMED', + 'Proposal decision is already linked to a Hive operation.', + ); + } + + if (proposal.authorId !== input.signerId) { + throw new CanonVotingError( + 403, + 'SIGNER_NOT_AUTHOR', + 'Only the proposal author can sign the canon decision.', + ); + } + + await assertCanSubmitCanonTransaction(database, { + actorId: input.signerId, + proposalAuthorId: proposal.authorId, + worldId: input.worldId, + }); + + if ( + proposal.decision.transactionId || + proposal.decision.operationIndex !== null || + proposal.decision.hiveEventId + ) { + throw new CanonVotingError( + 409, + 'DECISION_ALREADY_CONFIRMED', + 'Proposal decision is already linked to a Hive operation.', + ); + } + + const signer = proposal.author.hiveUsername.toLowerCase(); + const operation = buildHiveLoreCustomJsonOperation({ + action: 'canon_approval', + entityId: proposal.decision.id, + entityType: 'CANON_DECISION', + payload: proposal.decision.decisionPayload as Record, + proposalId: proposal.id, + signer, + worldId: proposal.worldId, + }); + + await database.proposalDecision.update({ + data: { + customJsonId: HIVELORE_CUSTOM_JSON_ID, + expectedSigner: signer, + }, + where: { + id: proposal.decision.id, + }, + }); + + return { + customJsonId: HIVELORE_CUSTOM_JSON_ID, + decisionId: proposal.decision.id, + operation, + signer, + }; +} + +function readHafTransactionId(row: HafOperationRow) { + const value = row.transaction_id ?? row.transactionId ?? row.trx_id; + + return typeof value === 'string' && value.length > 0 ? value : null; +} + +function readHafOperationIndex(row: HafOperationRow) { + const value = row.operation_id ?? row.operationIndex ?? row.op_in_trx ?? row.op_pos; + const numeric = typeof value === 'string' ? Number(value) : value; + + return typeof numeric === 'number' && Number.isInteger(numeric) ? numeric : null; +} + +async function assertCanSubmitCanonTransaction( + database: CanonVotingDatabase | Prisma.TransactionClient, + input: { actorId: string; proposalAuthorId: string; worldId: string }, +) { + if (input.proposalAuthorId !== input.actorId) { + throw new CanonVotingError( + 403, + 'CONFIRMER_NOT_AUTHOR', + 'Only the proposal author can confirm the canon decision transaction.', + ); + } + + const membership = await database.worldMembership.findUnique({ + select: { + role: true, + }, + where: { + revokedAt: null, + worldId_userId: { + userId: input.actorId, + worldId: input.worldId, + }, + }, + }); + + if (!membership || !roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.SUBMIT_PROPOSAL)) { + throw new CanonVotingError( + 403, + 'INSUFFICIENT_WORLD_PERMISSIONS', + 'Insufficient world permissions.', + ); + } +} + +async function findConfirmedOperation(input: { + blockNumber?: number | undefined; + expectedOperation: ReturnType; + expectedSigner: string; + hafClient: HafClient; + hiveBroadcaster?: HiveReliableBroadcaster | undefined; + operationIndex?: number | undefined; + transactionId: string; +}): Promise { + if (input.hiveBroadcaster) { + try { + return await input.hiveBroadcaster.confirmTransactionOperation({ + blockNumberHint: input.blockNumber, + expectedOperation: input.expectedOperation, + expectedSigner: input.expectedSigner, + operationIndex: input.operationIndex, + transactionId: input.transactionId, + }); + } catch (error) { + if (error instanceof HiveBroadcastError && error.code === 'BROADCAST_CONFIRMATION_TIMEOUT') { + return null; + } + + throw error; + } + } + + if (!input.blockNumber || input.operationIndex === undefined) { + throw new CanonVotingError( + 400, + 'CONFIRMATION_LOOKUP_UNAVAILABLE', + 'A confirmation service or block and operation hints are required.', + ); + } + + const page = await input.hafClient.searchBlocks({ + fromBlock: input.blockNumber, + toBlock: input.blockNumber, + }); + + for (const row of page.operations) { + if (readHafTransactionId(row) !== input.transactionId) { + continue; + } + + if (readHafOperationIndex(row) !== input.operationIndex) { + continue; + } + + try { + const operation = normalizeHafOperation(row); + return operation; + } catch (error) { + throw new CanonVotingError( + 400, + 'HIVE_OPERATION_INVALID', + error instanceof Error ? error.message : 'Invalid Hive operation.', + ); + } + } + + return null; +} + +export async function confirmCanonTransaction( + database: CanonVotingDatabase, + input: { + actorId: string; + blockNumber?: number | undefined; + hafClient: HafClient; + hiveBroadcaster?: HiveReliableBroadcaster | undefined; + operationIndex?: number | undefined; + proposalId: string; + transactionId: string; + worldId: string; + }, +) { + const proposal = await database.proposal.findFirst({ + include: { + author: { + select: { + hiveUsername: true, + id: true, + }, + }, + decision: true, + }, + where: { + id: input.proposalId, + worldId: input.worldId, + }, + }); + + if (!proposal?.decision) { + throw new CanonVotingError( + 409, + 'DECISION_NOT_FINALIZED', + 'Proposal decision is not finalized.', + ); + } + + const currentDecision = proposal.decision; + + await assertCanSubmitCanonTransaction(database, { + actorId: input.actorId, + proposalAuthorId: proposal.author.id, + worldId: input.worldId, + }); + + if ( + currentDecision.transactionId === input.transactionId && + (input.operationIndex === undefined || currentDecision.operationIndex === input.operationIndex) + ) { + return { + decision: serializeDecision(currentDecision), + idempotent: true, + }; + } + + if (currentDecision.transactionId || currentDecision.operationIndex !== null) { + throw new CanonVotingError( + 409, + 'DECISION_ALREADY_CONFIRMED', + 'Proposal decision is already linked to a different Hive operation.', + ); + } + + const signer = (currentDecision.expectedSigner ?? proposal.author.hiveUsername).toLowerCase(); + const expectedOperation = buildHiveLoreCustomJsonOperation({ + action: 'canon_approval', + entityId: currentDecision.id, + entityType: 'CANON_DECISION', + payload: currentDecision.decisionPayload as Record, + proposalId: input.proposalId, + signer, + worldId: input.worldId, + }); + const operation = await findConfirmedOperation({ + blockNumber: input.blockNumber, + expectedOperation, + expectedSigner: signer, + hafClient: input.hafClient, + hiveBroadcaster: input.hiveBroadcaster, + operationIndex: input.operationIndex, + transactionId: input.transactionId, + }); + + if (!operation) { + throw new CanonVotingError( + 404, + 'HIVE_OPERATION_NOT_FOUND', + 'Hive operation was not confirmed.', + ); + } + + const verification = verifyHiveLoreOperation({ + expectedSigner: signer, + operation: operation.operation, + }); + + if (!verification.ok) { + throw new CanonVotingError( + 400, + 'HIVE_OPERATION_INVALID', + verification.reason ?? 'Invalid Hive operation.', + ); + } + + const customJsonOperation = operation.operation.custom_json_operation; + + if ( + !customJsonOperation || + customJsonOperation.required_auths.length > 0 || + !customJsonOperation.required_posting_auths.includes(signer) + ) { + throw new CanonVotingError( + 400, + 'HIVE_OPERATION_INVALID_AUTHORITY', + 'Canon decisions must be signed with posting authority by the expected signer.', + ); + } + + const payload = parseHiveLoreCustomJsonPayload(operation.operation); + + if ( + !payload || + payload.action !== 'canon_approval' || + payload.entityType !== 'CANON_DECISION' || + payload.entityId !== currentDecision.id || + payload.worldId !== input.worldId || + payload.proposalId !== input.proposalId || + hashCanonicalJson(payload.payload) !== currentDecision.decisionPayloadHash + ) { + throw new CanonVotingError( + 400, + 'HIVE_OPERATION_MISMATCH', + 'Hive operation does not match the frozen decision.', + ); + } + + return database.$transaction(async (transaction: Prisma.TransactionClient) => { + const confirmationClaim = await transaction.proposalDecision.updateMany({ + data: { + blockchainTimestamp: operation.blockchainTimestamp, + blockNumber: operation.blockNumber, + customJsonId: HIVELORE_CUSTOM_JSON_ID, + expectedSigner: signer, + operationIndex: operation.operationIndex, + transactionId: operation.transactionId, + }, + where: { + hiveEventId: null, + id: currentDecision.id, + operationIndex: null, + transactionId: null, + }, + }); + + if (confirmationClaim.count !== 1) { + const confirmedDecision = await transaction.proposalDecision.findUnique({ + where: { + id: currentDecision.id, + }, + }); + + if ( + confirmedDecision?.transactionId === operation.transactionId && + confirmedDecision.operationIndex === operation.operationIndex + ) { + return { + decision: serializeDecision(confirmedDecision), + idempotent: true, + }; + } + + throw new CanonVotingError( + 409, + 'DECISION_ALREADY_CONFIRMED', + 'Proposal decision is already linked to a different Hive operation.', + ); + } + + const hiveEvent = await transaction.hiveEvent.upsert({ + create: { + blockNumber: operation.blockNumber, + blockchainTimestamp: operation.blockchainTimestamp, + eventType: HiveEventType.CUSTOM_JSON, + operationIndex: operation.operationIndex, + payload: operation.operation as Prisma.InputJsonValue, + transactionId: operation.transactionId, + }, + update: { + blockNumber: operation.blockNumber, + blockchainTimestamp: operation.blockchainTimestamp, + eventType: HiveEventType.CUSTOM_JSON, + payload: operation.operation as Prisma.InputJsonValue, + }, + where: { + transactionId_operationIndex: { + operationIndex: operation.operationIndex, + transactionId: operation.transactionId, + }, + }, + }); + + const confirmedDecision = await transaction.proposalDecision.update({ + data: { + hiveEventId: hiveEvent.id, + }, + where: { + id: currentDecision.id, + }, + }); + + await transaction.worldAuditLog.create({ + data: { + action: WorldAuditAction.CANON_DECISION_CONFIRMED, + actorId: input.actorId, + metadata: { + blockNumber: operation.blockNumber.toString(), + decisionId: currentDecision.id, + hiveEventId: hiveEvent.id, + operationIndex: operation.operationIndex, + transactionId: operation.transactionId, + }, + targetId: currentDecision.id, + targetType: 'PROPOSAL_DECISION', + worldId: input.worldId, + }, + }); + + return { + decision: serializeDecision(confirmedDecision), + idempotent: false, + }; + }); +} + +export function prepareSubmittedProposalVotingFields(input: { + proposedContent: unknown; + submittedAt: Date; +}) { + return { + contentHash: hashCanonicalJson(input.proposedContent), + votingEndsAt: addVotingWindow(input.submittedAt), + votingStartedAt: input.submittedAt, + }; +} diff --git a/apps/api/src/lib/contributions.ts b/apps/api/src/lib/contributions.ts new file mode 100644 index 0000000..e502159 --- /dev/null +++ b/apps/api/src/lib/contributions.ts @@ -0,0 +1,780 @@ +import type { Prisma, PrismaClient } from '../generated/prisma/client.js'; +import { + ContributionKind, + ContributionStatus, + ProposalStatus, + ProposalType, + WorldAuditAction, +} from '../generated/prisma/enums.js'; +import { prepareSubmittedProposalVotingFields } from './canon-voting.js'; + +const STRUCTURED_DOCUMENT_MAX_BYTES = 100 * 1024; + +export class ContributionError extends Error { + constructor( + public readonly statusCode: number, + message: string, + ) { + super(message); + } +} + +export type ContributionDatabase = Pick< + PrismaClient, + | '$transaction' + | 'contributionDraft' + | 'loreEntry' + | 'proposal' + | 'refreshSession' + | 'world' + | 'worldAuditLog' + | 'worldMembership' +>; + +export type StructuredDocument = Prisma.InputJsonObject; + +export type CreateContributionInput = { + worldId: string; + authorId: string; + kind: ContributionKind; + title: string; + summary?: string | undefined; + targetLoreEntryId?: string | undefined; + content: unknown; +}; + +export type UpdateContributionInput = { + worldId: string; + contributionId: string; + authorId: string; + kind?: ContributionKind | undefined; + title?: string | undefined; + summary?: string | null | undefined; + targetLoreEntryId?: string | null | undefined; + content?: unknown; +}; + +export type ListContributionInput = { + worldId: string; + authorId: string; + status?: ContributionStatus | undefined; + kind?: ContributionKind | undefined; + page?: number | undefined; + pageSize?: number | undefined; +}; + +const contributionInclude = { + proposal: true, + targetLoreEntry: { + select: { + id: true, + loreType: true, + slug: true, + title: true, + worldId: true, + }, + }, +} as const; + +type ContributionWithRelations = Prisma.ContributionDraftGetPayload<{ + include: typeof contributionInclude; +}>; + +type ProposalRecord = Prisma.ProposalGetPayload>; + +function serializeDate(value: Date | null) { + return value?.toISOString() ?? null; +} + +export function serializeProposal(proposal: ProposalRecord | null) { + if (!proposal) { + return null; + } + + return { + approvedAt: serializeDate(proposal.approvedAt), + authorId: proposal.authorId, + contributionKind: proposal.contributionKind, + createdAt: proposal.createdAt.toISOString(), + id: proposal.id, + proposedContent: proposal.proposedContent, + proposalType: proposal.proposalType, + publishedAt: serializeDate(proposal.publishedAt), + rejectedAt: serializeDate(proposal.rejectedAt), + resultingBibleVersionId: proposal.resultingBibleVersionId, + resultingLoreEntryId: proposal.resultingLoreEntryId, + status: proposal.status, + submittedAt: serializeDate(proposal.submittedAt), + summary: proposal.summary, + targetLoreEntryId: proposal.targetLoreEntryId, + title: proposal.title, + updatedAt: proposal.updatedAt.toISOString(), + votingStartedAt: serializeDate(proposal.votingStartedAt), + worldId: proposal.worldId, + }; +} + +export function serializeContribution(contribution: ContributionWithRelations) { + return { + authorId: contribution.authorId, + content: contribution.content, + createdAt: contribution.createdAt.toISOString(), + id: contribution.id, + kind: contribution.kind, + proposal: serializeProposal(contribution.proposal), + proposalId: contribution.proposalId, + status: contribution.status, + submittedAt: serializeDate(contribution.submittedAt), + summary: contribution.summary, + targetLoreEntry: contribution.targetLoreEntry, + targetLoreEntryId: contribution.targetLoreEntryId, + title: contribution.title, + updatedAt: contribution.updatedAt.toISOString(), + worldId: contribution.worldId, + }; +} + +function isPlainObject(value: unknown): value is Record { + return ( + typeof value === 'object' && + value !== null && + !Array.isArray(value) && + (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null) + ); +} + +function assertJsonByteLimit(value: unknown) { + const serialized = JSON.stringify(value); + + if (!serialized || Buffer.byteLength(serialized, 'utf8') > STRUCTURED_DOCUMENT_MAX_BYTES) { + throw new ContributionError(400, 'Structured content exceeds the 100 KB limit.'); + } +} + +export function validateStructuredDocument(value: unknown): StructuredDocument { + assertJsonByteLimit(value); + + if (!isPlainObject(value)) { + throw new ContributionError(400, 'Structured content must be a JSON object.'); + } + + if (value.type !== 'doc') { + throw new ContributionError(400, 'Structured content root type must be "doc".'); + } + + if ('content' in value && !Array.isArray(value.content)) { + throw new ContributionError(400, 'Structured content root content must be an array.'); + } + + return value as StructuredDocument; +} + +export function hasMeaningfulText(value: unknown): boolean { + if (Array.isArray(value)) { + return value.some(hasMeaningfulText); + } + + if (!isPlainObject(value)) { + return false; + } + + if (typeof value.text === 'string' && value.text.trim().length > 0) { + return true; + } + + return Object.values(value).some(hasMeaningfulText); +} + +function normalizeTitle(title: string) { + const normalized = title.trim(); + + if (!normalized) { + throw new ContributionError(400, 'Contribution title is required.'); + } + + if (normalized.length > 200) { + throw new ContributionError(400, 'Contribution title must be at most 200 characters.'); + } + + return normalized; +} + +function normalizeSummary(summary: string | null | undefined) { + const normalized = summary?.trim() || null; + + if (normalized && normalized.length > 1_000) { + throw new ContributionError(400, 'Contribution summary must be at most 1000 characters.'); + } + + return normalized; +} + +async function assertWorldExists(database: Pick, worldId: string) { + const world = await database.world.findUnique({ + select: { + id: true, + }, + where: { + id: worldId, + }, + }); + + if (!world) { + throw new ContributionError(404, 'World not found.'); + } +} + +async function assertTargetLoreEntry( + database: Pick, + worldId: string, + targetLoreEntryId: string | null | undefined, +) { + if (!targetLoreEntryId) { + return null; + } + + const target = await database.loreEntry.findUnique({ + select: { + id: true, + worldId: true, + }, + where: { + id: targetLoreEntryId, + }, + }); + + if (!target) { + throw new ContributionError(404, 'Target lore entry not found.'); + } + + if (target.worldId !== worldId) { + throw new ContributionError(400, 'Target lore entry must belong to the same world.'); + } + + return target; +} + +function proposalTypeForContribution(kind: ContributionKind, hasTargetLoreEntry: boolean) { + if (kind === ContributionKind.STORY) { + return ProposalType.ADD_STORY; + } + + return hasTargetLoreEntry ? ProposalType.UPDATE_LORE : ProposalType.ADD_LORE; +} + +async function createContributionAuditLog( + database: Pick, + input: { + action: (typeof WorldAuditAction)[keyof typeof WorldAuditAction]; + actorId: string; + worldId: string; + targetId: string; + targetType: string; + metadata?: Prisma.InputJsonObject | undefined; + }, +) { + await database.worldAuditLog.create({ + data: { + action: input.action, + actorId: input.actorId, + metadata: input.metadata ?? {}, + targetId: input.targetId, + targetType: input.targetType, + worldId: input.worldId, + }, + }); +} + +export async function createContribution( + database: ContributionDatabase, + input: CreateContributionInput, +) { + const title = normalizeTitle(input.title); + const summary = normalizeSummary(input.summary); + const content = validateStructuredDocument(input.content); + + await assertWorldExists(database, input.worldId); + await assertTargetLoreEntry(database, input.worldId, input.targetLoreEntryId); + + const contribution = await database.$transaction( + async (transaction: Prisma.TransactionClient) => { + const created = await transaction.contributionDraft.create({ + data: { + authorId: input.authorId, + content, + kind: input.kind, + summary, + targetLoreEntryId: input.targetLoreEntryId || null, + title, + worldId: input.worldId, + }, + include: contributionInclude, + }); + + await createContributionAuditLog(transaction, { + action: WorldAuditAction.CONTRIBUTION_CREATED, + actorId: input.authorId, + metadata: { + kind: input.kind, + targetLoreEntryId: input.targetLoreEntryId ?? null, + }, + targetId: created.id, + targetType: 'CONTRIBUTION_DRAFT', + worldId: input.worldId, + }); + + return created; + }, + ); + + return serializeContribution(contribution); +} + +export async function listOwnedContributions( + database: ContributionDatabase, + input: ListContributionInput, +) { + const page = input.page ?? 1; + const pageSize = input.pageSize ?? 20; + const where: Prisma.ContributionDraftWhereInput = { + authorId: input.authorId, + ...(input.kind ? { kind: input.kind } : {}), + ...(input.status ? { status: input.status } : {}), + worldId: input.worldId, + }; + + const [contributions, total] = await Promise.all([ + database.contributionDraft.findMany({ + include: contributionInclude, + orderBy: [ + { + updatedAt: 'desc', + }, + { + id: 'desc', + }, + ], + skip: (page - 1) * pageSize, + take: pageSize, + where, + }), + database.contributionDraft.count({ + where, + }), + ]); + + return { + contributions: contributions.map(serializeContribution), + pagination: { + page, + pageSize, + total, + }, + }; +} + +async function resolveMissingOrLockedContribution( + database: Pick, + input: { + worldId: string; + contributionId: string; + authorId: string; + lockedMessage: string; + }, +) { + const current = await database.contributionDraft.findFirst({ + select: { + status: true, + }, + where: { + authorId: input.authorId, + id: input.contributionId, + worldId: input.worldId, + }, + }); + + if (!current) { + throw new ContributionError(404, 'Contribution not found.'); + } + + if (current.status !== ContributionStatus.DRAFT) { + throw new ContributionError(409, input.lockedMessage); + } + + throw new ContributionError(409, 'Concurrent contribution update conflict.'); +} + +async function findOwnedContributionOrThrow( + database: Pick, + input: { + worldId: string; + contributionId: string; + authorId: string; + }, +) { + const contribution = await database.contributionDraft.findFirst({ + include: contributionInclude, + where: { + authorId: input.authorId, + id: input.contributionId, + worldId: input.worldId, + }, + }); + + if (!contribution) { + throw new ContributionError(404, 'Contribution not found.'); + } + + return contribution; +} + +export async function getOwnedContribution( + database: ContributionDatabase, + input: { + worldId: string; + contributionId: string; + authorId: string; + }, +) { + const contribution = await database.contributionDraft.findFirst({ + include: contributionInclude, + where: { + authorId: input.authorId, + id: input.contributionId, + worldId: input.worldId, + }, + }); + + return contribution ? serializeContribution(contribution) : null; +} + +export async function updateContribution( + database: ContributionDatabase, + input: UpdateContributionInput, +) { + await findOwnedContributionOrThrow(database, input); + + const data: Prisma.ContributionDraftUpdateManyMutationInput = {}; + const changedFields: string[] = []; + let targetLoreEntryId: string | null | undefined; + + if (input.kind) { + data.kind = input.kind; + changedFields.push('kind'); + } + + if (input.title !== undefined) { + data.title = normalizeTitle(input.title); + changedFields.push('title'); + } + + if (input.summary !== undefined) { + data.summary = normalizeSummary(input.summary); + changedFields.push('summary'); + } + + if (input.content !== undefined) { + data.content = validateStructuredDocument(input.content); + changedFields.push('content'); + } + + if (input.targetLoreEntryId !== undefined) { + await assertTargetLoreEntry(database, input.worldId, input.targetLoreEntryId); + targetLoreEntryId = input.targetLoreEntryId; + changedFields.push('targetLoreEntryId'); + } + + if (Object.keys(data).length === 0) { + data.updatedAt = new Date(); + } + + const contribution = await database.$transaction( + async (transaction: Prisma.TransactionClient) => { + const updated = await transaction.contributionDraft.updateMany({ + data, + where: { + authorId: input.authorId, + id: input.contributionId, + status: ContributionStatus.DRAFT, + worldId: input.worldId, + }, + }); + + if (updated.count !== 1) { + await resolveMissingOrLockedContribution(transaction, { + ...input, + lockedMessage: 'Submitted contributions cannot be edited.', + }); + } + + if (targetLoreEntryId !== undefined) { + await transaction.contributionDraft.update({ + data: { + targetLoreEntry: + targetLoreEntryId === null + ? { + disconnect: true, + } + : { + connect: { + id: targetLoreEntryId, + }, + }, + }, + where: { + id: input.contributionId, + }, + }); + } + + const current = await transaction.contributionDraft.findFirst({ + include: contributionInclude, + where: { + authorId: input.authorId, + id: input.contributionId, + worldId: input.worldId, + }, + }); + + if (!current) { + throw new ContributionError(404, 'Contribution not found.'); + } + + await createContributionAuditLog(transaction, { + action: WorldAuditAction.CONTRIBUTION_UPDATED, + actorId: input.authorId, + metadata: { + changedFields: changedFields.sort(), + }, + targetId: current.id, + targetType: 'CONTRIBUTION_DRAFT', + worldId: input.worldId, + }); + + return current; + }, + ); + + return serializeContribution(contribution); +} + +export async function deleteContribution( + database: ContributionDatabase, + input: { + worldId: string; + contributionId: string; + authorId: string; + }, +) { + await database.$transaction(async (transaction: Prisma.TransactionClient) => { + const existing = await transaction.contributionDraft.findFirst({ + where: { + authorId: input.authorId, + id: input.contributionId, + worldId: input.worldId, + }, + }); + + if (!existing) { + throw new ContributionError(404, 'Contribution not found.'); + } + + if (existing.status !== ContributionStatus.DRAFT) { + throw new ContributionError(409, 'Submitted contributions cannot be deleted.'); + } + + const deleted = await transaction.contributionDraft.deleteMany({ + where: { + authorId: input.authorId, + id: input.contributionId, + status: ContributionStatus.DRAFT, + worldId: input.worldId, + }, + }); + + if (deleted.count !== 1) { + await resolveMissingOrLockedContribution(transaction, { + ...input, + lockedMessage: 'Submitted contributions cannot be deleted.', + }); + } + + await createContributionAuditLog(transaction, { + action: WorldAuditAction.CONTRIBUTION_DELETED, + actorId: input.authorId, + metadata: { + kind: existing.kind, + targetLoreEntryId: existing.targetLoreEntryId, + }, + targetId: existing.id, + targetType: 'CONTRIBUTION_DRAFT', + worldId: input.worldId, + }); + }); +} + +export async function submitContribution( + database: ContributionDatabase, + input: { + worldId: string; + contributionId: string; + authorId: string; + }, +) { + const result = await database.$transaction(async (transaction: Prisma.TransactionClient) => { + const existing = await transaction.contributionDraft.findFirst({ + include: contributionInclude, + where: { + authorId: input.authorId, + id: input.contributionId, + worldId: input.worldId, + }, + }); + + if (!existing) { + throw new ContributionError(404, 'Contribution not found.'); + } + + if (existing.status !== ContributionStatus.DRAFT) { + if (existing.proposal) { + return { + alreadySubmitted: true, + contribution: existing, + proposal: existing.proposal, + }; + } + + throw new ContributionError(409, 'Contribution already submitted.'); + } + + normalizeTitle(existing.title); + const structuredContent = validateStructuredDocument(existing.content); + + if (!hasMeaningfulText(existing.content)) { + throw new ContributionError(400, 'Contribution content must include meaningful text.'); + } + + await assertWorldExists(transaction, input.worldId); + await assertTargetLoreEntry(transaction, input.worldId, existing.targetLoreEntryId); + + const submittedAt = new Date(); + const votingFields = prepareSubmittedProposalVotingFields({ + proposedContent: structuredContent, + submittedAt, + }); + const currentBible = await transaction.worldBibleVersion.findFirst({ + orderBy: { + versionNumber: 'desc', + }, + select: { + id: true, + }, + where: { + worldId: input.worldId, + }, + }); + const transition = await transaction.contributionDraft.updateMany({ + data: { + status: ContributionStatus.SUBMITTED, + submittedAt, + }, + where: { + authorId: input.authorId, + id: input.contributionId, + status: ContributionStatus.DRAFT, + worldId: input.worldId, + }, + }); + + if (transition.count !== 1) { + const submitted = await transaction.contributionDraft.findFirst({ + include: contributionInclude, + where: { + authorId: input.authorId, + id: input.contributionId, + worldId: input.worldId, + }, + }); + + if (submitted?.proposal) { + return { + alreadySubmitted: true, + contribution: submitted, + proposal: submitted.proposal, + }; + } + + throw new ContributionError(409, 'Concurrent submission conflict.'); + } + + // Proposal.proposedContent is the immutable reviewer snapshot; submitted + // drafts are locked so draft endpoints cannot mutate active voting content. + const proposal = await transaction.proposal.create({ + data: { + authorId: input.authorId, + baseCanonVersionId: currentBible?.id ?? null, + contributionKind: existing.kind, + contentHash: votingFields.contentHash, + proposedContent: structuredContent, + proposalType: proposalTypeForContribution( + existing.kind, + Boolean(existing.targetLoreEntryId), + ), + status: ProposalStatus.VOTING, + submittedAt, + summary: existing.summary ?? '', + targetLoreEntryId: existing.targetLoreEntryId, + title: existing.title, + votingEndsAt: votingFields.votingEndsAt, + votingStartedAt: votingFields.votingStartedAt, + worldId: input.worldId, + }, + }); + + const contribution = await transaction.contributionDraft.update({ + data: { + proposalId: proposal.id, + }, + include: contributionInclude, + where: { + id: existing.id, + }, + }); + + await createContributionAuditLog(transaction, { + action: WorldAuditAction.PROPOSAL_CREATED, + actorId: input.authorId, + metadata: { + contributionId: contribution.id, + contributionKind: contribution.kind, + proposalType: proposal.proposalType, + }, + targetId: proposal.id, + targetType: 'PROPOSAL', + worldId: input.worldId, + }); + + await createContributionAuditLog(transaction, { + action: WorldAuditAction.CONTRIBUTION_SUBMITTED, + actorId: input.authorId, + metadata: { + proposalId: proposal.id, + }, + targetId: contribution.id, + targetType: 'CONTRIBUTION_DRAFT', + worldId: input.worldId, + }); + + return { + alreadySubmitted: false, + contribution, + proposal, + }; + }); + + return { + alreadySubmitted: result.alreadySubmitted, + contribution: serializeContribution(result.contribution), + proposal: serializeProposal(result.proposal), + }; +} diff --git a/apps/api/src/lib/error-tracking.test.ts b/apps/api/src/lib/error-tracking.test.ts new file mode 100644 index 0000000..3fa3e99 --- /dev/null +++ b/apps/api/src/lib/error-tracking.test.ts @@ -0,0 +1,67 @@ +import { createServer } from 'node:http'; +import type { AddressInfo } from 'node:net'; +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { reportUnhandledError, serializeError } from './error-tracking.js'; + +describe('error tracking', () => { + test('serializes errors without request secrets', () => { + const serialized = serializeError(new Error('boom')); + + assert.equal(serialized.name, 'Error'); + assert.equal(serialized.message, 'boom'); + assert.equal('headers' in serialized, false); + }); + + test('logs unhandled errors and skips webhook delivery when disabled', async () => { + const logs: unknown[] = []; + + await reportUnhandledError( + { + error: new Error('boom'), + method: 'GET', + requestId: 'request-1', + url: '/explode', + }, + { + enabled: false, + logger: { + error(payload: unknown) { + logs.push(payload); + }, + } as never, + webhookUrl: 'https://example.com/errors', + }, + ); + + assert.equal(logs.length, 1); + assert.equal((logs[0] as { requestId?: string }).requestId, 'request-1'); + }); + + test('gives up on an unresponsive webhook instead of hanging the error path', async () => { + // Regression guard. Fastify awaits the onError hook, so an unbounded fetch + // to a stalled webhook would keep every failing request open until OS-level + // TCP timeouts. Against the unbounded version this test never resolves. + const stalled = createServer(() => { + // accept the connection, never reply + }); + await new Promise((resolve) => stalled.listen(0, resolve)); + const address = stalled.address() as AddressInfo; + + const startedAt = Date.now(); + await reportUnhandledError( + { error: new Error('boom'), method: 'GET', requestId: 'req-stall', url: '/x' }, + { + enabled: true, + timeoutMs: 150, + webhookUrl: `http://127.0.0.1:${address.port}/hook`, + }, + ); + const elapsed = Date.now() - startedAt; + + stalled.close(); + + assert.ok(elapsed < 2_000, `expected the webhook to be abandoned quickly, took ${elapsed}ms`); + }); +}); diff --git a/apps/api/src/lib/error-tracking.ts b/apps/api/src/lib/error-tracking.ts new file mode 100644 index 0000000..1335c2f --- /dev/null +++ b/apps/api/src/lib/error-tracking.ts @@ -0,0 +1,77 @@ +import type { FastifyBaseLogger } from 'fastify'; + +type ErrorTrackingEvent = { + error: unknown; + method?: string | undefined; + requestId?: string | undefined; + url?: string | undefined; +}; + +type ErrorTrackerOptions = { + enabled?: boolean; + logger?: FastifyBaseLogger; + timeoutMs?: number; + webhookUrl?: string | undefined; +}; + +// Telemetry must never outlive the request it describes. Without a bound, a +// webhook that accepts the connection and never replies keeps this promise +// pending until OS-level TCP timeouts - minutes - and Fastify's onError hook +// would wait on it. +const DEFAULT_WEBHOOK_TIMEOUT_MS = 2_000; + +export function serializeError(error: unknown) { + if (error instanceof Error) { + return { + message: error.message, + name: error.name, + stack: error.stack, + }; + } + + return { + message: String(error), + name: 'UnknownError', + }; +} + +export async function reportUnhandledError( + event: ErrorTrackingEvent, + options: ErrorTrackerOptions = {}, +) { + const payload = { + error: serializeError(event.error), + method: event.method, + requestId: event.requestId, + service: 'hivelore-api', + timestamp: new Date().toISOString(), + url: event.url, + }; + + options.logger?.error(payload, 'Unhandled API error'); + + if (!options.enabled || !options.webhookUrl) { + return; + } + + const timeoutMs = options.timeoutMs ?? DEFAULT_WEBHOOK_TIMEOUT_MS; + + try { + await fetch(options.webhookUrl, { + body: JSON.stringify(payload), + headers: { + 'content-type': 'application/json', + }, + method: 'POST', + signal: AbortSignal.timeout(timeoutMs), + }); + } catch (error) { + options.logger?.warn( + { + error: serializeError(error), + requestId: event.requestId, + }, + 'Error tracking webhook delivery failed', + ); + } +} diff --git a/apps/api/src/lib/founder-memberships.test.ts b/apps/api/src/lib/founder-memberships.test.ts new file mode 100644 index 0000000..b7a4f3a --- /dev/null +++ b/apps/api/src/lib/founder-memberships.test.ts @@ -0,0 +1,318 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { + backfillFounderMemberships, + createWorldWithFounderMembership, + ensureActiveFounderMembership, + FounderMembershipBackfillError, + type ActiveFounderMembershipDatabase, + type FounderMembershipBackfillDatabase, +} from './founder-memberships.js'; +import { WORLD_ROLES } from './world-permissions.js'; + +type WorldFixture = { + id: string; + founderId: string | null; + founder: { id: string } | null; +}; + +type MembershipFixture = { + id: string; + worldId: string; + userId: string; + role: string; + revokedAt: Date | null; +}; + +function createDatabase(args: { + worlds: WorldFixture[]; + memberships?: MembershipFixture[]; +}): FounderMembershipBackfillDatabase & { + memberships: MembershipFixture[]; + createdMemberships: MembershipFixture[]; + createdWorlds: Array<{ slug: string; title: string; description: string; founderId: string }>; +} { + const memberships = [...(args.memberships ?? [])]; + const createdMemberships: MembershipFixture[] = []; + const createdWorlds: Array<{ + slug: string; + title: string; + description: string; + founderId: string; + }> = []; + + return { + memberships, + createdMemberships, + createdWorlds, + world: { + async findMany() { + return args.worlds; + }, + async create(createArgs) { + createdWorlds.push(createArgs.data); + return { + id: `world-${createdWorlds.length}`, + founderId: createArgs.data.founderId, + }; + }, + }, + worldMembership: { + async findUnique(findArgs) { + const { worldId, userId } = findArgs.where.worldId_userId; + return ( + memberships.find( + (membership) => membership.worldId === worldId && membership.userId === userId, + ) ?? null + ); + }, + async create(createArgs) { + const membership: MembershipFixture = { + id: `membership-${memberships.length + 1}`, + worldId: createArgs.data.worldId, + userId: createArgs.data.userId, + role: createArgs.data.role, + revokedAt: null, + }; + memberships.push(membership); + createdMemberships.push(membership); + return membership; + }, + }, + async $transaction(callback) { + return callback(this); + }, + }; +} + +describe('founder membership backfill', () => { + test('creates FOUNDER membership for an existing world creator', async () => { + const database = createDatabase({ + worlds: [{ id: 'world-1', founderId: 'user-1', founder: { id: 'user-1' } }], + }); + + const result = await backfillFounderMemberships(database); + + assert.deepEqual(result, { + created: [{ worldId: 'world-1', userId: 'user-1' }], + unchanged: [], + }); + assert.deepEqual(database.createdMemberships, [ + { + id: 'membership-1', + worldId: 'world-1', + userId: 'user-1', + role: WORLD_ROLES.FOUNDER, + revokedAt: null, + }, + ]); + }); + + test('rerunning the backfill creates no duplicate memberships', async () => { + const database = createDatabase({ + worlds: [{ id: 'world-1', founderId: 'user-1', founder: { id: 'user-1' } }], + }); + + await backfillFounderMemberships(database); + const secondResult = await backfillFounderMemberships(database); + + assert.deepEqual(secondResult, { + created: [], + unchanged: [{ worldId: 'world-1', userId: 'user-1', membershipId: 'membership-1' }], + }); + assert.equal(database.memberships.length, 1); + }); + + test('leaves an existing active FOUNDER membership unchanged', async () => { + const database = createDatabase({ + worlds: [{ id: 'world-1', founderId: 'user-1', founder: { id: 'user-1' } }], + memberships: [ + { + id: 'membership-existing', + worldId: 'world-1', + userId: 'user-1', + role: WORLD_ROLES.FOUNDER, + revokedAt: null, + }, + ], + }); + + const result = await backfillFounderMemberships(database); + + assert.deepEqual(result, { + created: [], + unchanged: [{ worldId: 'world-1', userId: 'user-1', membershipId: 'membership-existing' }], + }); + assert.deepEqual(database.createdMemberships, []); + }); + + test('reports conflicting active roles without creating memberships', async () => { + const database = createDatabase({ + worlds: [{ id: 'world-1', founderId: 'user-1', founder: { id: 'user-1' } }], + memberships: [ + { + id: 'membership-reader', + worldId: 'world-1', + userId: 'user-1', + role: WORLD_ROLES.READER, + revokedAt: null, + }, + ], + }); + + await assert.rejects(backfillFounderMemberships(database), (error: unknown) => { + assert.equal(error instanceof FounderMembershipBackfillError, true); + assert.deepEqual((error as FounderMembershipBackfillError).conflicts, [ + { + type: 'ACTIVE_ROLE_CONFLICT', + worldId: 'world-1', + founderId: 'user-1', + membershipId: 'membership-reader', + role: WORLD_ROLES.READER, + }, + ]); + return true; + }); + assert.deepEqual(database.createdMemberships, []); + }); + + test('does not silently reactivate revoked founder memberships', async () => { + const revokedAt = new Date('2026-01-01T00:00:00.000Z'); + const database = createDatabase({ + worlds: [{ id: 'world-1', founderId: 'user-1', founder: { id: 'user-1' } }], + memberships: [ + { + id: 'membership-revoked', + worldId: 'world-1', + userId: 'user-1', + role: WORLD_ROLES.FOUNDER, + revokedAt, + }, + ], + }); + + await assert.rejects(backfillFounderMemberships(database), (error: unknown) => { + assert.equal(error instanceof FounderMembershipBackfillError, true); + assert.deepEqual((error as FounderMembershipBackfillError).conflicts, [ + { + type: 'REVOKED_MEMBERSHIP', + worldId: 'world-1', + founderId: 'user-1', + membershipId: 'membership-revoked', + role: WORLD_ROLES.FOUNDER, + revokedAt, + }, + ]); + return true; + }); + assert.deepEqual(database.createdMemberships, []); + }); + + test('reports missing creator references without creating memberships', async () => { + const database = createDatabase({ + worlds: [{ id: 'world-1', founderId: 'missing-user', founder: null }], + }); + + await assert.rejects(backfillFounderMemberships(database), (error: unknown) => { + assert.equal(error instanceof FounderMembershipBackfillError, true); + assert.deepEqual((error as FounderMembershipBackfillError).conflicts, [ + { + type: 'MISSING_FOUNDER', + worldId: 'world-1', + founderId: 'missing-user', + }, + ]); + return true; + }); + assert.deepEqual(database.createdMemberships, []); + }); + + test('seed helper force-normalizes disposable fixture data to one active founder membership', async () => { + const memberships: MembershipFixture[] = [ + { + id: 'membership-existing', + worldId: 'world-1', + userId: 'user-1', + role: WORLD_ROLES.READER, + revokedAt: new Date('2026-01-01T00:00:00.000Z'), + }, + ]; + const database: ActiveFounderMembershipDatabase = { + worldMembership: { + async upsert(args) { + const existing = memberships.find( + (membership) => + membership.worldId === args.where.worldId_userId.worldId && + membership.userId === args.where.worldId_userId.userId, + ); + + if (existing) { + existing.role = args.update.role; + existing.revokedAt = args.update.revokedAt; + return existing; + } + + const membership = { + id: `membership-${memberships.length + 1}`, + worldId: args.create.worldId, + userId: args.create.userId, + role: args.create.role, + revokedAt: null, + }; + memberships.push(membership); + return membership; + }, + }, + }; + + await ensureActiveFounderMembership(database, { worldId: 'world-1', userId: 'user-1' }); + await ensureActiveFounderMembership(database, { worldId: 'world-1', userId: 'user-1' }); + + const activeFounderMemberships = memberships.filter( + (membership) => + membership.worldId === 'world-1' && + membership.userId === 'user-1' && + membership.role === WORLD_ROLES.FOUNDER && + membership.revokedAt === null, + ); + + assert.equal(activeFounderMemberships.length, 1); + assert.deepEqual(memberships, [ + { + id: 'membership-existing', + worldId: 'world-1', + userId: 'user-1', + role: WORLD_ROLES.FOUNDER, + revokedAt: null, + }, + ]); + }); + + test('new-world helper creates world and founder membership in one transaction', async () => { + const database = createDatabase({ + worlds: [], + }); + + const world = await createWorldWithFounderMembership(database, { + slug: 'new-world', + title: 'New World', + description: 'A test world.', + founderId: 'user-1', + }); + + assert.deepEqual(world, { + id: 'world-1', + founderId: 'user-1', + }); + assert.deepEqual(database.createdMemberships, [ + { + id: 'membership-1', + worldId: 'world-1', + userId: 'user-1', + role: WORLD_ROLES.FOUNDER, + revokedAt: null, + }, + ]); + }); +}); diff --git a/apps/api/src/lib/founder-memberships.ts b/apps/api/src/lib/founder-memberships.ts new file mode 100644 index 0000000..18fa22d --- /dev/null +++ b/apps/api/src/lib/founder-memberships.ts @@ -0,0 +1,282 @@ +import { WORLD_ROLES } from './world-permissions.js'; + +type FounderMembershipWorld = { + id: string; + founderId: string | null; + founder: { + id: string; + } | null; +}; + +type FounderMembership = { + id: string; + worldId: string; + userId: string; + role: string; + revokedAt: Date | null; +}; + +export type FounderMembershipBackfillConflict = + | { + type: 'MISSING_FOUNDER'; + worldId: string; + founderId: string | null; + } + | { + type: 'ACTIVE_ROLE_CONFLICT'; + worldId: string; + founderId: string; + membershipId: string; + role: string; + } + | { + type: 'REVOKED_MEMBERSHIP'; + worldId: string; + founderId: string; + membershipId: string; + role: string; + revokedAt: Date; + }; + +export class FounderMembershipBackfillError extends Error { + constructor(public readonly conflicts: FounderMembershipBackfillConflict[]) { + super('Founder membership backfill found ambiguous authorization data.'); + this.name = 'FounderMembershipBackfillError'; + } +} + +export type FounderMembershipBackfillDatabase = { + world: { + findMany(args: { + select: { + id: true; + founderId: true; + founder: { + select: { + id: true; + }; + }; + }; + }): Promise; + create(args: { + data: { + slug: string; + title: string; + description: string; + founderId: string; + }; + }): Promise<{ id: string; founderId: string }>; + }; + worldMembership: { + findUnique(args: { + where: { + worldId_userId: { + worldId: string; + userId: string; + }; + }; + select: { + id: true; + worldId: true; + userId: true; + role: true; + revokedAt: true; + }; + }): Promise; + create(args: { + data: { + worldId: string; + userId: string; + role: typeof WORLD_ROLES.FOUNDER; + grantedById: string; + }; + }): Promise; + }; + $transaction( + callback: (transaction: FounderMembershipBackfillDatabase) => Promise, + ): Promise; +}; + +export type FounderMembershipBackfillResult = { + created: Array<{ worldId: string; userId: string }>; + unchanged: Array<{ worldId: string; userId: string; membershipId: string }>; +}; + +export type ActiveFounderMembershipDatabase = { + worldMembership: { + upsert(args: { + where: { + worldId_userId: { + worldId: string; + userId: string; + }; + }; + update: { + role: typeof WORLD_ROLES.FOUNDER; + grantedById: string; + revokedAt: null; + }; + create: { + worldId: string; + userId: string; + role: typeof WORLD_ROLES.FOUNDER; + grantedById: string; + }; + }): Promise; + }; +}; + +export function ensureActiveFounderMembership( + database: ActiveFounderMembershipDatabase, + membership: { worldId: string; userId: string }, +) { + // Intended for disposable development seed data. It normalizes the fixture owner + // back to an active FOUNDER membership on every seed run. + return database.worldMembership.upsert({ + where: { + worldId_userId: membership, + }, + update: { + role: WORLD_ROLES.FOUNDER, + grantedById: membership.userId, + revokedAt: null, + }, + create: { + ...membership, + role: WORLD_ROLES.FOUNDER, + grantedById: membership.userId, + }, + }); +} + +export async function backfillFounderMemberships( + database: FounderMembershipBackfillDatabase, +): Promise { + const worlds = await database.world.findMany({ + select: { + id: true, + founderId: true, + founder: { + select: { + id: true, + }, + }, + }, + }); + const conflicts: FounderMembershipBackfillConflict[] = []; + const toCreate: Array<{ worldId: string; userId: string }> = []; + const unchanged: FounderMembershipBackfillResult['unchanged'] = []; + + for (const world of worlds) { + if (!world.founderId || !world.founder) { + conflicts.push({ + type: 'MISSING_FOUNDER', + worldId: world.id, + founderId: world.founderId, + }); + continue; + } + + const membership = await database.worldMembership.findUnique({ + where: { + worldId_userId: { + worldId: world.id, + userId: world.founderId, + }, + }, + select: { + id: true, + worldId: true, + userId: true, + role: true, + revokedAt: true, + }, + }); + + if (!membership) { + toCreate.push({ + worldId: world.id, + userId: world.founderId, + }); + continue; + } + + if (membership.revokedAt) { + conflicts.push({ + type: 'REVOKED_MEMBERSHIP', + worldId: world.id, + founderId: world.founderId, + membershipId: membership.id, + role: membership.role, + revokedAt: membership.revokedAt, + }); + continue; + } + + if (membership.role !== WORLD_ROLES.FOUNDER) { + conflicts.push({ + type: 'ACTIVE_ROLE_CONFLICT', + worldId: world.id, + founderId: world.founderId, + membershipId: membership.id, + role: membership.role, + }); + continue; + } + + unchanged.push({ + worldId: world.id, + userId: world.founderId, + membershipId: membership.id, + }); + } + + if (conflicts.length > 0) { + throw new FounderMembershipBackfillError(conflicts); + } + + const created: FounderMembershipBackfillResult['created'] = []; + + for (const membership of toCreate) { + await database.worldMembership.create({ + data: { + ...membership, + role: WORLD_ROLES.FOUNDER, + grantedById: membership.userId, + }, + }); + created.push(membership); + } + + return { + created, + unchanged, + }; +} + +export async function createWorldWithFounderMembership( + database: FounderMembershipBackfillDatabase, + data: { + slug: string; + title: string; + description: string; + founderId: string; + }, +) { + return database.$transaction(async (transaction) => { + const world = await transaction.world.create({ + data, + }); + + await transaction.worldMembership.create({ + data: { + worldId: world.id, + userId: data.founderId, + role: WORLD_ROLES.FOUNDER, + grantedById: data.founderId, + }, + }); + + return world; + }); +} diff --git a/apps/api/src/lib/hive-signature.test.ts b/apps/api/src/lib/hive-signature.test.ts new file mode 100644 index 0000000..1c66791 --- /dev/null +++ b/apps/api/src/lib/hive-signature.test.ts @@ -0,0 +1,100 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { cryptoUtils, PrivateKey } from '@hiveio/dhive'; +import type { ExtendedAccount } from '@hiveio/dhive'; + +import { DhivePostingSignatureVerifier, type HiveAccountClient } from './hive-signature.js'; + +function createAccount(username: string, publicKey: string, weightThreshold = 1, weight = 1) { + return { + name: username, + posting: { + account_auths: [], + key_auths: [[publicKey, weight]], + weight_threshold: weightThreshold, + }, + } as unknown as ExtendedAccount; +} + +function signMessage(message: string, privateKey: PrivateKey) { + return privateKey.sign(cryptoUtils.sha256(message)).toString(); +} + +describe('Hive posting signature verifier', () => { + test('accepts a signature from an authorized posting key', async () => { + const privateKey = PrivateKey.fromSeed('alice-posting'); + const publicKey = privateKey.createPublic('STM').toString(); + const verifier = new DhivePostingSignatureVerifier({ + async getAccount() { + return createAccount('alice', publicKey); + }, + }); + const message = 'HiveLore Authentication'; + + const verified = await verifier.verifyPostingSignature({ + message, + signature: signMessage(message, privateKey), + username: 'alice', + }); + + assert.equal(verified, true); + }); + + test('rejects malformed signatures and unknown accounts', async () => { + const verifier = new DhivePostingSignatureVerifier({ + async getAccount() { + return null; + }, + }); + + assert.equal( + await verifier.verifyPostingSignature({ + message: 'message', + signature: 'not-a-signature', + username: 'alice', + }), + false, + ); + + const privateKey = PrivateKey.fromSeed('alice-posting'); + assert.equal( + await verifier.verifyPostingSignature({ + message: 'message', + signature: signMessage('message', privateKey), + username: 'alice', + }), + false, + ); + }); + + test('rejects signatures from another account or insufficient authority weight', async () => { + const authorizedPrivateKey = PrivateKey.fromSeed('alice-posting'); + const otherPrivateKey = PrivateKey.fromSeed('bob-posting'); + const authorizedPublicKey = authorizedPrivateKey.createPublic('STM').toString(); + const accountClient: HiveAccountClient = { + async getAccount() { + return createAccount('alice', authorizedPublicKey, 2, 1); + }, + }; + const verifier = new DhivePostingSignatureVerifier(accountClient); + const message = 'HiveLore Authentication'; + + assert.equal( + await verifier.verifyPostingSignature({ + message, + signature: signMessage(message, otherPrivateKey), + username: 'alice', + }), + false, + ); + assert.equal( + await verifier.verifyPostingSignature({ + message, + signature: signMessage(message, authorizedPrivateKey), + username: 'alice', + }), + false, + ); + }); +}); diff --git a/apps/api/src/lib/hive-signature.ts b/apps/api/src/lib/hive-signature.ts new file mode 100644 index 0000000..87c07b3 --- /dev/null +++ b/apps/api/src/lib/hive-signature.ts @@ -0,0 +1,70 @@ +import { Client, cryptoUtils, Signature } from '@hiveio/dhive'; +import type { ExtendedAccount } from '@hiveio/dhive'; + +export type HiveAuthProvider = 'keychain' | 'hivesigner'; + +export type HiveAccountClient = { + getAccount(username: string): Promise; +}; + +export class DhiveAccountClient implements HiveAccountClient { + private readonly client: Client; + + constructor(rpcUrl: string) { + this.client = new Client([rpcUrl]); + } + + async getAccount(username: string) { + const [account] = await this.client.database.getAccounts([username]); + + return account ?? null; + } +} + +export type HiveSignatureVerificationInput = { + username: string; + message: string; + signature: string; + publicKey?: string | undefined; +}; + +export type HiveSignatureVerifier = { + verifyPostingSignature(input: HiveSignatureVerificationInput): Promise; +}; + +export class DhivePostingSignatureVerifier implements HiveSignatureVerifier { + constructor(private readonly accountClient: HiveAccountClient) {} + + async verifyPostingSignature(input: HiveSignatureVerificationInput) { + let recoveredPublicKey: string; + + try { + const digest = cryptoUtils.sha256(input.message); + recoveredPublicKey = Signature.fromString(input.signature).recover(digest, 'STM').toString(); + } catch { + return false; + } + + if (input.publicKey && input.publicKey !== recoveredPublicKey) { + return false; + } + + const account = await this.accountClient.getAccount(input.username); + + if (!account) { + return false; + } + + const matchingKey = account.posting.key_auths.find( + ([publicKey]) => publicKey.toString() === recoveredPublicKey, + ); + + if (!matchingKey) { + return false; + } + + const [, weight] = matchingKey; + + return weight >= account.posting.weight_threshold; + } +} diff --git a/apps/api/src/lib/hive-username.test.ts b/apps/api/src/lib/hive-username.test.ts new file mode 100644 index 0000000..bbd042e --- /dev/null +++ b/apps/api/src/lib/hive-username.test.ts @@ -0,0 +1,17 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { InvalidHiveUsernameError, normalizeHiveUsername } from './hive-username.js'; + +describe('Hive username normalization', () => { + test('trims and lowercases a valid account name', () => { + assert.equal(normalizeHiveUsername(' Alice-01.dev '), 'alice-01.dev'); + }); + + test('rejects invalid account names before challenge creation', () => { + assert.throws(() => normalizeHiveUsername('ab'), InvalidHiveUsernameError); + assert.throws(() => normalizeHiveUsername('-alice'), InvalidHiveUsernameError); + assert.throws(() => normalizeHiveUsername('alice..dev'), InvalidHiveUsernameError); + assert.throws(() => normalizeHiveUsername('alice_01'), InvalidHiveUsernameError); + }); +}); diff --git a/apps/api/src/lib/hive-username.ts b/apps/api/src/lib/hive-username.ts new file mode 100644 index 0000000..e5d5208 --- /dev/null +++ b/apps/api/src/lib/hive-username.ts @@ -0,0 +1,38 @@ +const HIVE_ACCOUNT_MAX_LENGTH = 16; +const ACCOUNT_PART_PATTERN = /^[a-z][a-z0-9-]*[a-z0-9]$/; + +export class InvalidHiveUsernameError extends Error { + constructor() { + super('Invalid Hive username.'); + } +} + +export function normalizeHiveUsername(value: string) { + const normalized = value.trim().toLowerCase(); + + if (!isValidHiveUsername(normalized)) { + throw new InvalidHiveUsernameError(); + } + + return normalized; +} + +export function isValidHiveUsername(value: string) { + if (value.length < 3 || value.length > HIVE_ACCOUNT_MAX_LENGTH) { + return false; + } + + if (value !== value.toLowerCase() || value.startsWith('.') || value.endsWith('.')) { + return false; + } + + const parts = value.split('.'); + + return parts.every((part) => { + if (part.length < 3) { + return false; + } + + return ACCOUNT_PART_PATTERN.test(part) && !part.includes('--'); + }); +} diff --git a/apps/api/src/lib/hive/broadcast-reliability.test.ts b/apps/api/src/lib/hive/broadcast-reliability.test.ts new file mode 100644 index 0000000..df734ed --- /dev/null +++ b/apps/api/src/lib/hive/broadcast-reliability.test.ts @@ -0,0 +1,723 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; +import type { ApiTransaction } from '@hiveio/wax'; + +import { buildHiveLoreCustomJsonOperation } from './operations.js'; +import { + classifyHiveBroadcastError, + delayForAttempt, + DefaultHiveBroadcastTransport, + findAndVerifyOperation, + HiveBroadcastError, + HiveNodePool, + HiveReliableBroadcaster, +} from './broadcast-reliability.js'; +import { + buildHiveNetworkConfig, + DEFAULT_HIVE_RETRY_CONFIG, + parseNodeList, +} from './network-config.js'; +import type { HafOperationRow } from './types.js'; + +const network = buildHiveNetworkConfig({ + customJsonId: 'hivelore', + mainnetRpcNodes: 'https://node-a.test,https://node-b.test', + nodeEnv: 'test', +}); + +const transaction: ApiTransaction = { + expiration: '2026-08-10T12:05:00', + extensions: [], + operations: [], + ref_block_num: 1, + ref_block_prefix: 2, + signatures: ['public-signature'], +}; + +const operation = buildHiveLoreCustomJsonOperation({ + action: 'canon_approval', + entityId: 'decision-1', + entityType: 'CANON_DECISION', + payload: { + contentHash: 'hash-1', + }, + proposalId: 'proposal-1', + signer: 'mira-vale.dev', + worldId: 'world-1', +}); + +function row(transactionId = 'tx-1'): HafOperationRow { + return { + block_num: 101, + operation, + operation_id: 0, + timestamp: '2026-08-10T12:01:00.000Z', + transaction_id: transactionId, + }; +} + +function fakeClock(random = 0.5) { + let now = 0; + + return { + advance(ms: number) { + now += ms; + }, + now: () => now, + random: () => random, + async sleep(ms: number) { + now += ms; + }, + }; +} + +describe('Hive broadcast reliability', () => { + test('transaction lookup uses the confirmed block header timestamp instead of expiration', async () => { + const customJson = operation.custom_json_operation; + assert.ok(customJson); + const calls: Array<{ method: string; params: unknown[] }> = []; + const originalFetch = globalThis.fetch; + + globalThis.fetch = (async (_input: string | URL, init?: RequestInit) => { + const body = JSON.parse(String(init?.body)) as { method: string; params: unknown[] }; + calls.push({ method: body.method, params: body.params }); + + if (body.method === 'condenser_api.get_transaction') { + return Response.json({ + result: { + block_num: 101, + expiration: '2026-08-10T12:11:00', + operations: [['custom_json', customJson]], + trx_id: 'tx-1', + }, + }); + } + + if (body.method === 'condenser_api.get_block_header') { + return Response.json({ + result: { + previous: '00000000', + timestamp: '2026-08-10T12:01:00', + }, + }); + } + + return Response.json({ result: null }); + }) as typeof fetch; + + try { + const rows = await new DefaultHiveBroadcastTransport(network).getTransaction({ + transactionId: 'tx-1', + }); + const confirmed = findAndVerifyOperation(rows ?? [], { + expectedOperation: operation, + expectedSigner: 'mira-vale.dev', + transactionId: 'tx-1', + }); + + assert.equal(confirmed?.blockchainTimestamp.toISOString(), '2026-08-10T12:01:00.000Z'); + assert.notEqual(confirmed?.blockchainTimestamp.toISOString(), '2026-08-10T12:11:00.000Z'); + assert.deepEqual(calls, [ + { method: 'condenser_api.get_transaction', params: ['tx-1'] }, + { method: 'condenser_api.get_block_header', params: [101] }, + ]); + } finally { + globalThis.fetch = originalFetch; + } + }); + + test('transaction lookup fails closed when block metadata is missing or invalid', async () => { + const customJson = operation.custom_json_operation; + assert.ok(customJson); + const originalFetch = globalThis.fetch; + + globalThis.fetch = (async (_input: string | URL, init?: RequestInit) => { + const body = JSON.parse(String(init?.body)) as { method: string }; + + if (body.method === 'condenser_api.get_transaction') { + return Response.json({ + result: { + block_num: 101, + operations: [['custom_json', customJson]], + trx_id: 'tx-1', + }, + }); + } + + return Response.json({ + result: { + timestamp: 'not-a-date', + }, + }); + }) as typeof fetch; + + try { + await assert.rejects( + () => new DefaultHiveBroadcastTransport(network).getTransaction({ transactionId: 'tx-1' }), + (error: unknown) => + error instanceof HiveBroadcastError && + error.code === 'BROADCAST_REJECTED' && + error.diagnostics.reason === 'missing_or_invalid_block_timestamp', + ); + } finally { + globalThis.fetch = originalFetch; + } + }); + + test('transaction lookup rejects mismatched transaction IDs with diagnostics', async () => { + const customJson = operation.custom_json_operation; + assert.ok(customJson); + const originalFetch = globalThis.fetch; + + globalThis.fetch = (async (_input: string | URL, init?: RequestInit) => { + const body = JSON.parse(String(init?.body)) as { method: string }; + + if (body.method === 'condenser_api.get_transaction') { + return Response.json({ + result: { + block_num: 101, + operations: [['custom_json', customJson]], + trx_id: 'tx-other', + }, + }); + } + + return Response.json({ + result: { + timestamp: '2026-08-10T12:01:00', + }, + }); + }) as typeof fetch; + + try { + await assert.rejects( + () => new DefaultHiveBroadcastTransport(network).getTransaction({ transactionId: 'tx-1' }), + (error: unknown) => + error instanceof HiveBroadcastError && + error.code === 'BROADCAST_REJECTED' && + error.diagnostics.reason === 'transaction_id_mismatch', + ); + } finally { + globalThis.fetch = originalFetch; + } + }); + + test('retries a transient broadcast failure on the next node and confirms through HAF', async () => { + const calls: string[] = []; + const clock = fakeClock(); + const broadcaster = new HiveReliableBroadcaster( + network, + { + async broadcast(nodeUrl) { + calls.push(nodeUrl); + + if (calls.length === 1) { + throw Object.assign(new Error('HTTP 503'), { status: 503 }); + } + }, + async getHeadBlock() { + return 101; + }, + async searchBlocks() { + return calls.length < 2 ? [] : [row()]; + }, + }, + { + confirmationPollIntervalMs: 1, + confirmationTimeoutMs: 10, + initialDelayMs: 10, + maxDelayMs: 10, + }, + clock, + ); + + const result = await broadcaster.broadcastSignedTransaction({ + expectedOperation: operation, + expectedSigner: 'mira-vale.dev', + transaction, + transactionId: 'tx-1', + }); + + assert.deepEqual(calls, ['https://node-a.test', 'https://node-b.test']); + assert.equal(result.transactionId, 'tx-1'); + assert.equal(result.blockNumber, 101); + assert.equal(result.attempts, 2); + }); + + test('fails fast for permanent transaction errors without rotating every node', async () => { + const calls: string[] = []; + const broadcaster = new HiveReliableBroadcaster( + network, + { + async broadcast(nodeUrl) { + calls.push(nodeUrl); + throw new Error('missing required signature'); + }, + async getHeadBlock() { + return 0; + }, + async searchBlocks() { + return []; + }, + }, + {}, + fakeClock(), + ); + + await assert.rejects( + broadcaster.broadcastSignedTransaction({ + transaction, + transactionId: 'tx-1', + }), + (error: unknown) => + error instanceof HiveBroadcastError && error.code === 'PERMANENT_TRANSACTION_ERROR', + ); + assert.deepEqual(calls, ['https://node-a.test']); + }); + + test('ambiguous timeout enters confirmation before retrying the same signed transaction', async () => { + let broadcasts = 0; + const broadcaster = new HiveReliableBroadcaster( + network, + { + async broadcast() { + broadcasts += 1; + throw new Error('request timeout'); + }, + async getHeadBlock() { + return 101; + }, + async searchBlocks() { + return [row()]; + }, + }, + { + confirmationPollIntervalMs: 1, + confirmationTimeoutMs: 10, + }, + fakeClock(), + ); + + const result = await broadcaster.broadcastSignedTransaction({ + expectedOperation: operation, + expectedSigner: 'mira-vale.dev', + transaction, + transactionId: 'tx-1', + }); + + assert.equal(broadcasts, 1); + assert.equal(result.transactionId, 'tx-1'); + }); + + test('confirmation read-back rotates nodes after transient provider failures', async () => { + const readNodes: string[] = []; + const broadcaster = new HiveReliableBroadcaster( + network, + { + async broadcast() {}, + async getHeadBlock(nodeUrl) { + readNodes.push(nodeUrl ?? 'none'); + + if (readNodes.length === 1) { + throw Object.assign(new Error('HTTP 503'), { status: 503 }); + } + + return 101; + }, + async searchBlocks() { + return [row()]; + }, + }, + { + confirmationPollIntervalMs: 1, + confirmationTimeoutMs: 10, + maxConsecutiveNodeFailures: 1, + }, + fakeClock(), + ); + + const result = await broadcaster.confirmTransaction({ + expectedOperation: operation, + expectedSigner: 'mira-vale.dev', + transactionId: 'tx-1', + }); + + assert.deepEqual(readNodes, ['https://node-a.test', 'https://node-b.test']); + assert.equal(result.transactionId, 'tx-1'); + }); + + test('confirmation can read back through a different healthy node than broadcast', async () => { + const broadcastNodes: string[] = []; + const readNodes: string[] = []; + const broadcaster = new HiveReliableBroadcaster( + network, + { + async broadcast(nodeUrl) { + broadcastNodes.push(nodeUrl); + }, + async getHeadBlock(nodeUrl) { + readNodes.push(nodeUrl ?? 'none'); + + if (readNodes.length === 1) { + throw Object.assign(new Error('HTTP 503'), { status: 503 }); + } + + return 101; + }, + async searchBlocks() { + return [row()]; + }, + }, + { + confirmationPollIntervalMs: 1, + confirmationTimeoutMs: 10, + }, + fakeClock(), + ); + + await broadcaster.broadcastSignedTransaction({ + expectedOperation: operation, + expectedSigner: 'mira-vale.dev', + transaction, + transactionId: 'tx-1', + }); + + assert.deepEqual(broadcastNodes, ['https://node-a.test']); + assert.deepEqual(readNodes, ['https://node-a.test', 'https://node-b.test']); + }); + + test('rejects a confirmed transaction id with mismatched operation content', () => { + const mismatched = buildHiveLoreCustomJsonOperation({ + action: 'canon_approval', + entityId: 'decision-2', + entityType: 'CANON_DECISION', + payload: { + contentHash: 'other', + }, + proposalId: 'proposal-1', + signer: 'mira-vale.dev', + worldId: 'world-1', + }); + + assert.throws( + () => + findAndVerifyOperation([row()], { + expectedOperation: mismatched, + expectedSigner: 'mira-vale.dev', + transactionId: 'tx-1', + }), + (error: unknown) => + error instanceof HiveBroadcastError && error.code === 'BROADCAST_REJECTED', + ); + }); + + test('matches expected operations with canonical JSON ordering', () => { + const customJson = operation.custom_json_operation; + assert.ok(customJson); + + const hivedOrderedOperation = { + custom_json_operation: { + required_auths: customJson.required_auths, + required_posting_auths: customJson.required_posting_auths, + id: customJson.id, + json: customJson.json, + }, + }; + + const confirmed = findAndVerifyOperation( + [ + { + block_num: 101, + operation: hivedOrderedOperation, + operation_id: 0, + timestamp: '2026-08-10T12:01:00.000Z', + transaction_id: 'tx-1', + }, + ], + { + expectedOperation: operation, + expectedSigner: 'mira-vale.dev', + transactionId: 'tx-1', + }, + ); + + assert.equal(confirmed?.transactionId, 'tx-1'); + }); + + test('normalizes condenser operation rows returned by transaction read-back', () => { + const customJson = operation.custom_json_operation; + assert.ok(customJson); + + const confirmed = findAndVerifyOperation( + [ + { + block: 101, + op: ['custom_json', customJson], + op_in_trx: 0, + timestamp: '2026-08-10T12:01:00.000Z', + trx_id: 'tx-1', + }, + ], + { + expectedOperation: operation, + expectedSigner: 'mira-vale.dev', + operationIndex: 0, + transactionId: 'tx-1', + }, + ); + + assert.equal(confirmed?.transactionId, 'tx-1'); + assert.equal(confirmed.operationIndex, 0); + }); + + test('ignores unrelated malformed HAF rows before normalizing candidates', () => { + const confirmed = findAndVerifyOperation( + [ + { + block_num: 101, + operation: { transfer_operation: { from: 'alice', to: 'bob' } }, + operation_id: 0, + timestamp: '2026-08-10T12:01:00.000Z', + transaction_id: 'unrelated-tx', + }, + row(), + ], + { + expectedOperation: operation, + expectedSigner: 'mira-vale.dev', + transactionId: 'tx-1', + }, + ); + + assert.equal(confirmed?.transactionId, 'tx-1'); + }); + + test('walks HAF block-search pages until the target transaction is found', async () => { + const searchedPages: number[] = []; + const broadcaster = new HiveReliableBroadcaster( + network, + { + async broadcast() {}, + async getHeadBlock() { + return 101; + }, + async searchBlocks(params) { + searchedPages.push(params.page ?? 0); + + if (params.page === 1) { + return { + operations: Array.from({ length: params.pageSize ?? 100 }, (_, index) => ({ + block_num: 101, + operation: { transfer_operation: { from: 'alice', to: 'bob' } }, + operation_id: index, + timestamp: '2026-08-10T12:01:00.000Z', + transaction_id: `unrelated-${index}`, + })), + totalPages: 2, + }; + } + + return { operations: [row()], totalPages: 2 }; + }, + }, + { + confirmationPollIntervalMs: 1, + confirmationTimeoutMs: 10, + }, + fakeClock(), + ); + + const result = await broadcaster.confirmTransaction({ + expectedOperation: operation, + expectedSigner: 'mira-vale.dev', + transactionId: 'tx-1', + }); + + assert.deepEqual(searchedPages, [1, 2]); + assert.equal(result.transactionId, 'tx-1'); + }); + + test('prefers transaction lookup over HAF block-search for confirmation', async () => { + let transactionLookups = 0; + let blockSearches = 0; + const customJson = operation.custom_json_operation; + assert.ok(customJson); + + const broadcaster = new HiveReliableBroadcaster( + network, + { + async broadcast() {}, + async getHeadBlock() { + return 101; + }, + async getTransaction() { + transactionLookups += 1; + + return [ + { + block_num: 101, + operation: { + custom_json_operation: { + required_auths: customJson.required_auths, + required_posting_auths: customJson.required_posting_auths, + id: customJson.id, + json: customJson.json, + }, + }, + operation_id: 0, + timestamp: '2026-08-10T12:01:00.000Z', + transaction_id: 'tx-1', + }, + ]; + }, + async searchBlocks() { + blockSearches += 1; + throw new Error('block-search should not be used when transaction lookup exists'); + }, + }, + { + confirmationPollIntervalMs: 1, + confirmationTimeoutMs: 10, + }, + fakeClock(), + ); + + const result = await broadcaster.confirmTransaction({ + expectedOperation: operation, + expectedSigner: 'mira-vale.dev', + transactionId: 'tx-1', + }); + + assert.equal(result.transactionId, 'tx-1'); + assert.equal(transactionLookups, 1); + assert.equal(blockSearches, 0); + }); + + test('uses block header timestamp instead of transaction expiration for lookup rows', async () => { + const customJson = operation.custom_json_operation; + assert.ok(customJson); + + const originalFetch = globalThis.fetch; + const requestedMethods: string[] = []; + + globalThis.fetch = (async (_url, init) => { + const body = JSON.parse(String(init?.body)) as { method?: string }; + requestedMethods.push(body.method ?? ''); + + if (body.method === 'condenser_api.get_transaction') { + return Response.json({ + result: { + block_num: 101, + expiration: '2026-08-10T12:05:00', + operations: [ + [ + 'custom_json', + { + id: customJson.id, + json: customJson.json, + required_auths: customJson.required_auths, + required_posting_auths: customJson.required_posting_auths, + }, + ], + ], + transaction_id: 'tx-1', + }, + }); + } + + if (body.method === 'condenser_api.get_block_header') { + return Response.json({ + result: { + timestamp: '2026-08-10T12:01:00', + }, + }); + } + + return Response.json({ error: { message: 'unexpected method' } }); + }) as typeof fetch; + + try { + const transport = new DefaultHiveBroadcastTransport(network); + const rows = await transport.getTransaction({ transactionId: 'tx-1' }); + + assert.deepEqual(requestedMethods, [ + 'condenser_api.get_transaction', + 'condenser_api.get_block_header', + ]); + assert.equal(rows?.[0]?.timestamp, '2026-08-10T12:01:00.000Z'); + } finally { + globalThis.fetch = originalFetch; + } + }); + + test('calculates capped exponential backoff with bounded jitter', () => { + assert.equal(delayForAttempt(1, DEFAULT_HIVE_RETRY_CONFIG, 0.5), 500); + assert.equal(delayForAttempt(3, DEFAULT_HIVE_RETRY_CONFIG, 0.5), 2_000); + assert.equal(delayForAttempt(6, DEFAULT_HIVE_RETRY_CONFIG, 0.5), 5_000); + assert.equal(delayForAttempt(1, DEFAULT_HIVE_RETRY_CONFIG, 0), 400); + assert.equal(delayForAttempt(1, DEFAULT_HIVE_RETRY_CONFIG, 1), 600); + }); + + test('classifies transient, permanent, and expired provider failures', () => { + assert.equal(classifyHiveBroadcastError(new Error('HTTP timeout')).failureClass, 'transient'); + assert.equal( + classifyHiveBroadcastError( + Object.assign(new Error('Hive block header lookup failed: 503 Service Unavailable'), { + status: 503, + }), + ).failureClass, + 'transient', + ); + assert.equal( + classifyHiveBroadcastError(new Error('Hive block header lookup timed out')).failureClass, + 'transient', + ); + assert.equal( + classifyHiveBroadcastError(new Error('insufficient authority')).failureClass, + 'permanent', + ); + assert.equal( + classifyHiveBroadcastError(new Error('transaction expired')).code, + 'TRANSACTION_EXPIRED', + ); + }); + + test('rotates unhealthy nodes and recovers after cooldown', () => { + let now = 0; + const pool = new HiveNodePool( + ['https://a.test', 'https://b.test'], + { + ...DEFAULT_HIVE_RETRY_CONFIG, + maxConsecutiveNodeFailures: 1, + nodeCooldownMs: 100, + }, + () => now, + ); + + assert.equal(pool.current(), 'https://a.test'); + pool.reportTransientFailure('https://a.test'); + assert.equal(pool.current(), 'https://b.test'); + now = 101; + assert.equal(pool.current(), 'https://b.test'); + pool.reportTransientFailure('https://b.test'); + assert.equal(pool.current(), 'https://a.test'); + }); + + test('validates node lists without mixing credentials or duplicates', () => { + assert.deepEqual(parseNodeList('https://a.test, https://a.test/', 'test'), ['https://a.test']); + assert.throws(() => parseNodeList('https://user:pass@a.test', 'test'), /credentials/); + assert.throws(() => parseNodeList('', 'test'), /At least one/); + }); + + test('pins mainnet to the exact Hive chain id', () => { + assert.throws( + () => + buildHiveNetworkConfig({ + customJsonId: 'hivelore', + mainnetChainId: '0'.repeat(64), + nodeEnv: 'test', + }), + /mainnet chain ID/, + ); + }); +}); diff --git a/apps/api/src/lib/hive/broadcast-reliability.ts b/apps/api/src/lib/hive/broadcast-reliability.ts new file mode 100644 index 0000000..50b7eec --- /dev/null +++ b/apps/api/src/lib/hive/broadcast-reliability.ts @@ -0,0 +1,1043 @@ +import type { ApiTransaction } from '@hiveio/wax'; + +import { hashCanonicalJson } from '../canon-voting-policy.js'; +import { verifyHiveLoreOperation } from './verification.js'; +import { normalizeHafOperation } from './projection.js'; +import { HafClient } from './haf-client.js'; +import { HiveWaxClient } from './wax-client.js'; +import { HIVE_CUSTOM_JSON_OPERATION_TYPE } from './constants.js'; +import { + DEFAULT_HIVE_RETRY_CONFIG, + type HiveNetworkConfig, + type HiveRetryConfig, + sanitizeHiveNodeUrl, +} from './network-config.js'; +import type { HafOperationRow, HiveLoreOperation, NormalizedHiveOperation } from './types.js'; + +// Server-side signed broadcasts are groundwork for future custodial/worker flows. +// The application currently uses this module primarily for confirming client-signed Hive broadcasts. + +export type BroadcastStatusCode = + | 'BROADCAST_CONFIRMED' + | 'BROADCAST_REJECTED' + | 'BROADCAST_CONFIRMATION_TIMEOUT' + | 'BROADCAST_STATUS_UNKNOWN' + | 'NETWORK_CONFIGURATION_ERROR' + | 'NETWORK_MISMATCH' + | 'TRANSACTION_EXPIRED' + | 'PERMANENT_TRANSACTION_ERROR' + | 'TRANSIENT_RPC_ERROR'; + +export type BroadcastFailureClass = 'transient' | 'permanent' | 'unknown'; + +export interface ConfirmedBroadcastResult { + network: HiveNetworkConfig['name']; + transactionId: string; + blockNumber: number; + transactionIndex?: number | undefined; + operationIndexes?: number[] | undefined; + blockchainTimestamp: string; + confirmedAt: string; + confirmationSource: 'rpc' | 'haf' | 'indexer'; + nodeUrl?: string | undefined; + attempts: number; +} + +export class HiveBroadcastError extends Error { + constructor( + public readonly code: BroadcastStatusCode, + message: string, + public readonly failureClass: BroadcastFailureClass, + public readonly diagnostics: Record = {}, + ) { + super(message); + } +} + +export interface HiveBroadcastTransport { + broadcast(nodeUrl: string, transaction: ApiTransaction, signal?: AbortSignal): Promise; + getTransaction?(params: { + transactionId: string; + nodeUrl?: string; + signal?: AbortSignal; + }): Promise; + getBlockHeader?(params: { + blockNumber: number; + nodeUrl?: string; + signal?: AbortSignal; + }): Promise<{ timestamp?: string } | null>; + searchBlocks(params: { + fromBlock?: number; + toBlock?: number; + page?: number; + pageSize?: number; + operationTypes?: number[]; + nodeUrl?: string; + signal?: AbortSignal; + }): Promise; + getHeadBlock(nodeUrl?: string, signal?: AbortSignal): Promise; +} + +export interface ConfirmOperationInput { + transactionId: string; + operationIndex?: number | undefined; + expectedSigner?: string | undefined; + expectedOperation?: HiveLoreOperation | undefined; + blockNumberHint?: number | undefined; + signal?: AbortSignal | undefined; +} + +export class DefaultHiveBroadcastTransport implements HiveBroadcastTransport { + constructor(private readonly network: HiveNetworkConfig) {} + + async broadcast(nodeUrl: string, transaction: ApiTransaction): Promise { + const client = new HiveWaxClient({ + apiEndpoint: nodeUrl, + apiTimeoutMs: DEFAULT_HIVE_RETRY_CONFIG.requestTimeoutMs, + chainId: this.network.chainId, + }); + + await client.broadcastTransaction(transaction); + } + + async searchBlocks(params: { + fromBlock?: number; + toBlock?: number; + page?: number; + pageSize?: number; + operationTypes?: number[]; + signal?: AbortSignal; + }) { + const client = new HafClient( + this.network.hafUrl + ? { + baseUrl: this.network.hafUrl, + requestTimeoutMs: DEFAULT_HIVE_RETRY_CONFIG.requestTimeoutMs, + } + : { requestTimeoutMs: DEFAULT_HIVE_RETRY_CONFIG.requestTimeoutMs }, + ); + return client.searchBlocks({ + ...(params.fromBlock === undefined ? {} : { fromBlock: params.fromBlock }), + ...(params.operationTypes === undefined ? {} : { operationTypes: params.operationTypes }), + ...(params.page === undefined ? {} : { page: params.page }), + ...(params.pageSize === undefined ? {} : { pageSize: params.pageSize }), + ...(params.toBlock === undefined ? {} : { toBlock: params.toBlock }), + ...(params.signal ? { signal: params.signal } : {}), + }); + } + + async getHeadBlock(_nodeUrl?: string, signal?: AbortSignal): Promise { + const client = new HafClient( + this.network.hafUrl + ? { + baseUrl: this.network.hafUrl, + requestTimeoutMs: DEFAULT_HIVE_RETRY_CONFIG.requestTimeoutMs, + } + : { requestTimeoutMs: DEFAULT_HIVE_RETRY_CONFIG.requestTimeoutMs }, + ); + + return client.getHeadBlock(signal); + } + + async getTransaction(params: { + transactionId: string; + nodeUrl?: string; + signal?: AbortSignal; + }): Promise { + const nodeUrl = params.nodeUrl ?? this.network.rpcNodes[0]; + + if (!nodeUrl) { + throw new HiveBroadcastError( + 'NETWORK_CONFIGURATION_ERROR', + 'No Hive RPC nodes are configured for transaction lookup.', + 'permanent', + ); + } + + const response = await fetch(nodeUrl, { + body: JSON.stringify({ + id: 1, + jsonrpc: '2.0', + method: 'condenser_api.get_transaction', + params: [params.transactionId], + }), + headers: { + accept: 'application/json', + 'content-type': 'application/json', + }, + method: 'POST', + signal: createTimeoutSignal(DEFAULT_HIVE_RETRY_CONFIG.requestTimeoutMs, params.signal), + }); + + if (!response.ok) { + throw Object.assign( + new Error(`Hive transaction lookup failed: ${response.status} ${response.statusText}`), + { status: response.status }, + ); + } + + const body = (await response.json()) as { + error?: { message?: string }; + result?: unknown; + }; + + if (body.error) { + const message = body.error.message ?? 'Hive transaction lookup failed.'; + + if (message.toLowerCase().includes('unknown transaction')) { + return null; + } + + throw new Error(message); + } + + const blockchainTimestamp = await this.getBlockTimestamp({ + nodeUrl, + result: body.result, + signal: params.signal, + }); + + return transactionLookupToRows(body.result, params.transactionId, blockchainTimestamp); + } + + private async getBlockTimestamp(input: { + nodeUrl: string; + result: unknown; + signal?: AbortSignal | undefined; + }): Promise { + const blockNumber = getTransactionBlockNumber(input.result); + + const response = await fetch(input.nodeUrl, { + body: JSON.stringify({ + id: 1, + jsonrpc: '2.0', + method: 'condenser_api.get_block_header', + params: [blockNumber], + }), + headers: { + accept: 'application/json', + 'content-type': 'application/json', + }, + method: 'POST', + signal: createTimeoutSignal(DEFAULT_HIVE_RETRY_CONFIG.requestTimeoutMs, input.signal), + }); + + if (!response.ok) { + throw Object.assign( + new Error(`Hive block header lookup failed: ${response.status} ${response.statusText}`), + { status: response.status }, + ); + } + + const body = (await response.json()) as { + error?: { message?: string }; + result?: { timestamp?: unknown }; + }; + + if (body.error) { + throw new Error(body.error.message ?? 'Hive block header lookup failed.'); + } + + const timestamp = body.result?.timestamp; + const normalizedTimestamp = + typeof timestamp === 'string' && !/[zZ]|[+-]\d\d:?\d\d$/.test(timestamp) + ? `${timestamp}Z` + : timestamp; + const parsedTimestamp = + typeof normalizedTimestamp === 'string' ? new Date(normalizedTimestamp) : null; + + if (!parsedTimestamp || Number.isNaN(parsedTimestamp.getTime())) { + throw new HiveBroadcastError( + 'BROADCAST_REJECTED', + 'Confirmed Hive block header did not include a valid timestamp.', + 'permanent', + { + blockNumber, + reason: 'missing_or_invalid_block_timestamp', + }, + ); + } + + return parsedTimestamp.toISOString(); + } +} + +export class HiveNodePool { + private readonly states: Array<{ + url: string; + consecutiveFailures: number; + unhealthyUntil: number; + }>; + private cursor = 0; + + constructor( + nodes: string[], + private readonly retry: HiveRetryConfig, + private readonly now: () => number = () => Date.now(), + ) { + this.states = nodes.map((url) => ({ consecutiveFailures: 0, unhealthyUntil: 0, url })); + } + + current(): string { + const now = this.now(); + + for (let offset = 0; offset < this.states.length; offset += 1) { + const index = (this.cursor + offset) % this.states.length; + const state = this.states[index]; + + if (state && state.unhealthyUntil <= now) { + this.cursor = index; + + return state.url; + } + } + + const fallback = this.states[this.cursor % this.states.length]; + + if (!fallback) { + throw new HiveBroadcastError( + 'NETWORK_CONFIGURATION_ERROR', + 'No Hive RPC nodes are configured.', + 'permanent', + ); + } + + return fallback.url; + } + + reportSuccess(nodeUrl: string) { + const state = this.find(nodeUrl); + + if (state) { + state.consecutiveFailures = 0; + state.unhealthyUntil = 0; + } + } + + reportTransientFailure(nodeUrl: string) { + const state = this.find(nodeUrl); + + if (!state) { + return; + } + + state.consecutiveFailures += 1; + + if (state.consecutiveFailures >= this.retry.maxConsecutiveNodeFailures) { + state.unhealthyUntil = this.now() + this.retry.nodeCooldownMs; + this.cursor = (this.states.indexOf(state) + 1) % this.states.length; + } + } + + private find(nodeUrl: string) { + return this.states.find((state) => state.url === nodeUrl); + } +} + +export class HiveReliableBroadcaster { + private readonly retry: HiveRetryConfig; + private readonly pool: HiveNodePool; + private readonly confirmationPool: HiveNodePool; + + constructor( + private readonly network: HiveNetworkConfig, + private readonly transport: HiveBroadcastTransport = new DefaultHiveBroadcastTransport(network), + retry: Partial = {}, + private readonly clock: { + now(): number; + sleep(ms: number, signal?: AbortSignal): Promise; + random(): number; + } = systemClock, + ) { + this.retry = { ...DEFAULT_HIVE_RETRY_CONFIG, ...retry }; + this.pool = new HiveNodePool(network.rpcNodes, this.retry, () => this.clock.now()); + this.confirmationPool = new HiveNodePool(network.rpcNodes, this.retry, () => this.clock.now()); + } + + async broadcastSignedTransaction(input: { + transaction: ApiTransaction; + transactionId: string; + expectedSigner?: string | undefined; + expectedOperation?: HiveLoreOperation | undefined; + signal?: AbortSignal | undefined; + }): Promise { + const startedAt = this.clock.now(); + let attempts = 0; + let lastError: HiveBroadcastError | null = null; + + while (attempts < this.retry.maxAttempts) { + throwIfAborted(input.signal); + + if (this.clock.now() - startedAt > this.retry.totalDeadlineMs) { + break; + } + + attempts += 1; + const nodeUrl = this.pool.current(); + const remainingDeadlineMs = this.retry.totalDeadlineMs - (this.clock.now() - startedAt); + + try { + await this.transport.broadcast(nodeUrl, input.transaction, input.signal); + this.pool.reportSuccess(nodeUrl); + + return await this.confirmAfterBroadcast({ + attempts, + expectedOperation: input.expectedOperation, + expectedSigner: input.expectedSigner, + confirmationTimeoutMs: Math.min(this.retry.confirmationTimeoutMs, remainingDeadlineMs), + nodeUrl, + signal: input.signal, + transactionId: input.transactionId, + }); + } catch (error) { + const classified = classifyHiveBroadcastError(error); + lastError = classified; + + if (classified.failureClass === 'permanent') { + throw classified; + } + + this.pool.reportTransientFailure(nodeUrl); + + const ambiguous = isAmbiguousBroadcastError(classified); + const confirmation = ambiguous + ? await this.tryConfirm({ + attempts, + confirmationTimeoutMs: Math.min( + this.retry.confirmationTimeoutMs, + Math.max(0, this.retry.totalDeadlineMs - (this.clock.now() - startedAt)), + ), + expectedOperation: input.expectedOperation, + expectedSigner: input.expectedSigner, + nodeUrl, + signal: input.signal, + transactionId: input.transactionId, + }) + : null; + + if (confirmation) { + return confirmation; + } + + if (attempts >= this.retry.maxAttempts) { + break; + } + + await this.clock.sleep( + delayForAttempt(attempts, this.retry, this.clock.random()), + input.signal, + ); + } + } + + throw new HiveBroadcastError( + lastError?.code === 'TRANSIENT_RPC_ERROR' + ? 'BROADCAST_STATUS_UNKNOWN' + : 'BROADCAST_CONFIRMATION_TIMEOUT', + 'Hive transaction broadcast status is unknown after bounded retries.', + 'unknown', + { + attempts, + network: this.network.name, + transactionId: input.transactionId, + }, + ); + } + + async confirmTransaction(input: ConfirmOperationInput): Promise { + const operation = await this.confirmTransactionOperation(input); + + return toConfirmedBroadcastResult({ + attempts: 0, + network: this.network, + operation, + }); + } + + async confirmTransactionOperation( + input: ConfirmOperationInput, + ): Promise { + const operation = await pollForConfirmedOperation({ + confirmationTimeoutMs: this.retry.confirmationTimeoutMs, + clock: this.clock, + nodePool: this.confirmationPool, + input, + network: this.network, + pollIntervalMs: this.retry.confirmationPollIntervalMs, + transport: this.transport, + }); + + if (!operation) { + throw new HiveBroadcastError( + 'BROADCAST_CONFIRMATION_TIMEOUT', + 'Hive transaction was not found before the confirmation timeout.', + 'unknown', + { + network: this.network.name, + transactionId: input.transactionId, + }, + ); + } + + return operation; + } + + private async confirmAfterBroadcast(input: { + attempts: number; + transactionId: string; + expectedSigner?: string | undefined; + expectedOperation?: HiveLoreOperation | undefined; + confirmationTimeoutMs?: number | undefined; + nodeUrl: string; + signal?: AbortSignal | undefined; + }): Promise { + const confirmed = await this.tryConfirm(input); + + if (confirmed) { + return confirmed; + } + + throw new HiveBroadcastError( + 'BROADCAST_STATUS_UNKNOWN', + 'Hive transaction broadcast was accepted but confirmation is still pending.', + 'unknown', + { + attempts: input.attempts, + network: this.network.name, + transactionId: input.transactionId, + }, + ); + } + + private async tryConfirm(input: { + attempts: number; + transactionId: string; + expectedSigner?: string | undefined; + expectedOperation?: HiveLoreOperation | undefined; + confirmationTimeoutMs?: number | undefined; + nodeUrl: string; + signal?: AbortSignal | undefined; + }): Promise { + let operation: NormalizedHiveOperation | null; + + try { + operation = await pollForConfirmedOperation({ + confirmationTimeoutMs: input.confirmationTimeoutMs ?? this.retry.confirmationTimeoutMs, + clock: this.clock, + nodePool: this.confirmationPool, + input, + network: this.network, + pollIntervalMs: this.retry.confirmationPollIntervalMs, + transport: this.transport, + }); + } catch (error) { + if (error instanceof HiveBroadcastError && error.code === 'BROADCAST_CONFIRMATION_TIMEOUT') { + return null; + } + + throw error; + } + + return operation + ? toConfirmedBroadcastResult({ + attempts: input.attempts, + network: this.network, + nodeUrl: sanitizeHiveNodeUrl(input.nodeUrl), + operation, + }) + : null; + } +} + +export function classifyHiveBroadcastError(error: unknown): HiveBroadcastError { + if (error instanceof HiveBroadcastError) { + return error; + } + + const detail = error instanceof Error ? error.message : String(error); + const lower = detail.toLowerCase(); + const status = + typeof error === 'object' && error ? Number((error as { status?: unknown }).status) : 0; + + if (lower.includes('expired')) { + return new HiveBroadcastError('TRANSACTION_EXPIRED', 'Hive transaction expired.', 'permanent'); + } + + if ( + lower.includes('missing required signature') || + lower.includes('invalid signature') || + lower.includes('tx_missing_posting_auth') || + lower.includes('insufficient authority') || + lower.includes('malformed') || + lower.includes('parse') || + lower.includes('insufficient rc') || + lower.includes('resource credits') + ) { + return new HiveBroadcastError( + 'PERMANENT_TRANSACTION_ERROR', + 'Hive transaction was permanently rejected.', + 'permanent', + ); + } + + if (lower.includes('block metadata') || lower.includes('transaction id mismatch')) { + return new HiveBroadcastError( + 'BROADCAST_REJECTED', + 'Hive confirmation failed closed on invalid read-back metadata.', + 'permanent', + { reason: lower.includes('transaction id mismatch') ? 'transaction_id_mismatch' : undefined }, + ); + } + + if ( + status === 408 || + status === 429 || + status >= 500 || + lower.includes('timeout') || + lower.includes('timed out') || + lower.includes('econnreset') || + lower.includes('enotfound') || + lower.includes('network') || + lower.includes('temporarily unavailable') || + lower.includes('bad gateway') || + lower.includes('already known') || + lower.includes('duplicate transaction') + ) { + return new HiveBroadcastError( + 'TRANSIENT_RPC_ERROR', + 'Hive RPC request failed transiently.', + 'transient', + { status: status || undefined }, + ); + } + + return new HiveBroadcastError( + 'BROADCAST_STATUS_UNKNOWN', + 'Hive broadcast failed with an unclassified error.', + 'unknown', + ); +} + +export function delayForAttempt(attempt: number, retry: HiveRetryConfig, random: number): number { + const base = Math.min( + retry.maxDelayMs, + retry.initialDelayMs * retry.backoffMultiplier ** Math.max(0, attempt - 1), + ); + const jitter = base * retry.jitterRatio * (random * 2 - 1); + + return Math.max(1, Math.round(base + jitter)); +} + +export async function pollForConfirmedOperation(input: { + input: ConfirmOperationInput; + transport: HiveBroadcastTransport; + network: HiveNetworkConfig; + nodePool?: HiveNodePool | undefined; + confirmationTimeoutMs: number; + pollIntervalMs: number; + clock: { + now(): number; + sleep(ms: number, signal?: AbortSignal): Promise; + }; +}): Promise { + const startedAt = input.clock.now(); + let fromBlock = input.input.blockNumberHint; + const pageSize = 100; + let lastFailure: HiveBroadcastError | null = null; + let sawTransaction = false; + + while (input.clock.now() - startedAt <= input.confirmationTimeoutMs) { + throwIfAborted(input.input.signal); + + const nodeUrl = input.nodePool?.current(); + + try { + if (input.transport.getTransaction) { + const transactionRows = await input.transport.getTransaction({ + ...(nodeUrl ? { nodeUrl } : {}), + ...(input.input.signal ? { signal: input.input.signal } : {}), + transactionId: input.input.transactionId, + }); + + if (transactionRows) { + sawTransaction = true; + const confirmed = findAndVerifyOperation(transactionRows, input.input); + + if (confirmed) { + if (nodeUrl) { + input.nodePool?.reportSuccess(nodeUrl); + } + + return confirmed; + } + } + + if (nodeUrl) { + input.nodePool?.reportSuccess(nodeUrl); + } + + await input.clock.sleep(input.pollIntervalMs, input.input.signal); + continue; + } + + const head = fromBlock + ? fromBlock + : await input.transport.getHeadBlock(nodeUrl, input.input.signal); + const searchFromBlock = fromBlock ?? Math.max(1, head - 1_200); + const searchToBlock = fromBlock ?? head; + let page = 1; + + while (input.clock.now() - startedAt <= input.confirmationTimeoutMs) { + throwIfAborted(input.input.signal); + + const searchPage = normalizeSearchPage( + await input.transport.searchBlocks({ + fromBlock: searchFromBlock, + ...(nodeUrl ? { nodeUrl } : {}), + operationTypes: [HIVE_CUSTOM_JSON_OPERATION_TYPE], + page, + pageSize, + toBlock: searchToBlock, + ...(input.input.signal ? { signal: input.input.signal } : {}), + }), + ); + const confirmed = findAndVerifyOperation(searchPage.operations, input.input); + + if (confirmed) { + if (nodeUrl) { + input.nodePool?.reportSuccess(nodeUrl); + } + + return confirmed; + } + + if ( + searchPage.totalPages !== undefined + ? page >= searchPage.totalPages + : searchPage.operations.length < pageSize + ) { + break; + } + + page += 1; + } + + if (nodeUrl) { + input.nodePool?.reportSuccess(nodeUrl); + } + } catch (error) { + const classified = classifyHiveBroadcastError(error); + lastFailure = classified; + + if (classified.failureClass === 'permanent') { + throw classified; + } + + if (nodeUrl) { + input.nodePool?.reportTransientFailure(nodeUrl); + } + } + + fromBlock = undefined; + await input.clock.sleep(input.pollIntervalMs, input.input.signal); + } + + if (lastFailure) { + throw new HiveBroadcastError( + 'BROADCAST_CONFIRMATION_TIMEOUT', + 'Hive transaction was not confirmed before the timeout.', + 'unknown', + { + lastFailure: { + code: lastFailure.code, + diagnostics: lastFailure.diagnostics, + failureClass: lastFailure.failureClass, + message: lastFailure.message, + }, + reason: 'last_rpc_or_response_failure', + transactionId: input.input.transactionId, + }, + ); + } + + if (!sawTransaction) { + throw new HiveBroadcastError( + 'BROADCAST_CONFIRMATION_TIMEOUT', + 'Hive transaction was not found before the confirmation timeout.', + 'unknown', + { + reason: 'transaction_not_found_yet', + transactionId: input.input.transactionId, + }, + ); + } + + return null; +} + +export function findAndVerifyOperation( + rows: HafOperationRow[], + input: ConfirmOperationInput, +): NormalizedHiveOperation | null { + for (const row of rows) { + if (!rowMatchesTransaction(row, input.transactionId)) { + continue; + } + + if (!rowMatchesOperationIndex(row, input.operationIndex)) { + continue; + } + + let operation: NormalizedHiveOperation; + + try { + operation = normalizeHafOperation(row); + } catch (error) { + if (input.operationIndex === undefined) { + continue; + } + + throw new HiveBroadcastError( + 'BROADCAST_REJECTED', + 'Confirmed Hive row for the transaction could not be normalized.', + 'permanent', + { + cause: error instanceof Error ? error.message : String(error), + reason: 'operation_normalization_failed', + }, + ); + } + + const verification = verifyHiveLoreOperation({ + ...(input.expectedSigner ? { expectedSigner: input.expectedSigner } : {}), + operation: operation.operation, + }); + + if (!verification.ok) { + throw new HiveBroadcastError( + 'BROADCAST_REJECTED', + verification.reason ?? 'Confirmed Hive operation did not pass verification.', + 'permanent', + { reason: verification.reason ?? 'operation_verification_failed' }, + ); + } + + if (input.expectedOperation && !operationsEqual(operation.operation, input.expectedOperation)) { + throw new HiveBroadcastError( + 'BROADCAST_REJECTED', + 'Confirmed Hive operation does not match the expected operation.', + 'permanent', + { reason: 'payload_mismatch' }, + ); + } + + return operation; + } + + return null; +} + +function toConfirmedBroadcastResult(input: { + network: HiveNetworkConfig; + operation: NormalizedHiveOperation; + attempts: number; + nodeUrl?: string | undefined; +}): ConfirmedBroadcastResult { + return { + attempts: input.attempts, + blockchainTimestamp: input.operation.blockchainTimestamp.toISOString(), + blockNumber: Number(input.operation.blockNumber), + confirmationSource: 'haf', + confirmedAt: new Date().toISOString(), + network: input.network.name, + nodeUrl: input.nodeUrl, + operationIndexes: [input.operation.operationIndex], + transactionId: input.operation.transactionId, + }; +} + +function isAmbiguousBroadcastError(error: HiveBroadcastError) { + return error.failureClass !== 'permanent'; +} + +function operationsEqual(left: HiveLoreOperation, right: HiveLoreOperation) { + return hashCanonicalJson(left) === hashCanonicalJson(right); +} + +function normalizeSearchPage( + page: HafOperationRow[] | { operations: HafOperationRow[]; totalPages?: number }, +) { + return Array.isArray(page) ? { operations: page } : page; +} + +function transactionLookupToRows( + result: unknown, + transactionId: string, + blockchainTimestamp: string, +): HafOperationRow[] | null { + if (!result || typeof result !== 'object') { + return null; + } + + const transaction = result as { + block_num?: number | string; + blockNumber?: number | string; + block?: number | string; + operations?: unknown; + transaction_id?: string; + transactionId?: string; + trx_id?: string; + }; + + if (!Array.isArray(transaction.operations)) { + return []; + } + + const resolvedTransactionId = + transaction.transaction_id ?? transaction.transactionId ?? transaction.trx_id ?? transactionId; + + if (resolvedTransactionId !== transactionId) { + throw new HiveBroadcastError( + 'BROADCAST_REJECTED', + 'Hive transaction lookup returned a transaction ID mismatch.', + 'permanent', + { + reason: 'transaction_id_mismatch', + requestedTransactionId: transactionId, + returnedTransactionId: resolvedTransactionId, + }, + ); + } + + return transaction.operations.map((operationValue, index) => { + const blockNumber = transaction.block_num ?? transaction.blockNumber ?? transaction.block; + + return { + ...(blockNumber === undefined ? {} : { block_num: blockNumber }), + operation: normalizeCondenserOperation(operationValue), + operation_id: index, + timestamp: blockchainTimestamp, + transaction_id: resolvedTransactionId, + }; + }); +} + +function getTransactionBlockNumber(result: unknown): number { + if (!result || typeof result !== 'object') { + throw new HiveBroadcastError( + 'BROADCAST_REJECTED', + 'Confirmed Hive transaction lookup did not include usable block metadata.', + 'permanent', + { reason: 'missing_transaction_result' }, + ); + } + + const transaction = result as { + block_num?: number | string; + blockNumber?: number | string; + block?: number | string; + }; + const rawBlockNumber = transaction.block_num ?? transaction.blockNumber ?? transaction.block; + const blockNumber = typeof rawBlockNumber === 'string' ? Number(rawBlockNumber) : rawBlockNumber; + + if (typeof blockNumber !== 'number' || !Number.isInteger(blockNumber) || blockNumber <= 0) { + throw new HiveBroadcastError( + 'BROADCAST_REJECTED', + 'Confirmed Hive transaction lookup did not include usable block metadata.', + 'permanent', + { reason: 'missing_or_invalid_block_number' }, + ); + } + + return blockNumber; +} + +function normalizeCondenserOperation(operationValue: unknown): unknown { + if (Array.isArray(operationValue) && operationValue.length >= 2) { + const [type, value] = operationValue; + + if (type === 'comment') { + return { comment_operation: value }; + } + + if (type === 'custom_json') { + return { custom_json_operation: value }; + } + } + + return operationValue; +} + +function rowMatchesTransaction(row: HafOperationRow, transactionId: string) { + return (row.transaction_id ?? row.transactionId ?? row.trx_id) === transactionId; +} + +function rowMatchesOperationIndex(row: HafOperationRow, operationIndex: number | undefined) { + if (operationIndex === undefined) { + return true; + } + + const rawIndex = row.operation_id ?? row.operationIndex ?? row.op_in_trx ?? row.op_pos; + const numericIndex = typeof rawIndex === 'string' ? Number(rawIndex) : rawIndex; + + return numericIndex === operationIndex; +} + +function throwIfAborted(signal: AbortSignal | undefined) { + if (signal?.aborted) { + throw new HiveBroadcastError( + 'BROADCAST_STATUS_UNKNOWN', + 'Hive broadcast was cancelled.', + 'unknown', + ); + } +} + +function createTimeoutSignal(timeoutMs: number, parentSignal?: AbortSignal): AbortSignal { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), timeoutMs); + + if (parentSignal?.aborted) { + clearTimeout(timeout); + controller.abort(); + return controller.signal; + } + + parentSignal?.addEventListener( + 'abort', + () => { + clearTimeout(timeout); + controller.abort(); + }, + { once: true }, + ); + + controller.signal.addEventListener('abort', () => clearTimeout(timeout), { once: true }); + + return controller.signal; +} + +const systemClock = { + now: () => Date.now(), + random: () => Math.random(), + sleep(ms: number, signal?: AbortSignal) { + return new Promise((resolve, reject) => { + const timeout = setTimeout(resolve, ms); + + signal?.addEventListener( + 'abort', + () => { + clearTimeout(timeout); + reject( + new HiveBroadcastError( + 'BROADCAST_STATUS_UNKNOWN', + 'Hive broadcast was cancelled.', + 'unknown', + ), + ); + }, + { once: true }, + ); + }); + }, +}; diff --git a/apps/api/src/lib/hive/client.ts b/apps/api/src/lib/hive/client.ts new file mode 100644 index 0000000..52b0ff6 --- /dev/null +++ b/apps/api/src/lib/hive/client.ts @@ -0,0 +1,64 @@ +import { env } from '../../config/env.js'; +import { HiveReliableBroadcaster } from './broadcast-reliability.js'; +import { HafClient } from './haf-client.js'; +import { HIVELORE_CUSTOM_JSON_ID } from './constants.js'; +import { + buildHiveNetworkConfig, + validateHiveRetryConfig, + type HiveRetryConfig, +} from './network-config.js'; +import { HiveWaxClient } from './wax-client.js'; + +export function createHiveNetworkConfig() { + return buildHiveNetworkConfig({ + customJsonId: HIVELORE_CUSTOM_JSON_ID, + mainnetChainId: env.HIVE_MAINNET_CHAIN_ID, + mainnetHafUrl: env.HIVE_MAINNET_HAF_URL, + mainnetRpcNodes: env.HIVE_MAINNET_RPC_NODES || env.HIVE_RPC_URL, + nodeEnv: env.NODE_ENV, + }); +} + +export function createHiveRetryConfig(): HiveRetryConfig { + return validateHiveRetryConfig({ + backoffMultiplier: env.HIVE_BROADCAST_BACKOFF_MULTIPLIER, + confirmationPollIntervalMs: env.HIVE_CONFIRMATION_POLL_INTERVAL_MS, + confirmationTimeoutMs: env.HIVE_CONFIRMATION_TIMEOUT_MS, + initialDelayMs: env.HIVE_BROADCAST_INITIAL_DELAY_MS, + jitterRatio: env.HIVE_BROADCAST_JITTER_RATIO, + maxAttempts: env.HIVE_BROADCAST_MAX_ATTEMPTS, + maxConsecutiveNodeFailures: env.HIVE_NODE_MAX_CONSECUTIVE_FAILURES, + maxDelayMs: env.HIVE_BROADCAST_MAX_DELAY_MS, + nodeCooldownMs: env.HIVE_NODE_COOLDOWN_MS, + requestTimeoutMs: env.HIVE_BROADCAST_TIMEOUT_MS, + totalDeadlineMs: env.HIVE_BROADCAST_TOTAL_DEADLINE_MS, + }); +} + +export function createHiveWaxClient() { + const network = createHiveNetworkConfig(); + const [apiEndpoint] = network.rpcNodes; + + if (!apiEndpoint) { + throw new Error('At least one Hive RPC node must be configured.'); + } + + return new HiveWaxClient({ + apiEndpoint, + appName: env.HIVELORE_APP_ID, + apiTimeoutMs: env.HIVE_BROADCAST_TIMEOUT_MS, + chainId: network.chainId, + }); +} + +export function createHafClient() { + const network = createHiveNetworkConfig(); + + return new HafClient({ + baseUrl: network.hafUrl ?? env.HAF_API_URL, + }); +} + +export function createHiveReliableBroadcaster() { + return new HiveReliableBroadcaster(createHiveNetworkConfig(), undefined, createHiveRetryConfig()); +} diff --git a/apps/api/src/lib/hive/constants.ts b/apps/api/src/lib/hive/constants.ts new file mode 100644 index 0000000..5995fc2 --- /dev/null +++ b/apps/api/src/lib/hive/constants.ts @@ -0,0 +1,11 @@ +export const HIVE_MAINNET_CHAIN_ID = + 'beeab0de00000000000000000000000000000000000000000000000000000000'; + +export const DEFAULT_HIVE_RPC_URL = 'https://api.hive.blog'; +export const DEFAULT_HAF_API_URL = 'https://api.hive.blog/hafbe-api'; +export const DEFAULT_HIVELORE_APP_ID = 'hivelore/0.1.0'; +export const HIVELORE_CUSTOM_JSON_ID = 'hivelore'; +export const HIVELORE_SMOKE_CUSTOM_JSON_ID = 'hivelore_smoke'; +export const HIVE_CUSTOM_JSON_OPERATION_TYPE = 18; + +export const HIVELORE_SCHEMA_VERSION = 1; diff --git a/apps/api/src/lib/hive/haf-client.test.ts b/apps/api/src/lib/hive/haf-client.test.ts new file mode 100644 index 0000000..08a1ca6 --- /dev/null +++ b/apps/api/src/lib/hive/haf-client.test.ts @@ -0,0 +1,91 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { HafClient, parseBlockSearchPage } from './haf-client.js'; + +function createJsonResponse(body: unknown, ok = true): Response { + return { + ok, + status: ok ? 200 : 500, + statusText: ok ? 'OK' : 'Server Error', + async json() { + return body; + }, + } as Response; +} + +describe('HAF client', () => { + test('uses the live HAFBE last-synced-block path', async () => { + const urls: string[] = []; + const client = new HafClient({ + baseUrl: 'https://example.test/hafbe-api', + async fetchImpl(url) { + urls.push(url.toString()); + return createJsonResponse(108500881); + }, + }); + + assert.equal(await client.getLatestSyncedBlock(), 108500881); + assert.deepEqual(urls, ['https://example.test/hafbe-api/last-synced-block']); + }); + + test('returns operations_result from the live HAFBE comment operations wrapper', async () => { + const urls: string[] = []; + const client = new HafClient({ + baseUrl: 'https://example.test/hafbe-api', + async fetchImpl(url) { + urls.push(url.toString()); + return createJsonResponse({ + total_operations: 1, + total_pages: 1, + operations_result: [ + { + op: { + type: 'comment_operation', + value: { + author: 'alice', + permlink: 'hello', + }, + }, + block: 123, + trx_id: 'abc', + op_pos: 0, + timestamp: '2026-07-25T18:00:00', + }, + ], + }); + }, + }); + + const operations = await client.getCommentOperations('alice', 'hello'); + + assert.equal(operations.length, 1); + assert.equal(operations[0]?.trx_id, 'abc'); + assert.deepEqual(urls, [ + 'https://example.test/hafbe-api/accounts/alice/operations/comments/hello', + ]); + }); + + test('parses block-search wrappers into operation pages', () => { + assert.deepEqual( + parseBlockSearchPage({ + page: '2', + total_pages: '3', + operations_result: [ + { + block: 123, + }, + ], + }), + { + page: 2, + totalPages: 3, + operations: [ + { + block: 123, + }, + ], + }, + ); + }); +}); diff --git a/apps/api/src/lib/hive/haf-client.ts b/apps/api/src/lib/hive/haf-client.ts new file mode 100644 index 0000000..619394f --- /dev/null +++ b/apps/api/src/lib/hive/haf-client.ts @@ -0,0 +1,156 @@ +import { DEFAULT_HAF_API_URL } from './constants.js'; +import type { HafBlockSearchPage, HafOperationRow } from './types.js'; + +export interface HafClientOptions { + baseUrl?: string; + fetchImpl?: typeof fetch; + requestTimeoutMs?: number; +} + +export class HafClient { + private readonly baseUrl: string; + private readonly fetchImpl: typeof fetch; + private readonly requestTimeoutMs: number; + + constructor(options: HafClientOptions = {}) { + this.baseUrl = (options.baseUrl ?? DEFAULT_HAF_API_URL).replace(/\/$/, ''); + this.fetchImpl = options.fetchImpl ?? fetch; + this.requestTimeoutMs = options.requestTimeoutMs ?? 10_000; + } + + async getHeadBlock(signal?: AbortSignal): Promise { + return this.getLatestSyncedBlock(signal); + } + + async getLatestSyncedBlock(signal?: AbortSignal): Promise { + const value = await this.getJson('/last-synced-block', undefined, signal); + + if (typeof value !== 'number' || !Number.isInteger(value)) { + throw new Error('HAF last-synced-block response did not include a block number.'); + } + + return value; + } + + async getCommentOperations(author: string, permlink: string): Promise { + const response = await this.getJson<{ + total_operations: number; + total_pages: number; + operations_result: HafOperationRow[]; + }>( + `/accounts/${encodeURIComponent(author)}/operations/comments/${encodeURIComponent(permlink)}`, + ); + + return response.operations_result; + } + + async searchBlocks(params: { + operationTypes?: number[]; + fromBlock?: number; + toBlock?: number; + page?: number; + pageSize?: number; + signal?: AbortSignal; + }): Promise { + const response = await this.getJson( + '/block-search', + { + 'operation-types': params.operationTypes?.join(','), + 'from-block': params.fromBlock, + 'to-block': params.toBlock, + page: params.page, + 'page-size': params.pageSize, + }, + params.signal, + ); + + return parseBlockSearchPage(response); + } + + private async getJson( + path: string, + params?: Record, + signal?: AbortSignal, + ): Promise { + const url = new URL(`${this.baseUrl}${path}`); + + for (const [key, value] of Object.entries(params ?? {})) { + if (value !== undefined) { + url.searchParams.set(key, String(value)); + } + } + + const response = await this.fetchImpl(url, { + signal: createTimeoutSignal(this.requestTimeoutMs, signal), + }); + + if (!response.ok) { + throw new Error(`HAF request failed: ${response.status} ${response.statusText}`); + } + + return (await response.json()) as T; + } +} + +function createTimeoutSignal(timeoutMs: number, parentSignal?: AbortSignal): AbortSignal { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), timeoutMs); + + if (parentSignal?.aborted) { + clearTimeout(timeout); + controller.abort(); + return controller.signal; + } + + parentSignal?.addEventListener( + 'abort', + () => { + clearTimeout(timeout); + controller.abort(); + }, + { once: true }, + ); + + controller.signal.addEventListener('abort', () => clearTimeout(timeout), { once: true }); + + return controller.signal; +} + +export function parseBlockSearchPage(response: unknown): HafBlockSearchPage { + if (Array.isArray(response)) { + return { operations: response as HafOperationRow[] }; + } + + if (!response || typeof response !== 'object') { + throw new Error('HAF block-search response was not an object.'); + } + + const source = response as Record; + const operations = + source.operations_result ?? source.operations ?? source.results ?? source.rows ?? source.data; + + if (!Array.isArray(operations)) { + throw new Error('HAF block-search response did not include operation rows.'); + } + + const page = optionalInteger(source.page); + const totalPages = optionalInteger(source.total_pages ?? source.totalPages); + + return { + operations: operations as HafOperationRow[], + ...(page === undefined ? {} : { page }), + ...(totalPages === undefined ? {} : { totalPages }), + }; +} + +function optionalInteger(value: unknown): number | undefined { + if (value === undefined || value === null) { + return undefined; + } + + const numericValue = typeof value === 'string' ? Number(value) : value; + + return typeof numericValue === 'number' && Number.isInteger(numericValue) + ? numericValue + : undefined; +} diff --git a/apps/api/src/lib/hive/index.ts b/apps/api/src/lib/hive/index.ts new file mode 100644 index 0000000..eda02fe --- /dev/null +++ b/apps/api/src/lib/hive/index.ts @@ -0,0 +1,14 @@ +export * from './broadcast-reliability.js'; +export * from './client.js'; +export * from './constants.js'; +export * from './haf-client.js'; +export * from './network-config.js'; +export * from './mainnet-smoke.js'; +export * from './operations.js'; +export * from './publishing.js'; +export * from './projection.js'; +export * from './signers.js'; +export * from './smoke-operation.js'; +export * from './types.js'; +export * from './verification.js'; +export * from './wax-client.js'; diff --git a/apps/api/src/lib/hive/mainnet-smoke.test.ts b/apps/api/src/lib/hive/mainnet-smoke.test.ts new file mode 100644 index 0000000..fbcb6ce --- /dev/null +++ b/apps/api/src/lib/hive/mainnet-smoke.test.ts @@ -0,0 +1,178 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; +import type { ApiOperation, ApiTransaction } from '@hiveio/wax'; + +import { formatHiveMainnetSmokeResult, runHiveMainnetSmoke } from './mainnet-smoke.js'; +import { + HIVELORE_MAINNET_SMOKE_PAYLOAD, + assertPostingAuthorityOnly, + buildHiveLoreSmokeCustomJsonOperation, + buildMainnetSmokeNetworkFromEnv, + verifyHiveLoreSmokeOperation, +} from './smoke-operation.js'; +import type { BuiltHiveTransaction, SignedHiveTransaction } from './types.js'; +import type { HiveWaxClient } from './wax-client.js'; + +const network = buildMainnetSmokeNetworkFromEnv({ + HIVE_MAINNET_RPC_NODES: 'https://node-a.test,https://node-b.test', + NODE_ENV: 'test', +}); + +const unsignedTransaction: ApiTransaction = { + expiration: '2026-08-15T12:10:00', + extensions: [], + operations: [], + ref_block_num: 1, + ref_block_prefix: 2, + signatures: [], +}; + +describe('Hive mainnet smoke test', () => { + test('builds the hivelore_smoke operation with posting authority only', () => { + const operation = buildHiveLoreSmokeCustomJsonOperation('Mira-Vale.Dev'); + const customJson = operation.custom_json_operation; + + assert.ok(customJson); + assert.equal(customJson.id, 'hivelore_smoke'); + assert.deepEqual(customJson.required_auths, []); + assert.deepEqual(customJson.required_posting_auths, ['mira-vale.dev']); + assert.deepEqual(JSON.parse(customJson.json), HIVELORE_MAINNET_SMOKE_PAYLOAD); + assert.deepEqual(verifyHiveLoreSmokeOperation({ expectedSigner: 'mira-vale.dev', operation }), { + ok: true, + payload: HIVELORE_MAINNET_SMOKE_PAYLOAD, + signer: 'mira-vale.dev', + }); + }); + + test('fails closed if a smoke operation requests active authority', () => { + const operation = buildHiveLoreSmokeCustomJsonOperation('mira-vale.dev'); + + assert.ok(operation.custom_json_operation); + operation.custom_json_operation.required_auths = ['mira-vale.dev']; + operation.custom_json_operation.required_posting_auths = []; + + assert.throws(() => assertPostingAuthorityOnly(operation), /BUG/); + assert.deepEqual(verifyHiveLoreSmokeOperation({ expectedSigner: 'mira-vale.dev', operation }), { + ok: false, + reason: 'Smoke custom_json must not require active authority.', + }); + }); + + test('rejects non-mainnet smoke configuration before broadcasting', () => { + assert.throws( + () => + buildMainnetSmokeNetworkFromEnv({ + HIVE_MAINNET_CHAIN_ID: '0'.repeat(64), + HIVE_MAINNET_RPC_NODES: 'https://node-a.test', + NODE_ENV: 'test', + }), + /mainnet chain ID/, + ); + }); + + test('broadcasts through the reliability path and confirms by transaction read-back', async () => { + let builtOperation = buildHiveLoreSmokeCustomJsonOperation('mira-vale.dev'); + const signedTransaction: ApiTransaction = { + ...unsignedTransaction, + signatures: ['stub-signature'], + }; + const transactionLookups: string[] = []; + const blockSearches: string[] = []; + const broadcasts: string[] = []; + const customJsonOperation = builtOperation.custom_json_operation; + + assert.ok(customJsonOperation); + + const transactionOperations: ApiOperation[] = [ + { + type: 'custom_json_operation', + value: customJsonOperation as unknown as Record, + }, + ]; + const waxClient = { + async buildTransaction(operations: Parameters[0]) { + builtOperation = operations[0] ?? builtOperation; + + return { + binaryHex: 'binary', + requiredAuthorities: { posting: ['mira-vale.dev'] }, + transaction: { + ...unsignedTransaction, + operations: transactionOperations, + }, + unsignedBinaryHex: 'unsigned-binary', + } satisfies BuiltHiveTransaction; + }, + async signTransaction(): Promise { + return { + binaryHex: 'signed-binary', + transaction: signedTransaction, + transactionId: 'tx-smoke-1', + } satisfies SignedHiveTransaction; + }, + } as unknown as HiveWaxClient; + + const result = await runHiveMainnetSmoke({ + account: 'mira-vale.dev', + network, + postingKey: 'stub-not-used-by-fake-client', + transport: { + async broadcast(nodeUrl) { + broadcasts.push(nodeUrl); + }, + async getHeadBlock() { + return 101; + }, + async getTransaction(params) { + transactionLookups.push(params.nodeUrl ?? 'none'); + + return [ + { + block_num: 101, + operation: builtOperation, + operation_id: 0, + timestamp: '2026-08-15T12:00:00.000Z', + transaction_id: params.transactionId, + }, + ]; + }, + async searchBlocks(params) { + blockSearches.push(params.nodeUrl ?? 'none'); + + return []; + }, + }, + waxClient, + }); + + assert.deepEqual(broadcasts, ['https://node-a.test']); + assert.deepEqual(transactionLookups, ['https://node-a.test']); + assert.deepEqual(blockSearches, []); + assert.deepEqual(result, { + blockNumber: 101, + blockTimestamp: '2026-08-15T12:00:00.000Z', + rpcNodeUsed: 'https://node-a.test', + transactionId: 'tx-smoke-1', + verificationSummary: 'PASS', + }); + }); + + test('formats only the approved confirmation fields', () => { + assert.equal( + formatHiveMainnetSmokeResult({ + blockNumber: 101, + blockTimestamp: '2026-08-15T12:00:00.000Z', + rpcNodeUsed: 'https://node-a.test', + transactionId: 'tx-smoke-1', + verificationSummary: 'PASS', + }), + [ + 'transaction ID: tx-smoke-1', + 'block number: 101', + 'block timestamp: 2026-08-15T12:00:00.000Z', + 'RPC node used: https://node-a.test', + 'verification summary: PASS', + ].join('\n'), + ); + }); +}); diff --git a/apps/api/src/lib/hive/mainnet-smoke.ts b/apps/api/src/lib/hive/mainnet-smoke.ts new file mode 100644 index 0000000..48dec13 --- /dev/null +++ b/apps/api/src/lib/hive/mainnet-smoke.ts @@ -0,0 +1,129 @@ +import type { ApiTransaction } from '@hiveio/wax'; +import { PrivateKey, cryptoUtils } from '@hiveio/dhive'; + +import type { HiveNetworkConfig } from './network-config.js'; +import { hiveAccountNameSchema } from './operations.js'; +import { HiveReliableBroadcaster, type HiveBroadcastTransport } from './broadcast-reliability.js'; +import { HiveWaxClient } from './wax-client.js'; +import { + assertPostingAuthorityOnly, + buildHiveLoreSmokeCustomJsonOperation, + verifyHiveLoreSmokeOperation, +} from './smoke-operation.js'; + +export interface HiveMainnetSmokeResult { + transactionId: string; + blockNumber: number; + blockTimestamp: string; + rpcNodeUsed: string; + verificationSummary: 'PASS' | 'FAIL'; +} + +export interface RunHiveMainnetSmokeInput { + account: string; + postingKey: string; + network: HiveNetworkConfig; + waxClient?: HiveWaxClient | undefined; + transport?: HiveBroadcastTransport | undefined; +} + +export async function runHiveMainnetSmoke( + input: RunHiveMainnetSmokeInput, +): Promise { + const signer = hiveAccountNameSchema.parse(input.account); + const operation = buildHiveLoreSmokeCustomJsonOperation(signer); + const smokeVerification = verifyHiveLoreSmokeOperation({ expectedSigner: signer, operation }); + + if (!smokeVerification.ok) { + throw new Error(smokeVerification.reason); + } + + assertPostingAuthorityOnly(operation); + + const primaryRpcNode = input.network.rpcNodes[0]; + + if (!primaryRpcNode) { + throw new Error('Hive mainnet smoke test requires at least one RPC node.'); + } + + const waxClient = + input.waxClient ?? + new HiveWaxClient({ + apiEndpoint: primaryRpcNode, + chainId: input.network.chainId, + }); + const built = await waxClient.buildTransaction([operation]); + const signed = await waxClient.signTransaction(built, { + provider: 'wax', + async signTransaction(transaction) { + return signApiTransactionWithPostingKey({ + chainId: input.network.chainId, + postingKey: input.postingKey, + transaction, + }); + }, + }); + const broadcaster = new HiveReliableBroadcaster(input.network, input.transport); + const confirmed = await broadcaster.broadcastSignedTransaction({ + expectedOperation: operation, + expectedSigner: signer, + transaction: signed.transaction, + transactionId: signed.transactionId, + }); + + return { + blockNumber: confirmed.blockNumber, + blockTimestamp: confirmed.blockchainTimestamp, + rpcNodeUsed: confirmed.nodeUrl ?? primaryRpcNode, + transactionId: confirmed.transactionId, + verificationSummary: 'PASS', + }; +} + +export function formatHiveMainnetSmokeResult(result: HiveMainnetSmokeResult): string { + return [ + `transaction ID: ${result.transactionId}`, + `block number: ${result.blockNumber}`, + `block timestamp: ${result.blockTimestamp}`, + `RPC node used: ${result.rpcNodeUsed}`, + `verification summary: ${result.verificationSummary}`, + ].join('\n'); +} + +export function signApiTransactionWithPostingKey(input: { + transaction: ApiTransaction; + postingKey: string; + chainId: string; +}): ApiTransaction { + const key = PrivateKey.fromString(input.postingKey); + const signed = cryptoUtils.signTransaction( + apiTransactionToLegacyCustomJsonTransaction(input.transaction), + key, + Buffer.from(input.chainId, 'hex'), + ); + + return { + ...input.transaction, + signatures: signed.signatures, + }; +} + +function apiTransactionToLegacyCustomJsonTransaction(transaction: ApiTransaction) { + return { + ...transaction, + operations: transaction.operations.map((operation) => { + const customJson = + 'custom_json_operation' in operation + ? operation.custom_json_operation + : operation.type === 'custom_json_operation' + ? operation.value + : undefined; + + if (!customJson) { + throw new Error('Smoke transaction may only contain custom_json operations.'); + } + + return ['custom_json', customJson] as const; + }), + }; +} diff --git a/apps/api/src/lib/hive/network-config.ts b/apps/api/src/lib/hive/network-config.ts new file mode 100644 index 0000000..8777d10 --- /dev/null +++ b/apps/api/src/lib/hive/network-config.ts @@ -0,0 +1,167 @@ +import { DEFAULT_HAF_API_URL, DEFAULT_HIVE_RPC_URL, HIVE_MAINNET_CHAIN_ID } from './constants.js'; + +export type HiveNetworkName = 'mainnet'; + +export interface HiveNetworkConfig { + name: HiveNetworkName; + chainId: string; + rpcNodes: string[]; + hafUrl?: string | undefined; + addressPrefix: 'STM'; + customJsonId: string; + transactionExpirationMinutes: number; + explorerTransactionUrl?: string | undefined; +} + +export interface HiveRetryConfig { + maxAttempts: number; + initialDelayMs: number; + maxDelayMs: number; + backoffMultiplier: number; + jitterRatio: number; + requestTimeoutMs: number; + totalDeadlineMs: number; + confirmationPollIntervalMs: number; + confirmationTimeoutMs: number; + maxConsecutiveNodeFailures: number; + nodeCooldownMs: number; +} + +export const DEFAULT_HIVE_RETRY_CONFIG: HiveRetryConfig = { + backoffMultiplier: 2, + confirmationPollIntervalMs: 3_000, + confirmationTimeoutMs: 60_000, + initialDelayMs: 500, + jitterRatio: 0.2, + maxAttempts: 4, + maxConsecutiveNodeFailures: 1, + maxDelayMs: 5_000, + nodeCooldownMs: 30_000, + requestTimeoutMs: 10_000, + totalDeadlineMs: 90_000, +}; + +export function buildHiveNetworkConfig(input: { + mainnetChainId?: string | undefined; + mainnetRpcNodes?: string | undefined; + mainnetHafUrl?: string | undefined; + customJsonId: string; + nodeEnv?: string | undefined; +}): HiveNetworkConfig { + const chainId = input.mainnetChainId || HIVE_MAINNET_CHAIN_ID; + const rpcNodes = parseNodeList(input.mainnetRpcNodes || DEFAULT_HIVE_RPC_URL, input.nodeEnv); + const hafUrl = input.mainnetHafUrl || DEFAULT_HAF_API_URL; + + validateChainId(chainId); + + if (chainId !== HIVE_MAINNET_CHAIN_ID) { + throw new Error('HIVE_MAINNET_CHAIN_ID must match the Hive mainnet chain ID.'); + } + + return { + addressPrefix: 'STM', + chainId, + customJsonId: input.customJsonId, + explorerTransactionUrl: 'https://hiveblocks.com/tx/{transactionId}', + hafUrl: hafUrl || undefined, + name: 'mainnet', + rpcNodes, + transactionExpirationMinutes: 10, + }; +} + +export function parseNodeList(value: string, nodeEnv = 'development'): string[] { + const seen = new Set(); + const nodes = value + .split(',') + .map((node) => node.trim()) + .filter(Boolean) + .map((node) => { + const url = new URL(node); + + if (url.username || url.password) { + throw new Error('Hive RPC node URLs must not contain credentials.'); + } + + if (nodeEnv !== 'test' && nodeEnv !== 'development' && url.protocol !== 'https:') { + throw new Error('Hive RPC node URLs must use HTTPS outside local/test environments.'); + } + + url.hash = ''; + + return url.toString().replace(/\/$/, ''); + }) + .filter((node) => { + if (seen.has(node)) { + return false; + } + + seen.add(node); + + return true; + }); + + if (nodes.length === 0) { + throw new Error('At least one Hive RPC node must be configured.'); + } + + return nodes; +} + +export function validateHiveRetryConfig(config: HiveRetryConfig): HiveRetryConfig { + const entries = Object.entries(config); + + for (const [key, value] of entries) { + if (!Number.isFinite(value) || value < 0) { + throw new Error(`Invalid Hive retry configuration for ${key}.`); + } + } + + if (config.maxAttempts < 1) { + throw new Error('HIVE_BROADCAST_MAX_ATTEMPTS must be at least 1.'); + } + + if (config.backoffMultiplier < 1) { + throw new Error('HIVE_BROADCAST_BACKOFF_MULTIPLIER must be at least 1.'); + } + + if (config.initialDelayMs <= 0 || config.maxDelayMs < config.initialDelayMs) { + throw new Error('Hive broadcast delay configuration is invalid.'); + } + + if (config.jitterRatio > 1) { + throw new Error('HIVE_BROADCAST_JITTER_RATIO must be between 0 and 1.'); + } + + if (config.totalDeadlineMs < config.requestTimeoutMs) { + throw new Error('HIVE_BROADCAST_TOTAL_DEADLINE_MS must be >= request timeout.'); + } + + if (config.totalDeadlineMs < config.confirmationTimeoutMs) { + throw new Error('HIVE_BROADCAST_TOTAL_DEADLINE_MS must be >= confirmation timeout.'); + } + + return config; +} + +export function sanitizeHiveNodeUrl(nodeUrl: string): string { + const url = new URL(nodeUrl); + + url.username = ''; + url.password = ''; + url.pathname = ''; + url.search = ''; + url.hash = ''; + + return url.toString().replace(/\/$/, ''); +} + +function validateChainId(chainId: string) { + if (!/^[a-f0-9]{64}$/i.test(chainId)) { + throw new Error('Hive chain ID must be a 64-character hex string.'); + } + + if (chainId.toLowerCase() !== HIVE_MAINNET_CHAIN_ID) { + throw new Error('Hive chain ID must be the mainnet chain ID.'); + } +} diff --git a/apps/api/src/lib/hive/operations.test.ts b/apps/api/src/lib/hive/operations.test.ts new file mode 100644 index 0000000..7ea140a --- /dev/null +++ b/apps/api/src/lib/hive/operations.test.ts @@ -0,0 +1,111 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { + buildHiveLoreCommentOperation, + buildHiveLoreCustomJsonOperation, + parseHiveLoreCommentMetadata, + parseHiveLoreCustomJsonPayload, +} from './operations.js'; +import { verifyHiveLoreOperation } from './verification.js'; + +describe('HiveLore Hive operations', () => { + test('builds a WAX comment operation with normalized HiveLore metadata', () => { + const operation = buildHiveLoreCommentOperation({ + author: 'EmberQuill.Dev', + permlink: 'world-seed', + title: 'World Seed', + body: 'The world begins here.', + kind: 'world_seed', + entityType: 'WORLD_SEED', + entityId: 'world-1', + worldId: 'world-1', + }); + + assert.equal(operation.comment_operation?.author, 'emberquill.dev'); + assert.equal(operation.comment_operation?.parent_author, ''); + assert.equal(operation.comment_operation?.parent_permlink, 'hivelore'); + + const metadata = parseHiveLoreCommentMetadata(operation); + + assert.equal(metadata?.app, 'hivelore/0.1.0'); + assert.equal(metadata?.hivelore.kind, 'world_seed'); + assert.equal(metadata?.hivelore.entityType, 'WORLD_SEED'); + }); + + test('builds a posting custom_json operation for canon approvals', () => { + const operation = buildHiveLoreCustomJsonOperation({ + signer: 'EmberQuill.Dev', + action: 'canon_approval', + entityType: 'CANON_DECISION', + entityId: 'proposal-1', + worldId: 'world-1', + proposalId: 'proposal-1', + payload: { + approvedAt: '2026-07-25T18:00:00.000Z', + }, + }); + + assert.deepEqual(operation.custom_json_operation?.required_auths, []); + assert.deepEqual(operation.custom_json_operation?.required_posting_auths, ['emberquill.dev']); + assert.equal(operation.custom_json_operation?.id, 'hivelore'); + + const payload = parseHiveLoreCustomJsonPayload(operation); + + assert.equal(payload?.action, 'canon_approval'); + assert.equal(payload?.signer, 'emberquill.dev'); + }); + + test('rejects invalid Hive account names and permlinks', () => { + assert.throws( + () => + buildHiveLoreCommentOperation({ + author: 'bad_name', + permlink: 'world-seed', + title: 'World Seed', + body: 'The world begins here.', + kind: 'world_seed', + entityType: 'WORLD_SEED', + entityId: 'world-1', + }), + /Invalid Hive account name/, + ); + + assert.throws( + () => + buildHiveLoreCommentOperation({ + author: 'emberquill.dev', + permlink: 'Bad Permlink', + title: 'World Seed', + body: 'The world begins here.', + kind: 'world_seed', + entityType: 'WORLD_SEED', + entityId: 'world-1', + }), + /Invalid string/, + ); + }); + + test('verifies signer and HiveLore payload before projection', () => { + const operation = buildHiveLoreCustomJsonOperation({ + signer: 'emberquill.dev', + action: 'revision_history', + entityType: 'METADATA', + entityId: 'revision-1', + payload: { + previous: 'draft', + }, + }); + + assert.deepEqual(verifyHiveLoreOperation({ operation, expectedSigner: 'other-user' }), { + ok: false, + reason: 'Signer does not match expected Hive account.', + }); + + const decision = verifyHiveLoreOperation({ operation, expectedSigner: 'emberquill.dev' }); + + assert.equal(decision.ok, true); + assert.equal(decision.signer, 'emberquill.dev'); + assert.equal(decision.entityType, 'METADATA'); + }); +}); diff --git a/apps/api/src/lib/hive/operations.ts b/apps/api/src/lib/hive/operations.ts new file mode 100644 index 0000000..569d186 --- /dev/null +++ b/apps/api/src/lib/hive/operations.ts @@ -0,0 +1,210 @@ +import type { comment, custom_json } from '@hiveio/wax'; +import { z } from 'zod'; + +import { + DEFAULT_HIVELORE_APP_ID, + HIVELORE_CUSTOM_JSON_ID, + HIVELORE_SCHEMA_VERSION, +} from './constants.js'; +import type { + HiveAuthorityKind, + HiveLoreCommentKind, + HiveLoreCustomJsonAction, + HiveLoreCustomJsonPayload, + HiveLoreEntityType, + HiveLoreMetadata, + HiveLoreOperation, +} from './types.js'; + +const hiveAccountLabelPattern = /^[a-z][a-z0-9-]{1,14}[a-z0-9]$/; + +export const hiveAccountNameSchema = z + .string() + .trim() + .min(3) + .max(16) + .toLowerCase() + .refine( + (account) => account.split('.').every((label) => hiveAccountLabelPattern.test(label)), + 'Invalid Hive account name.', + ); + +export const hivePermlinkSchema = z + .string() + .trim() + .min(1) + .max(255) + .regex(/^[a-z0-9](?:[a-z0-9-]{0,253}[a-z0-9])?$/); + +const metadataSchema = z.object({ + app: z.string().min(1), + format: z.literal('markdown'), + tags: z.array(z.string().min(1)).min(1), + hivelore: z.object({ + schemaVersion: z.literal(HIVELORE_SCHEMA_VERSION), + kind: z.enum(['world_seed', 'world_bible', 'canon_lore', 'story_chapter']), + entityType: z.enum([ + 'WORLD_SEED', + 'WORLD_BIBLE_VERSION', + 'LORE_ENTRY', + 'STORY_CHAPTER', + 'CANON_DECISION', + 'LORE_RELATIONSHIP', + 'METADATA', + ]), + entityId: z.string().min(1), + worldId: z.string().min(1).optional(), + proposalId: z.string().min(1).optional(), + }), +}); + +export const hiveLoreCustomJsonPayloadSchema = z.object({ + app: z.string().min(1), + schemaVersion: z.literal(HIVELORE_SCHEMA_VERSION), + action: z.enum([ + 'canon_approval', + 'lore_relationship', + 'revision_history', + 'beneficiary_metadata', + ]), + signer: hiveAccountNameSchema, + entityType: metadataSchema.shape.hivelore.shape.entityType, + entityId: z.string().min(1), + worldId: z.string().min(1).optional(), + proposalId: z.string().min(1).optional(), + payload: z.record(z.string(), z.unknown()), +}); + +export interface BuildHiveLoreCommentInput { + author: string; + permlink: string; + title: string; + body: string; + kind: HiveLoreCommentKind; + entityType: HiveLoreEntityType; + entityId: string; + worldId?: string; + proposalId?: string; + parentAuthor?: string; + parentPermlink?: string; + tags?: string[]; + app?: string; +} + +export interface BuildHiveLoreCustomJsonInput { + signer: string; + action: HiveLoreCustomJsonAction; + entityType: HiveLoreEntityType; + entityId: string; + payload: Record; + worldId?: string; + proposalId?: string; + authority?: HiveAuthorityKind; + app?: string; +} + +export function buildHiveLoreCommentOperation(input: BuildHiveLoreCommentInput): HiveLoreOperation { + const author = hiveAccountNameSchema.parse(input.author); + const parentAuthor = input.parentAuthor ? hiveAccountNameSchema.parse(input.parentAuthor) : ''; + const parentPermlink = hivePermlinkSchema.parse( + input.parentPermlink ?? input.tags?.[0] ?? 'hivelore', + ); + const permlink = hivePermlinkSchema.parse(input.permlink); + const tags = input.tags?.length ? input.tags : ['hivelore', input.kind.replaceAll('_', '-')]; + + const metadata: HiveLoreMetadata = metadataSchema.parse({ + app: input.app ?? DEFAULT_HIVELORE_APP_ID, + format: 'markdown', + tags, + hivelore: { + schemaVersion: HIVELORE_SCHEMA_VERSION, + kind: input.kind, + entityType: input.entityType, + entityId: input.entityId, + worldId: input.worldId, + proposalId: input.proposalId, + }, + }); + + const op: comment = { + parent_author: parentAuthor, + parent_permlink: parentPermlink, + author, + permlink, + title: input.title, + body: input.body, + json_metadata: JSON.stringify(metadata), + }; + + return { + comment_operation: op, + }; +} + +export function buildHiveLoreCustomJsonOperation( + input: BuildHiveLoreCustomJsonInput, +): HiveLoreOperation { + const signer = hiveAccountNameSchema.parse(input.signer); + const authority = input.authority ?? 'posting'; + + const payload: HiveLoreCustomJsonPayload = hiveLoreCustomJsonPayloadSchema.parse({ + app: input.app ?? DEFAULT_HIVELORE_APP_ID, + schemaVersion: HIVELORE_SCHEMA_VERSION, + action: input.action, + signer, + entityType: input.entityType, + entityId: input.entityId, + worldId: input.worldId, + proposalId: input.proposalId, + payload: input.payload, + }); + + const op: custom_json = { + id: HIVELORE_CUSTOM_JSON_ID, + json: JSON.stringify(payload), + required_auths: authority === 'active' ? [signer] : [], + required_posting_auths: authority === 'posting' ? [signer] : [], + }; + + return { + custom_json_operation: op, + }; +} + +export function parseHiveLoreCommentMetadata( + operation: HiveLoreOperation, +): HiveLoreMetadata | null { + const commentOperation = operation.comment_operation; + + if (!commentOperation) { + return null; + } + + const parsedJson = safeParseJson(commentOperation.json_metadata); + const parsedMetadata = metadataSchema.safeParse(parsedJson); + + return parsedMetadata.success ? parsedMetadata.data : null; +} + +export function parseHiveLoreCustomJsonPayload( + operation: HiveLoreOperation, +): HiveLoreCustomJsonPayload | null { + const customJsonOperation = operation.custom_json_operation; + + if (!customJsonOperation || customJsonOperation.id !== HIVELORE_CUSTOM_JSON_ID) { + return null; + } + + const parsedJson = safeParseJson(customJsonOperation.json); + const parsedPayload = hiveLoreCustomJsonPayloadSchema.safeParse(parsedJson); + + return parsedPayload.success ? parsedPayload.data : null; +} + +function safeParseJson(value: string): unknown { + try { + return JSON.parse(value); + } catch { + return null; + } +} diff --git a/apps/api/src/lib/hive/projection.test.ts b/apps/api/src/lib/hive/projection.test.ts new file mode 100644 index 0000000..9c45a54 --- /dev/null +++ b/apps/api/src/lib/hive/projection.test.ts @@ -0,0 +1,115 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { buildHiveLoreCommentOperation } from './operations.js'; +import { normalizeHafOperation, projectHiveOperation } from './projection.js'; + +describe('HAF projection helpers', () => { + test('normalizes HAF rows into the API projection shape', () => { + const operation = buildHiveLoreCommentOperation({ + author: 'emberquill.dev', + permlink: 'canon-lore', + title: 'Canon Lore', + body: 'A verified entry.', + kind: 'canon_lore', + entityType: 'LORE_ENTRY', + entityId: 'lore-1', + }); + + const normalized = normalizeHafOperation({ + block_num: '123', + transaction_id: 'abc123', + operation_id: '2', + timestamp: '2026-07-25T18:00:00', + operation, + }); + + assert.equal(normalized.blockNumber, 123n); + assert.equal(normalized.transactionId, 'abc123'); + assert.equal(normalized.operationIndex, 2); + assert.equal(normalized.operationType, 'comment'); + }); + + test('normalizes the live HAFBE operation wrapper shape', () => { + const operation = buildHiveLoreCommentOperation({ + author: 'emberquill.dev', + permlink: 'canon-lore', + title: 'Canon Lore', + body: 'A verified entry.', + kind: 'canon_lore', + entityType: 'LORE_ENTRY', + entityId: 'lore-1', + }); + + const normalized = normalizeHafOperation({ + block: 123, + trx_id: 'abc123', + op_pos: 2, + timestamp: '2026-07-25T18:00:00', + op: { + type: 'comment_operation', + value: operation.comment_operation, + }, + }); + + assert.equal(normalized.blockNumber, 123n); + assert.equal(normalized.transactionId, 'abc123'); + assert.equal(normalized.operationIndex, 2); + assert.deepEqual(normalized.operation, operation); + }); + + test('upserts projected Hive events by transaction and operation index', async () => { + const calls: unknown[] = []; + const operation = buildHiveLoreCommentOperation({ + author: 'emberquill.dev', + permlink: 'story', + title: 'Story', + body: 'Chapter one.', + kind: 'story_chapter', + entityType: 'STORY_CHAPTER', + entityId: 'story-1', + }); + + await projectHiveOperation( + { + hiveEvent: { + async upsert(args) { + calls.push(args); + }, + }, + }, + { + blockNumber: 456n, + transactionId: 'def456', + operationIndex: 0, + blockchainTimestamp: new Date('2026-07-25T18:30:00.000Z'), + operationType: 'comment', + operation, + }, + ); + + assert.equal(calls.length, 1); + assert.deepEqual(calls[0], { + where: { + transactionId_operationIndex: { + transactionId: 'def456', + operationIndex: 0, + }, + }, + create: { + blockNumber: 456n, + transactionId: 'def456', + operationIndex: 0, + eventType: 'COMMENT', + blockchainTimestamp: new Date('2026-07-25T18:30:00.000Z'), + payload: operation, + }, + update: { + blockNumber: 456n, + eventType: 'COMMENT', + blockchainTimestamp: new Date('2026-07-25T18:30:00.000Z'), + payload: operation, + }, + }); + }); +}); diff --git a/apps/api/src/lib/hive/projection.ts b/apps/api/src/lib/hive/projection.ts new file mode 100644 index 0000000..f8cdc40 --- /dev/null +++ b/apps/api/src/lib/hive/projection.ts @@ -0,0 +1,177 @@ +import type { HafOperationRow, HiveLoreOperation, NormalizedHiveOperation } from './types.js'; + +type HiveProjectionEventType = 'COMMENT' | 'CUSTOM_JSON'; + +export interface HiveProjectionDatabase { + hiveEvent: { + upsert(args: { + where: { transactionId_operationIndex: { transactionId: string; operationIndex: number } }; + create: { + blockNumber: bigint; + transactionId: string; + operationIndex: number; + eventType: HiveProjectionEventType; + blockchainTimestamp: Date; + payload: unknown; + }; + update: { + blockNumber: bigint; + eventType: HiveProjectionEventType; + blockchainTimestamp: Date; + payload: unknown; + }; + }): Promise; + }; +} + +export function normalizeHafOperation(row: HafOperationRow): NormalizedHiveOperation { + const operation = unwrapHafOperation(row); + const operationType = getOperationType(operation); + + if (!operationType) { + throw new Error('HAF row does not contain a supported HiveLore operation.'); + } + + return { + blockNumber: BigInt( + requiredNumeric(row.block_num ?? row.blockNumber ?? row.block, 'block number'), + ), + transactionId: requiredString( + row.transaction_id ?? row.transactionId ?? row.trx_id, + 'transaction id', + ), + operationIndex: requiredNumeric( + row.operation_id ?? row.operationIndex ?? row.op_in_trx ?? row.op_pos, + 'operation index', + ), + blockchainTimestamp: new Date(requiredString(row.timestamp ?? row.created_at, 'timestamp')), + operationType, + operation, + }; +} + +export async function projectHiveOperation( + database: HiveProjectionDatabase, + operation: NormalizedHiveOperation, +): Promise { + await database.hiveEvent.upsert({ + where: { + transactionId_operationIndex: { + transactionId: operation.transactionId, + operationIndex: operation.operationIndex, + }, + }, + create: { + blockNumber: operation.blockNumber, + transactionId: operation.transactionId, + operationIndex: operation.operationIndex, + eventType: toHiveEventType(operation.operationType), + blockchainTimestamp: operation.blockchainTimestamp, + payload: operation.operation, + }, + update: { + blockNumber: operation.blockNumber, + eventType: toHiveEventType(operation.operationType), + blockchainTimestamp: operation.blockchainTimestamp, + payload: operation.operation, + }, + }); +} + +function unwrapHafOperation(row: HafOperationRow): HiveLoreOperation { + const source = row.operation ?? row.op ?? row.body; + + if (!source || typeof source !== 'object') { + throw new Error('HAF row did not include operation payload.'); + } + + if ('comment_operation' in source || 'custom_json_operation' in source) { + return source as HiveLoreOperation; + } + + if ('type' in source && 'value' in source) { + const typedOperation = source as { type: unknown; value: unknown }; + + if (typedOperation.type === 'comment_operation') { + return { + comment_operation: typedOperation.value as HiveLoreOperation['comment_operation'], + }; + } + + if (typedOperation.type === 'custom_json_operation') { + return { + custom_json_operation: typedOperation.value as HiveLoreOperation['custom_json_operation'], + }; + } + } + + if (Array.isArray(source) && source.length >= 2) { + const [type, value] = source as [unknown, unknown]; + + if (type === 'comment') { + return { + comment_operation: value as HiveLoreOperation['comment_operation'], + }; + } + + if (type === 'custom_json') { + return { + custom_json_operation: value as HiveLoreOperation['custom_json_operation'], + }; + } + } + + if ('comment' in source) { + return { + comment_operation: (source as { comment: unknown }) + .comment as HiveLoreOperation['comment_operation'], + }; + } + + if ('custom_json' in source) { + return { + custom_json_operation: (source as { custom_json: unknown }) + .custom_json as HiveLoreOperation['custom_json_operation'], + }; + } + + throw new Error('HAF row operation payload is not supported.'); +} + +function getOperationType( + operation: HiveLoreOperation, +): NormalizedHiveOperation['operationType'] | null { + if (operation.comment_operation) { + return 'comment'; + } + + if (operation.custom_json_operation) { + return 'custom_json'; + } + + return null; +} + +function toHiveEventType( + operationType: NormalizedHiveOperation['operationType'], +): HiveProjectionEventType { + return operationType === 'comment' ? 'COMMENT' : 'CUSTOM_JSON'; +} + +function requiredString(value: unknown, label: string): string { + if (typeof value !== 'string' || value.length === 0) { + throw new Error(`HAF row did not include ${label}.`); + } + + return value; +} + +function requiredNumeric(value: unknown, label: string): number { + const numericValue = typeof value === 'string' ? Number(value) : value; + + if (typeof numericValue !== 'number' || !Number.isInteger(numericValue)) { + throw new Error(`HAF row did not include valid ${label}.`); + } + + return numericValue; +} diff --git a/apps/api/src/lib/hive/publishing.ts b/apps/api/src/lib/hive/publishing.ts new file mode 100644 index 0000000..baf093e --- /dev/null +++ b/apps/api/src/lib/hive/publishing.ts @@ -0,0 +1,41 @@ +import type { + BuiltHiveTransaction, + HiveTransactionSigner, + SignedHiveTransaction, +} from './types.js'; +import { + buildHiveLoreCommentOperation, + buildHiveLoreCustomJsonOperation, + type BuildHiveLoreCommentInput, + type BuildHiveLoreCustomJsonInput, +} from './operations.js'; +import { HiveWaxClient } from './wax-client.js'; + +export async function prepareHiveLoreCommentTransaction( + client: HiveWaxClient, + input: BuildHiveLoreCommentInput, +): Promise { + return client.buildTransaction([buildHiveLoreCommentOperation(input)]); +} + +export async function prepareHiveLoreCustomJsonTransaction( + client: HiveWaxClient, + input: BuildHiveLoreCustomJsonInput, +): Promise { + return client.buildTransaction([buildHiveLoreCustomJsonOperation(input)]); +} + +export async function signHiveLoreTransaction( + client: HiveWaxClient, + transaction: BuiltHiveTransaction, + signer: HiveTransactionSigner, +): Promise { + return client.signTransaction(transaction, signer); +} + +export async function broadcastHiveLoreTransaction( + client: HiveWaxClient, + transaction: SignedHiveTransaction, +): Promise { + await client.broadcastTransaction(transaction.transaction); +} diff --git a/apps/api/src/lib/hive/signers.ts b/apps/api/src/lib/hive/signers.ts new file mode 100644 index 0000000..5380a96 --- /dev/null +++ b/apps/api/src/lib/hive/signers.ts @@ -0,0 +1,58 @@ +import type { ApiTransaction } from '@hiveio/wax'; + +import type { BuiltHiveTransaction, HiveAuthorityKind, HiveTransactionSigner } from './types.js'; + +export interface HiveKeychainSignRequest { + provider: 'hive-keychain'; + username: string; + authority: HiveAuthorityKind; + transaction: ApiTransaction; +} + +export interface HiveSignerSignRequest { + provider: 'hivesigner'; + username: string; + authority: HiveAuthorityKind; + transaction: ApiTransaction; + callbackUrl: string; +} + +export type BrowserHiveSignRequest = HiveKeychainSignRequest | HiveSignerSignRequest; + +export function createHiveKeychainSignRequest(input: { + username: string; + authority?: HiveAuthorityKind; + builtTransaction: BuiltHiveTransaction; +}): HiveKeychainSignRequest { + return { + provider: 'hive-keychain', + username: input.username.trim().toLowerCase(), + authority: input.authority ?? 'posting', + transaction: input.builtTransaction.transaction, + }; +} + +export function createHiveSignerSignRequest(input: { + username: string; + authority?: HiveAuthorityKind; + builtTransaction: BuiltHiveTransaction; + callbackUrl: string; +}): HiveSignerSignRequest { + return { + provider: 'hivesigner', + username: input.username.trim().toLowerCase(), + authority: input.authority ?? 'posting', + transaction: input.builtTransaction.transaction, + callbackUrl: input.callbackUrl, + }; +} + +export function createExternalSigner( + provider: HiveTransactionSigner['provider'], + sign: (transaction: ApiTransaction) => Promise, +): HiveTransactionSigner { + return { + provider, + signTransaction: sign, + }; +} diff --git a/apps/api/src/lib/hive/smoke-operation.ts b/apps/api/src/lib/hive/smoke-operation.ts new file mode 100644 index 0000000..9b032f9 --- /dev/null +++ b/apps/api/src/lib/hive/smoke-operation.ts @@ -0,0 +1,117 @@ +import type { custom_json } from '@hiveio/wax'; + +import { HIVE_MAINNET_CHAIN_ID, HIVELORE_SMOKE_CUSTOM_JSON_ID } from './constants.js'; +import { buildHiveNetworkConfig, type HiveNetworkConfig } from './network-config.js'; +import { hiveAccountNameSchema } from './operations.js'; +import type { HiveLoreOperation } from './types.js'; + +export const HIVELORE_MAINNET_SMOKE_PAYLOAD = { + app: 'hivelore', + type: 'mainnet_smoke', + version: 1, + purpose: 'broadcast_readback_verification', +} as const; + +export function buildHiveLoreSmokeCustomJsonOperation(account: string): HiveLoreOperation { + const signer = hiveAccountNameSchema.parse(account); + const operation: custom_json = { + id: HIVELORE_SMOKE_CUSTOM_JSON_ID, + json: JSON.stringify(HIVELORE_MAINNET_SMOKE_PAYLOAD), + required_auths: [], + required_posting_auths: [signer], + }; + + return { + custom_json_operation: operation, + }; +} + +export function verifyHiveLoreSmokeOperation(input: { + operation: HiveLoreOperation; + expectedSigner: string; +}): + | { ok: true; signer: string; payload: typeof HIVELORE_MAINNET_SMOKE_PAYLOAD } + | { + ok: false; + reason: string; + } { + const expectedSigner = hiveAccountNameSchema.parse(input.expectedSigner); + const customJson = input.operation.custom_json_operation; + + if (!customJson) { + return { ok: false, reason: 'Operation is not custom_json.' }; + } + + if (customJson.id !== HIVELORE_SMOKE_CUSTOM_JSON_ID) { + return { ok: false, reason: 'custom_json ID is not hivelore_smoke.' }; + } + + if (customJson.required_auths.length !== 0) { + return { ok: false, reason: 'Smoke custom_json must not require active authority.' }; + } + + if ( + customJson.required_posting_auths.length !== 1 || + customJson.required_posting_auths[0] !== expectedSigner + ) { + return { ok: false, reason: 'Smoke custom_json must require posting authority only.' }; + } + + const payload = parseSmokePayload(customJson.json); + + if (!payload) { + return { ok: false, reason: 'Smoke custom_json payload does not match expected payload.' }; + } + + return { ok: true, payload, signer: expectedSigner }; +} + +export function assertPostingAuthorityOnly(operation: HiveLoreOperation): void { + const customJson = operation.custom_json_operation; + + if (!customJson) { + throw new Error('Smoke operation must be a custom_json operation.'); + } + + if (customJson.required_auths.length > 0) { + throw new Error('BUG: smoke operation requested active authority.'); + } + + if (customJson.required_posting_auths.length !== 1) { + throw new Error('Smoke operation must request exactly one posting authority.'); + } +} + +export function buildMainnetSmokeNetworkFromEnv(environment: NodeJS.ProcessEnv): HiveNetworkConfig { + const network = buildHiveNetworkConfig({ + customJsonId: HIVELORE_SMOKE_CUSTOM_JSON_ID, + mainnetChainId: environment.HIVE_MAINNET_CHAIN_ID, + mainnetHafUrl: environment.HIVE_MAINNET_HAF_URL, + mainnetRpcNodes: environment.HIVE_MAINNET_RPC_NODES, + nodeEnv: environment.NODE_ENV, + }); + + if (network.name !== 'mainnet' || network.chainId !== HIVE_MAINNET_CHAIN_ID) { + throw new Error('Hive smoke test must be pinned to Hive mainnet.'); + } + + if (network.customJsonId !== HIVELORE_SMOKE_CUSTOM_JSON_ID) { + throw new Error('Hive smoke test must use custom_json ID hivelore_smoke.'); + } + + return network; +} + +function parseSmokePayload(value: string): typeof HIVELORE_MAINNET_SMOKE_PAYLOAD | null { + try { + const payload = JSON.parse(value) as typeof HIVELORE_MAINNET_SMOKE_PAYLOAD; + + return payload.type === HIVELORE_MAINNET_SMOKE_PAYLOAD.type && + payload.version === HIVELORE_MAINNET_SMOKE_PAYLOAD.version && + payload.purpose === HIVELORE_MAINNET_SMOKE_PAYLOAD.purpose + ? payload + : null; + } catch { + return null; + } +} diff --git a/apps/api/src/lib/hive/types.ts b/apps/api/src/lib/hive/types.ts new file mode 100644 index 0000000..d5087c0 --- /dev/null +++ b/apps/api/src/lib/hive/types.ts @@ -0,0 +1,116 @@ +import type { ApiTransaction, operation } from '@hiveio/wax'; + +export type HiveLoreCommentKind = 'world_seed' | 'world_bible' | 'canon_lore' | 'story_chapter'; + +export type HiveLoreCustomJsonAction = + 'canon_approval' | 'lore_relationship' | 'revision_history' | 'beneficiary_metadata'; + +export type HiveAuthorityKind = 'posting' | 'active'; + +export type HiveLoreEntityType = + | 'WORLD_SEED' + | 'WORLD_BIBLE_VERSION' + | 'LORE_ENTRY' + | 'STORY_CHAPTER' + | 'CANON_DECISION' + | 'LORE_RELATIONSHIP' + | 'METADATA'; + +export type HiveLoreOperation = operation; + +export interface HiveLoreMetadata { + app: string; + format: 'markdown'; + tags: string[]; + hivelore: { + schemaVersion: number; + kind: HiveLoreCommentKind; + entityType: HiveLoreEntityType; + entityId: string; + worldId?: string | undefined; + proposalId?: string | undefined; + }; +} + +export interface HiveLoreCustomJsonPayload { + app: string; + schemaVersion: number; + action: HiveLoreCustomJsonAction; + signer: string; + entityType: HiveLoreEntityType; + entityId: string; + worldId?: string | undefined; + proposalId?: string | undefined; + payload: Record; +} + +export interface HiveLoreSmokePayload { + app: 'hivelore'; + type: 'mainnet_smoke'; + version: 1; + purpose: 'broadcast_readback_verification'; +} + +export interface BuiltHiveTransaction { + transaction: ApiTransaction; + binaryHex: string; + unsignedBinaryHex: string; + requiredAuthorities: unknown; +} + +export interface SignedHiveTransaction { + transaction: ApiTransaction; + binaryHex: string; + transactionId: string; +} + +export interface HiveTransactionSigner { + readonly provider: 'hive-keychain' | 'hivesigner' | 'wax'; + signTransaction(transaction: ApiTransaction): Promise; +} + +export interface HafOperationRow { + block_num?: number | string; + blockNumber?: number | string; + block?: number | string; + transaction_num?: number | string; + transaction_id?: string; + transactionId?: string; + trx_id?: string; + operation_id?: number | string; + operationIndex?: number | string; + op_in_trx?: number | string; + op_pos?: number | string; + timestamp?: string; + created_at?: string; + operation_type?: string; + operationType?: string; + type?: string; + operation?: unknown; + op?: unknown; + body?: unknown; +} + +export interface HafBlockSearchPage { + operations: HafOperationRow[]; + page?: number; + totalPages?: number; +} + +export interface NormalizedHiveOperation { + blockNumber: bigint; + transactionId: string; + operationIndex: number; + blockchainTimestamp: Date; + operationType: 'comment' | 'custom_json'; + operation: HiveLoreOperation; +} + +export interface HiveOperationVerification { + ok: boolean; + reason?: string; + signer?: string; + entityType?: HiveLoreEntityType; + entityId?: string; + payload?: HiveLoreMetadata | HiveLoreCustomJsonPayload | HiveLoreSmokePayload; +} diff --git a/apps/api/src/lib/hive/verification.ts b/apps/api/src/lib/hive/verification.ts new file mode 100644 index 0000000..47ac434 --- /dev/null +++ b/apps/api/src/lib/hive/verification.ts @@ -0,0 +1,91 @@ +import { parseHiveLoreCommentMetadata, parseHiveLoreCustomJsonPayload } from './operations.js'; +import { verifyHiveLoreSmokeOperation } from './smoke-operation.js'; +import type { HiveLoreOperation, HiveOperationVerification } from './types.js'; + +export function verifyHiveLoreOperation(input: { + operation: HiveLoreOperation; + expectedSigner?: string; +}): HiveOperationVerification { + if (input.expectedSigner) { + const smokeVerification = verifyHiveLoreSmokeOperation({ + expectedSigner: input.expectedSigner, + operation: input.operation, + }); + + if (smokeVerification.ok) { + return { + ok: true, + payload: smokeVerification.payload, + signer: smokeVerification.signer, + }; + } + } + + const customJsonPayload = parseHiveLoreCustomJsonPayload(input.operation); + + if (customJsonPayload) { + const actualSigner = getCustomJsonSigner(input.operation); + const expectedSigner = input.expectedSigner?.trim().toLowerCase(); + + if (expectedSigner && actualSigner !== expectedSigner) { + return { + ok: false, + reason: 'Signer does not match expected Hive account.', + }; + } + + if (actualSigner !== customJsonPayload.signer) { + return { + ok: false, + reason: 'custom_json signer does not match HiveLore payload signer.', + }; + } + + return { + ok: true, + signer: actualSigner, + entityType: customJsonPayload.entityType, + entityId: customJsonPayload.entityId, + payload: customJsonPayload, + }; + } + + const commentMetadata = parseHiveLoreCommentMetadata(input.operation); + + if (commentMetadata && input.operation.comment_operation) { + const actualSigner = input.operation.comment_operation.author; + const expectedSigner = input.expectedSigner?.trim().toLowerCase(); + + if (expectedSigner && actualSigner !== expectedSigner) { + return { + ok: false, + reason: 'Comment author does not match expected Hive account.', + }; + } + + return { + ok: true, + signer: actualSigner, + entityType: commentMetadata.hivelore.entityType, + entityId: commentMetadata.hivelore.entityId, + payload: commentMetadata, + }; + } + + return { + ok: false, + reason: 'Operation is not a verified HiveLore comment or custom_json payload.', + }; +} + +function getCustomJsonSigner(operation: HiveLoreOperation): string { + const customJson = operation.custom_json_operation; + + if (!customJson) { + return ''; + } + + const signer = customJson.required_posting_auths[0] ?? customJson.required_auths[0]; + + return signer?.trim().toLowerCase() ?? ''; +} diff --git a/apps/api/src/lib/hive/wax-client.test.ts b/apps/api/src/lib/hive/wax-client.test.ts new file mode 100644 index 0000000..0d5236f --- /dev/null +++ b/apps/api/src/lib/hive/wax-client.test.ts @@ -0,0 +1,155 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; +import type { ApiTransaction } from '@hiveio/wax'; + +import { HIVE_MAINNET_CHAIN_ID } from './constants.js'; +import { buildHiveLoreCustomJsonOperation } from './operations.js'; +import { HiveWaxClient } from './wax-client.js'; + +const apiTransaction: ApiTransaction = { + ref_block_num: 1, + ref_block_prefix: 2, + expiration: '2026-07-25T18:00:00', + operations: [], + extensions: [], + signatures: [], +}; + +function createTransactionFixture(transaction: ApiTransaction, id = 'tx-id') { + const pushedOperations: unknown[] = []; + + return { + pushedOperations, + transaction: { + pushOperation(operation: unknown) { + pushedOperations.push(operation); + return this; + }, + validate() {}, + toApiJson() { + return transaction; + }, + toBinaryForm(stripToUnsignedTransaction?: boolean) { + return stripToUnsignedTransaction ? 'unsigned-binary' : 'binary'; + }, + requiredAuthorities: { + posting: ['alice'], + }, + id, + }, + }; +} + +describe('Hive WAX client', () => { + test('passes Hive mainnet chain id into WAX chain and foundation initialization', async () => { + const chainOptions: unknown[] = []; + const foundationOptions: unknown[] = []; + const fixture = createTransactionFixture(apiTransaction); + const client = new HiveWaxClient({ + async createChain(options) { + chainOptions.push(options); + + return { + async createTransaction() { + return fixture.transaction; + }, + async broadcast() {}, + }; + }, + async createFoundation(options) { + foundationOptions.push(options); + + return { + createTransactionFromJson() { + return fixture.transaction; + }, + convertTransactionToBinaryForm() { + return 'binary'; + }, + }; + }, + }); + + const built = await client.buildTransaction([ + buildHiveLoreCustomJsonOperation({ + signer: 'alice', + action: 'canon_approval', + entityType: 'CANON_DECISION', + entityId: 'proposal-1', + payload: {}, + }), + ]); + await client.signTransaction(built, { + provider: 'hive-keychain', + async signTransaction(transaction) { + return { + ...transaction, + signatures: ['signature'], + }; + }, + }); + + assert.equal((chainOptions[0] as { chainId: string }).chainId, HIVE_MAINNET_CHAIN_ID); + assert.equal((foundationOptions[0] as { chainId: string }).chainId, HIVE_MAINNET_CHAIN_ID); + }); + + test('builds, signs, serializes, and broadcasts through WAX abstractions', async () => { + const fixture = createTransactionFixture(apiTransaction, 'signed-id'); + const broadcasted: ApiTransaction[] = []; + const client = new HiveWaxClient({ + async createChain() { + return { + async createTransaction() { + return fixture.transaction; + }, + async broadcast(transaction) { + broadcasted.push(transaction); + }, + }; + }, + async createFoundation() { + return { + createTransactionFromJson(transaction) { + return createTransactionFixture(transaction, 'signed-id').transaction; + }, + convertTransactionToBinaryForm(_transaction, stripSignatures) { + return stripSignatures ? 'serialized-unsigned' : 'serialized'; + }, + }; + }, + }); + + const operation = buildHiveLoreCustomJsonOperation({ + signer: 'alice', + action: 'revision_history', + entityType: 'METADATA', + entityId: 'revision-1', + payload: {}, + }); + + const built = await client.buildTransaction([operation]); + const signed = await client.signTransaction(built, { + provider: 'hivesigner', + async signTransaction(transaction) { + return { + ...transaction, + signatures: ['signature'], + }; + }, + }); + + assert.deepEqual(fixture.pushedOperations, [operation]); + assert.equal(built.binaryHex, 'binary'); + assert.equal(built.unsignedBinaryHex, 'unsigned-binary'); + assert.equal(signed.transactionId, 'signed-id'); + assert.equal(await client.serializeTransaction(signed.transaction), 'serialized'); + assert.equal( + await client.serializeTransaction(signed.transaction, true), + 'serialized-unsigned', + ); + + await client.broadcastTransaction(signed.transaction); + + assert.deepEqual(broadcasted, [signed.transaction]); + }); +}); diff --git a/apps/api/src/lib/hive/wax-client.ts b/apps/api/src/lib/hive/wax-client.ts new file mode 100644 index 0000000..cea403d --- /dev/null +++ b/apps/api/src/lib/hive/wax-client.ts @@ -0,0 +1,141 @@ +import { + createHiveChain, + createWaxFoundation, + type ApiTransaction, + type IHiveChainInterface, + type IWaxBaseInterface, + type IWaxOptionsChain, +} from '@hiveio/wax'; + +import { + DEFAULT_HIVE_RPC_URL, + DEFAULT_HIVELORE_APP_ID, + HIVE_MAINNET_CHAIN_ID, +} from './constants.js'; +import type { + BuiltHiveTransaction, + HiveLoreOperation, + HiveTransactionSigner, + SignedHiveTransaction, +} from './types.js'; + +interface WaxTransactionLike { + pushOperation(operation: HiveLoreOperation): WaxTransactionLike; + validate(): void; + toApiJson(): ApiTransaction; + toBinaryForm(stripToUnsignedTransaction?: boolean): string; + readonly requiredAuthorities: unknown; + readonly id: string; +} + +interface WaxChainLike { + createTransaction(expirationTime?: unknown): Promise; + broadcast(transaction: ApiTransaction): Promise; +} + +interface WaxFoundationLike { + createTransactionFromJson(transaction: ApiTransaction): WaxTransactionLike; + convertTransactionToBinaryForm(transaction: ApiTransaction, stripSignatures?: boolean): string; +} + +export interface HiveWaxClientOptions { + apiEndpoint?: string; + appName?: string; + apiTimeoutMs?: number; + chainId?: string; + createChain?: (options: Partial) => Promise; + createFoundation?: (options: { chainId: string }) => Promise; +} + +export class HiveWaxClient { + private readonly chainOptions: Partial; + private readonly createChain: (options: Partial) => Promise; + private readonly createFoundation: (options: { chainId: string }) => Promise; + private chainPromise?: Promise; + private foundationPromise?: Promise; + + constructor(options: HiveWaxClientOptions = {}) { + this.chainOptions = { + chainId: options.chainId ?? HIVE_MAINNET_CHAIN_ID, + apiEndpoint: options.apiEndpoint ?? DEFAULT_HIVE_RPC_URL, + waxApiCaller: options.appName ?? DEFAULT_HIVELORE_APP_ID, + apiTimeout: options.apiTimeoutMs ?? 10_000, + }; + this.createChain = options.createChain ?? createDefaultChain; + this.createFoundation = options.createFoundation ?? createDefaultFoundation; + } + + async buildTransaction(operations: HiveLoreOperation[]): Promise { + const chain = await this.getChain(); + const transaction = await chain.createTransaction('+10m'); + + for (const operation of operations) { + transaction.pushOperation(operation); + } + + transaction.validate(); + + return { + transaction: transaction.toApiJson(), + binaryHex: transaction.toBinaryForm(), + unsignedBinaryHex: transaction.toBinaryForm(true), + requiredAuthorities: transaction.requiredAuthorities, + }; + } + + async signTransaction( + builtTransaction: BuiltHiveTransaction, + signer: HiveTransactionSigner, + ): Promise { + const foundation = await this.getFoundation(); + const signedTransaction = await signer.signTransaction(builtTransaction.transaction); + const transaction = foundation.createTransactionFromJson(signedTransaction); + + transaction.validate(); + + return { + transaction: transaction.toApiJson(), + binaryHex: transaction.toBinaryForm(), + transactionId: transaction.id, + }; + } + + async serializeTransaction( + transaction: ApiTransaction, + stripSignatures = false, + ): Promise { + const foundation = await this.getFoundation(); + + return foundation.convertTransactionToBinaryForm(transaction, stripSignatures); + } + + async broadcastTransaction(transaction: ApiTransaction): Promise { + const chain = await this.getChain(); + + await chain.broadcast(transaction); + } + + private getChain() { + this.chainPromise ??= this.createChain(this.chainOptions); + + return this.chainPromise; + } + + private getFoundation() { + this.foundationPromise ??= this.createFoundation({ + chainId: this.chainOptions.chainId ?? HIVE_MAINNET_CHAIN_ID, + }); + + return this.foundationPromise; + } +} + +async function createDefaultChain( + options: Partial, +): Promise { + return createHiveChain(options); +} + +async function createDefaultFoundation(options: { chainId: string }): Promise { + return createWaxFoundation(options); +} diff --git a/apps/api/src/lib/platform-authorization.test.ts b/apps/api/src/lib/platform-authorization.test.ts new file mode 100644 index 0000000..ac7250e --- /dev/null +++ b/apps/api/src/lib/platform-authorization.test.ts @@ -0,0 +1,35 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { PlatformRole } from '../generated/prisma/enums.js'; +import type { AuthenticatedUser } from './world-authorization.js'; +import { + hasPlatformPermission, + PLATFORM_PERMISSIONS, + PLATFORM_ROLES, +} from './platform-authorization.js'; + +const user: AuthenticatedUser = { + id: 'user-1', + hiveUsername: 'emberquill.dev', + normalizedHiveUsername: 'emberquill.dev', + platformRole: PlatformRole.USER, +}; + +describe('platform authorization', () => { + test('resolves platform admin status separately from world membership', () => { + const platformAdmin: AuthenticatedUser = { + ...user, + platformRole: PLATFORM_ROLES.ADMIN, + }; + + assert.equal( + hasPlatformPermission(platformAdmin, PLATFORM_PERMISSIONS.MANAGE_PLATFORM_SETTINGS), + true, + ); + }); + + test('denies platform permissions to ordinary users', () => { + assert.equal(hasPlatformPermission(user, PLATFORM_PERMISSIONS.MANAGE_PLATFORM_SETTINGS), false); + }); +}); diff --git a/apps/api/src/lib/platform-authorization.ts b/apps/api/src/lib/platform-authorization.ts new file mode 100644 index 0000000..17b40c8 --- /dev/null +++ b/apps/api/src/lib/platform-authorization.ts @@ -0,0 +1,21 @@ +import { PlatformRole } from '../generated/prisma/enums.js'; +import type { PlatformRole as PlatformRoleType } from '../generated/prisma/enums.js'; +import type { AuthenticatedUser } from './world-authorization.js'; + +export const PLATFORM_ROLES = PlatformRole; + +export type PlatformRoleValue = PlatformRoleType; + +export const PLATFORM_PERMISSIONS = { + MANAGE_PLATFORM_SETTINGS: 'MANAGE_PLATFORM_SETTINGS', +} as const; + +export type PlatformPermission = (typeof PLATFORM_PERMISSIONS)[keyof typeof PLATFORM_PERMISSIONS]; + +export function hasPlatformPermission(user: AuthenticatedUser, permission: PlatformPermission) { + if (permission === PLATFORM_PERMISSIONS.MANAGE_PLATFORM_SETTINGS) { + return user.platformRole === PLATFORM_ROLES.ADMIN; + } + + return false; +} diff --git a/apps/api/src/lib/prisma-conflicts.test.ts b/apps/api/src/lib/prisma-conflicts.test.ts new file mode 100644 index 0000000..9815b8c --- /dev/null +++ b/apps/api/src/lib/prisma-conflicts.test.ts @@ -0,0 +1,67 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { mapDuplicateVoteConflict, mapWorldSlugConflict } from './prisma-conflicts.js'; + +describe('Prisma conflict mapping', () => { + test('maps duplicate proposal vote unique constraint to 409', () => { + const conflict = mapDuplicateVoteConflict({ + code: 'P2002', + meta: { + target: ['proposalId', 'voterId'], + }, + }); + + assert.deepEqual(conflict, { + statusCode: 409, + error: 'User has already voted on this proposal.', + }); + }); + + test('does not map unrelated unique constraints', () => { + const conflict = mapDuplicateVoteConflict({ + code: 'P2002', + meta: { + target: ['slug'], + }, + }); + + assert.equal(conflict, null); + }); + + test('maps only world slug unique conflicts to 409', () => { + assert.deepEqual( + mapWorldSlugConflict({ + code: 'P2002', + meta: { + target: ['slug'], + }, + }), + { + statusCode: 409, + error: 'World slug is already in use.', + }, + ); + + assert.equal( + mapWorldSlugConflict({ + code: 'P2002', + meta: { + target: ['proposalId', 'voterId'], + }, + }), + null, + ); + }); + + test('does not map non-unique Prisma errors', () => { + const conflict = mapDuplicateVoteConflict({ + code: 'P2025', + meta: { + target: ['proposalId', 'voterId'], + }, + }); + + assert.equal(conflict, null); + }); +}); diff --git a/apps/api/src/lib/prisma-conflicts.ts b/apps/api/src/lib/prisma-conflicts.ts new file mode 100644 index 0000000..57a7e18 --- /dev/null +++ b/apps/api/src/lib/prisma-conflicts.ts @@ -0,0 +1,49 @@ +type PrismaKnownRequestErrorLike = { + code: string; + meta?: { + target?: unknown; + } | null; +}; + +export type ConflictHttpError = { + statusCode: 409; + error: string; +}; + +function hasDuplicateVoteTarget(target: unknown) { + return Array.isArray(target) && target.includes('proposalId') && target.includes('voterId'); +} + +function hasWorldSlugTarget(target: unknown) { + if (Array.isArray(target)) { + return target.length === 1 && target.includes('slug'); + } + + return target === 'World_slug_key'; +} + +export function mapDuplicateVoteConflict(error: unknown): ConflictHttpError | null { + const knownError = error as PrismaKnownRequestErrorLike; + + if (knownError.code !== 'P2002' || !hasDuplicateVoteTarget(knownError.meta?.target)) { + return null; + } + + return { + statusCode: 409, + error: 'User has already voted on this proposal.', + }; +} + +export function mapWorldSlugConflict(error: unknown): ConflictHttpError | null { + const knownError = error as PrismaKnownRequestErrorLike; + + if (knownError.code !== 'P2002' || !hasWorldSlugTarget(knownError.meta?.target)) { + return null; + } + + return { + statusCode: 409, + error: 'World slug is already in use.', + }; +} diff --git a/apps/api/src/lib/proposal-comments.ts b/apps/api/src/lib/proposal-comments.ts new file mode 100644 index 0000000..092aec7 --- /dev/null +++ b/apps/api/src/lib/proposal-comments.ts @@ -0,0 +1,252 @@ +import type { Prisma, PrismaClient } from '../generated/prisma/client.js'; + +export const PROPOSAL_COMMENT_MAX_LENGTH = 3000; +export const PROPOSAL_COMMENT_DEFAULT_PAGE_SIZE = 20; +export const PROPOSAL_COMMENT_MAX_PAGE_SIZE = 50; + +export class ProposalCommentError extends Error { + constructor( + public readonly statusCode: number, + public readonly code: string, + message: string, + ) { + super(message); + } +} + +export type ProposalCommentDatabase = PrismaClient; + +type CommentCursor = { + createdAt: string; + id: string; +}; + +type CommentWithAuthor = Prisma.ProposalCommentGetPayload<{ + include: { + author: { + select: { + avatarUrl: true; + displayName: true; + hiveUsername: true; + id: true; + }; + }; + }; +}>; + +function encodeCursor(cursor: CommentCursor) { + return Buffer.from(JSON.stringify(cursor), 'utf8').toString('base64url'); +} + +export function decodeProposalCommentCursor(cursor: string): CommentCursor { + try { + const decoded = JSON.parse( + Buffer.from(cursor, 'base64url').toString('utf8'), + ) as Partial; + + if ( + typeof decoded.id !== 'string' || + !decoded.id || + typeof decoded.createdAt !== 'string' || + Number.isNaN(Date.parse(decoded.createdAt)) + ) { + throw new Error('Invalid cursor payload.'); + } + + return { + createdAt: decoded.createdAt, + id: decoded.id, + }; + } catch { + throw new ProposalCommentError(400, 'INVALID_COMMENT_CURSOR', 'Invalid comment cursor.'); + } +} + +export function normalizeProposalCommentBody(body: string) { + const normalized = body.trim(); + + if (!normalized) { + throw new ProposalCommentError(400, 'COMMENT_BODY_EMPTY', 'Comment body is required.'); + } + + if (normalized.length > PROPOSAL_COMMENT_MAX_LENGTH) { + throw new ProposalCommentError( + 400, + 'COMMENT_BODY_TOO_LONG', + `Comment body must be ${PROPOSAL_COMMENT_MAX_LENGTH} characters or fewer.`, + ); + } + + return normalized; +} + +function normalizePageSize(pageSize: number | undefined) { + if (!pageSize) { + return PROPOSAL_COMMENT_DEFAULT_PAGE_SIZE; + } + + return Math.min(pageSize, PROPOSAL_COMMENT_MAX_PAGE_SIZE); +} + +function serializeComment(comment: CommentWithAuthor) { + const isDeleted = Boolean(comment.deletedAt); + + return { + author: { + avatarUrl: comment.author.avatarUrl, + displayName: comment.author.displayName, + hiveUsername: comment.author.hiveUsername, + id: comment.author.id, + }, + authorId: comment.authorId, + body: isDeleted ? null : comment.body, + createdAt: comment.createdAt.toISOString(), + deletedAt: comment.deletedAt?.toISOString() ?? null, + id: comment.id, + isDeleted, + proposalId: comment.proposalId, + }; +} + +function proposalCommentVisibilityWhere(input: { + proposalId: string; +}): Prisma.ProposalCommentWhereInput { + return { + proposalId: input.proposalId, + }; +} + +function proposalCommentCursorWhere( + cursor: CommentCursor | null, +): Prisma.ProposalCommentWhereInput { + if (!cursor) { + return {}; + } + + const cursorDate = new Date(cursor.createdAt); + + return { + OR: [ + { + createdAt: { + gt: cursorDate, + }, + }, + { + createdAt: cursorDate, + id: { + gt: cursor.id, + }, + }, + ], + }; +} + +async function assertProposalInWorld( + database: ProposalCommentDatabase, + input: { proposalId: string; worldId: string }, +) { + const proposal = await database.proposal.findFirst({ + select: { + id: true, + }, + where: { + id: input.proposalId, + worldId: input.worldId, + }, + }); + + if (!proposal) { + throw new ProposalCommentError(404, 'PROPOSAL_NOT_FOUND', 'Proposal not found.'); + } +} + +export async function listProposalComments( + database: ProposalCommentDatabase, + input: { + cursor?: string | undefined; + pageSize?: number | undefined; + proposalId: string; + worldId: string; + }, +) { + await assertProposalInWorld(database, input); + + const pageSize = normalizePageSize(input.pageSize); + const cursor = input.cursor ? decodeProposalCommentCursor(input.cursor) : null; + const visibilityWhere = proposalCommentVisibilityWhere({ proposalId: input.proposalId }); + const pageWhere: Prisma.ProposalCommentWhereInput = { + ...visibilityWhere, + ...proposalCommentCursorWhere(cursor), + }; + const [comments, commentCount] = await Promise.all([ + database.proposalComment.findMany({ + include: { + author: { + select: { + avatarUrl: true, + displayName: true, + hiveUsername: true, + id: true, + }, + }, + }, + orderBy: [{ createdAt: 'asc' }, { id: 'asc' }], + take: pageSize + 1, + where: pageWhere, + }), + database.proposalComment.count({ + where: visibilityWhere, + }), + ]); + + const page = comments.slice(0, pageSize); + const last = page.at(-1); + const hasMore = comments.length > pageSize; + + return { + comments: page.map(serializeComment), + pageInfo: { + hasMore, + nextCursor: + hasMore && last + ? encodeCursor({ + createdAt: last.createdAt.toISOString(), + id: last.id, + }) + : null, + }, + totalCount: commentCount, + }; +} + +export async function createProposalComment( + database: ProposalCommentDatabase, + input: { authorId: string; body: string; proposalId: string; worldId: string }, +) { + const body = normalizeProposalCommentBody(input.body); + + await assertProposalInWorld(database, input); + + const comment = await database.proposalComment.create({ + data: { + authorId: input.authorId, + body, + proposalId: input.proposalId, + }, + include: { + author: { + select: { + avatarUrl: true, + displayName: true, + hiveUsername: true, + id: true, + }, + }, + }, + }); + + return { + comment: serializeComment(comment), + }; +} diff --git a/apps/api/src/lib/proposal-consistency.test.ts b/apps/api/src/lib/proposal-consistency.test.ts new file mode 100644 index 0000000..9a77250 --- /dev/null +++ b/apps/api/src/lib/proposal-consistency.test.ts @@ -0,0 +1,118 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { AIReportStatus } from '../generated/prisma/enums.js'; +import { runProposalConsistencyCheck } from './proposal-consistency.js'; + +function createDatabase() { + const reports: unknown[] = []; + const proposal = { + id: 'proposal-1', + proposedContent: { + body: 'The moon gate is open.', + }, + title: 'Moon Gate Reopens', + worldId: 'world-1', + }; + const bibleVersion = { + content: { + rule: 'The moon gate is not open.', + }, + id: 'bible-1', + versionNumber: 2, + }; + const loreEntries = [ + { + content: { + body: 'A published canon note.', + }, + id: 'lore-1', + title: 'Canon Note', + }, + ]; + const database = { + aIReport: { + async create(args: { data: Record }) { + const report = { + createdAt: new Date('2026-09-02T12:00:00.000Z'), + errorCode: null, + errorMessage: null, + id: `report-${reports.length + 1}`, + updatedAt: new Date('2026-09-02T12:00:00.000Z'), + ...args.data, + }; + reports.push(report); + return report; + }, + }, + loreEntry: { + async findMany() { + return loreEntries; + }, + }, + proposal: { + async findFirst(args: { where: { id: string; worldId: string } }) { + if (args.where.id !== proposal.id || args.where.worldId !== proposal.worldId) { + return null; + } + + return proposal; + }, + }, + worldBibleVersion: { + async findFirst() { + return bibleVersion; + }, + }, + $transaction(callback: (transaction: unknown) => Promise) { + return callback(database); + }, + }; + + return { + database, + reports, + }; +} + +describe('proposal consistency checks', () => { + test('creates a completed AI report with a visible major warning when proposed canon conflicts', async () => { + const state = createDatabase(); + + const result = await runProposalConsistencyCheck(state.database as never, { + proposalId: 'proposal-1', + worldId: 'world-1', + }); + + assert.equal(result.warningCount, 1); + assert.equal(result.aiReport.status, AIReportStatus.COMPLETED); + assert.equal(result.aiReport.provider, 'hivelore'); + assert.equal( + ( + (state.reports[0] as { findings: { findings: Array<{ severity: string }> } }).findings + .findings[0] as { severity: string } + ).severity, + 'high', + ); + }); + + test('stores a no-warning report when the proposal does not contradict canon', async () => { + const state = createDatabase(); + (state.database.proposal.findFirst as unknown as () => Promise) = async () => ({ + id: 'proposal-1', + proposedContent: { + body: 'The archive remains closed.', + }, + title: 'Archive Remains Closed', + worldId: 'world-1', + }); + + const result = await runProposalConsistencyCheck(state.database as never, { + proposalId: 'proposal-1', + worldId: 'world-1', + }); + + assert.equal(result.warningCount, 0); + assert.equal(result.aiReport.summary, 'No major canon consistency conflicts found.'); + }); +}); diff --git a/apps/api/src/lib/proposal-consistency.ts b/apps/api/src/lib/proposal-consistency.ts new file mode 100644 index 0000000..cfc36c4 --- /dev/null +++ b/apps/api/src/lib/proposal-consistency.ts @@ -0,0 +1,171 @@ +import type { Prisma, PrismaClient } from '../generated/prisma/client.js'; +import { AIReportStatus, LoreStatus } from '../generated/prisma/enums.js'; +import { flattenSearchText } from './search-index.js'; + +export class ProposalConsistencyError extends Error { + constructor( + public readonly statusCode: number, + public readonly code: string, + message: string, + ) { + super(message); + } +} + +export type ProposalConsistencyDatabase = Pick< + PrismaClient, + '$transaction' | 'aIReport' | 'loreEntry' | 'proposal' | 'worldBibleVersion' +>; + +const NEGATION_PATTERNS = [ + /\b(?:no|not|never|cannot|can't|wont|won't|without)\b\s+(?:be\s+|have\s+|has\s+|is\s+|are\s+)?([a-z][a-z0-9 -]{2,80})/gi, + /\b([a-z][a-z0-9 -]{2,80})\s+(?:is|are|was|were|has|have)\s+(?:no|not|never)\b/gi, +]; + +function normalizeFragment(value: string) { + return value + .toLowerCase() + .replace(/[^a-z0-9 ]+/g, ' ') + .replace(/\s+/g, ' ') + .trim(); +} + +function collectNegatedClaims(text: string) { + const claims = new Set(); + + for (const pattern of NEGATION_PATTERNS) { + for (const match of text.matchAll(pattern)) { + const claim = normalizeFragment(match[1] ?? ''); + + if (claim.length >= 3) { + claims.add(claim); + } + } + } + + return claims; +} + +function detectContradictions(input: { canonText: string; proposedText: string }) { + const canonText = normalizeFragment(input.canonText); + const proposedText = normalizeFragment(input.proposedText); + const canonNegations = collectNegatedClaims(canonText); + const proposedNegations = collectNegatedClaims(proposedText); + const findings: Array> = []; + + for (const claim of canonNegations) { + if (proposedText.includes(claim) && !proposedNegations.has(claim)) { + findings.push({ + category: 'canon_consistency', + evidence: claim, + severity: 'high', + summary: `Proposed content appears to assert "${claim}" even though existing canon negates it.`, + }); + } + } + + for (const claim of proposedNegations) { + if (canonText.includes(claim) && !canonNegations.has(claim)) { + findings.push({ + category: 'canon_consistency', + evidence: claim, + severity: 'high', + summary: `Proposed content appears to negate "${claim}" even though existing canon asserts it.`, + }); + } + } + + return findings; +} + +export async function runProposalConsistencyCheck( + database: ProposalConsistencyDatabase, + input: { proposalId: string; worldId: string }, +) { + return database.$transaction(async (transaction) => { + const proposal = await transaction.proposal.findFirst({ + select: { + id: true, + proposedContent: true, + title: true, + worldId: true, + }, + where: { + id: input.proposalId, + worldId: input.worldId, + }, + }); + + if (!proposal) { + throw new ProposalConsistencyError(404, 'PROPOSAL_NOT_FOUND', 'Proposal not found.'); + } + + const [currentBible, canonEntries] = await Promise.all([ + transaction.worldBibleVersion.findFirst({ + orderBy: { + versionNumber: 'desc', + }, + select: { + content: true, + id: true, + versionNumber: true, + }, + where: { + worldId: input.worldId, + }, + }), + transaction.loreEntry.findMany({ + select: { + content: true, + id: true, + title: true, + }, + take: 50, + where: { + status: LoreStatus.PUBLISHED_CANON, + worldId: input.worldId, + }, + }), + ]); + + const proposedText = [proposal.title, flattenSearchText(proposal.proposedContent)].join(' '); + const canonText = [ + flattenSearchText(currentBible?.content), + ...canonEntries.map((entry) => `${entry.title} ${flattenSearchText(entry.content)}`), + ].join(' '); + const findings = detectContradictions({ + canonText, + proposedText, + }); + const hasWarning = findings.length > 0; + const report = await transaction.aIReport.create({ + data: { + findings: { + checkedCanonEntries: canonEntries.length, + currentBibleVersionId: currentBible?.id ?? null, + currentBibleVersionNumber: currentBible?.versionNumber ?? null, + findings, + } satisfies Prisma.InputJsonObject, + model: 'deterministic-canon-consistency-v1', + proposalId: proposal.id, + provider: 'hivelore', + status: AIReportStatus.COMPLETED, + summary: hasWarning + ? `${findings.length} possible canon consistency conflict${findings.length === 1 ? '' : 's'} found.` + : 'No major canon consistency conflicts found.', + }, + }); + + return { + aiReport: { + findings: report.findings, + id: report.id, + model: report.model, + provider: report.provider, + status: report.status, + summary: report.summary, + }, + warningCount: findings.length, + }; + }); +} diff --git a/apps/api/src/lib/search-index.test.ts b/apps/api/src/lib/search-index.test.ts new file mode 100644 index 0000000..710c86f --- /dev/null +++ b/apps/api/src/lib/search-index.test.ts @@ -0,0 +1,186 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { LoreStatus, LoreType, SearchEntityType } from '../generated/prisma/enums.js'; +import { + flattenSearchText, + rebuildSearchIndex, + searchWorldLore, + upsertLoreSearchIndex, + upsertWorldSearchIndex, +} from './search-index.js'; + +function createDatabase() { + const searchRows: Array> = []; + const worlds = [ + { + bibleVersions: [ + { + content: { + law: 'The obsidian tower remembers every oath.', + }, + versionNumber: 1, + }, + ], + description: 'A moonlit city of archives.', + id: 'world-1', + slug: 'moon-archive', + title: 'Moon Archive', + }, + ]; + const loreEntries = [ + { + content: { + body: 'Archivist Sera guards the obsidian tower.', + }, + id: 'lore-1', + loreType: LoreType.CHARACTER, + slug: 'sera', + status: LoreStatus.PUBLISHED_CANON, + title: 'Sera', + worldId: 'world-1', + }, + { + content: { + body: 'Private draft', + }, + id: 'draft-1', + loreType: LoreType.CHARACTER, + slug: 'draft', + status: LoreStatus.DRAFT, + title: 'Draft', + worldId: 'world-1', + }, + ]; + const database = { + async $queryRaw() { + return [ + { + entityId: 'lore-1', + entityType: SearchEntityType.LORE_ENTRY, + metadata: { loreType: LoreType.CHARACTER }, + rank: 0.4, + title: 'Sera', + worldId: 'world-1', + }, + ]; + }, + async $transaction(callback: (transaction: unknown) => Promise) { + return callback(database); + }, + loreEntry: { + async findMany(args?: { where?: { status?: LoreStatus } }) { + return args?.where?.status + ? loreEntries.filter((entry) => entry.status === args.where?.status) + : loreEntries; + }, + async findUnique(args: { where: { id: string } }) { + return loreEntries.find((entry) => entry.id === args.where.id) ?? null; + }, + }, + searchIndex: { + async deleteMany(args: { where?: { entityId?: string; entityType?: string } } = {}) { + const before = searchRows.length; + + for (let index = searchRows.length - 1; index >= 0; index -= 1) { + const row = searchRows[index]!; + if ( + (!args.where?.entityId || row.entityId === args.where.entityId) && + (!args.where?.entityType || row.entityType === args.where.entityType) + ) { + searchRows.splice(index, 1); + } + } + + return { count: before - searchRows.length }; + }, + async upsert(args: { + create: Record; + update: Record; + where: { entityType_entityId: { entityId: string; entityType: string } }; + }) { + const existing = searchRows.find( + (row) => + row.entityId === args.where.entityType_entityId.entityId && + row.entityType === args.where.entityType_entityId.entityType, + ); + + if (existing) { + Object.assign(existing, args.update); + return existing; + } + + searchRows.push(args.create); + return args.create; + }, + }, + world: { + async findMany() { + return worlds.map((world) => ({ id: world.id })); + }, + async findUnique(args: { where: { id: string } }) { + return worlds.find((world) => world.id === args.where.id) ?? null; + }, + }, + worldBibleVersion: {}, + }; + + return { + database, + searchRows, + }; +} + +describe('search index projection', () => { + test('flattens structured content into searchable text', () => { + assert.equal( + flattenSearchText({ body: ['Moon', { place: 'Archive' }], ok: true }), + 'Moon Archive true', + ); + }); + + test('upserts worlds and only published canon lore entries', async () => { + const state = createDatabase(); + + await upsertWorldSearchIndex(state.database as never, 'world-1'); + await upsertLoreSearchIndex(state.database as never, 'lore-1'); + await upsertLoreSearchIndex(state.database as never, 'draft-1'); + + assert.deepEqual( + state.searchRows.map((row) => [row.entityType, row.entityId]), + [ + [SearchEntityType.WORLD, 'world-1'], + [SearchEntityType.LORE_ENTRY, 'lore-1'], + ], + ); + assert.match(String(state.searchRows[0]?.searchableContent), /obsidian tower/); + }); + + test('rebuilds all searchable projections and returns counts', async () => { + const state = createDatabase(); + + const result = await rebuildSearchIndex(state.database as never); + + assert.deepEqual(result, { loreEntries: 1, worlds: 1 }); + assert.equal(state.searchRows.length, 2); + }); + + test('runs ranked search with pagination metadata', async () => { + const state = createDatabase(); + + const result = await searchWorldLore(state.database as never, { + page: 1, + pageSize: 10, + q: 'obsidian tower', + type: SearchEntityType.LORE_ENTRY, + worldId: 'world-1', + }); + + assert.equal(result.results[0]?.entityId, 'lore-1'); + assert.deepEqual(result.pageInfo, { + hasMore: false, + page: 1, + pageSize: 10, + }); + }); +}); diff --git a/apps/api/src/lib/search-index.ts b/apps/api/src/lib/search-index.ts new file mode 100644 index 0000000..7c2f696 --- /dev/null +++ b/apps/api/src/lib/search-index.ts @@ -0,0 +1,259 @@ +import type { Prisma, PrismaClient } from '../generated/prisma/client.js'; +import { LoreStatus, SearchEntityType } from '../generated/prisma/enums.js'; + +const MAX_QUERY_LENGTH = 120; +const MAX_PAGE_SIZE = 50; + +type SearchDatabase = Pick< + PrismaClient, + '$queryRaw' | '$transaction' | 'loreEntry' | 'searchIndex' | 'world' | 'worldBibleVersion' +>; + +type SearchIndexWriter = Pick< + PrismaClient, + 'loreEntry' | 'searchIndex' | 'world' | 'worldBibleVersion' +>; + +export type SearchQueryInput = { + page?: number | undefined; + pageSize?: number | undefined; + q: string; + type?: SearchEntityType | undefined; + worldId?: string | undefined; +}; + +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +export function flattenSearchText(value: unknown): string { + if (typeof value === 'string') { + return value; + } + + if (typeof value === 'number' || typeof value === 'boolean') { + return String(value); + } + + if (Array.isArray(value)) { + return value.map(flattenSearchText).filter(Boolean).join(' '); + } + + if (isRecord(value)) { + return Object.values(value).map(flattenSearchText).filter(Boolean).join(' '); + } + + return ''; +} + +function cleanQuery(q: string) { + return q.trim().replace(/\s+/g, ' '); +} + +function cleanPageSize(pageSize = 20) { + return Math.min(Math.max(pageSize, 1), MAX_PAGE_SIZE); +} + +function cleanPage(page = 1) { + return Math.max(page, 1); +} + +export async function upsertWorldSearchIndex(database: SearchIndexWriter, worldId: string) { + const world = await database.world.findUnique({ + include: { + bibleVersions: { + orderBy: { + versionNumber: 'desc', + }, + take: 1, + }, + }, + where: { + id: worldId, + }, + }); + + if (!world) { + await database.searchIndex.deleteMany({ + where: { + entityId: worldId, + entityType: SearchEntityType.WORLD, + }, + }); + return; + } + + const currentBible = world.bibleVersions[0]; + await database.searchIndex.upsert({ + create: { + entityId: world.id, + entityType: SearchEntityType.WORLD, + metadata: { + slug: world.slug, + }, + searchableContent: [world.description, flattenSearchText(currentBible?.content)] + .filter(Boolean) + .join(' '), + title: world.title, + worldId: world.id, + }, + update: { + metadata: { + slug: world.slug, + }, + searchableContent: [world.description, flattenSearchText(currentBible?.content)] + .filter(Boolean) + .join(' '), + title: world.title, + worldId: world.id, + }, + where: { + entityType_entityId: { + entityId: world.id, + entityType: SearchEntityType.WORLD, + }, + }, + }); +} + +export async function upsertLoreSearchIndex(database: SearchIndexWriter, loreEntryId: string) { + const entry = await database.loreEntry.findUnique({ + select: { + content: true, + id: true, + loreType: true, + slug: true, + status: true, + title: true, + worldId: true, + }, + where: { + id: loreEntryId, + }, + }); + + if (!entry || entry.status !== LoreStatus.PUBLISHED_CANON) { + await database.searchIndex.deleteMany({ + where: { + entityId: loreEntryId, + entityType: SearchEntityType.LORE_ENTRY, + }, + }); + return; + } + + await database.searchIndex.upsert({ + create: { + entityId: entry.id, + entityType: SearchEntityType.LORE_ENTRY, + metadata: { + loreType: entry.loreType, + slug: entry.slug, + }, + searchableContent: flattenSearchText(entry.content), + title: entry.title, + worldId: entry.worldId, + }, + update: { + metadata: { + loreType: entry.loreType, + slug: entry.slug, + }, + searchableContent: flattenSearchText(entry.content), + title: entry.title, + worldId: entry.worldId, + }, + where: { + entityType_entityId: { + entityId: entry.id, + entityType: SearchEntityType.LORE_ENTRY, + }, + }, + }); +} + +export async function rebuildSearchIndex(database: SearchDatabase) { + return database.$transaction(async (transaction) => { + await transaction.searchIndex.deleteMany({}); + + const worlds = await transaction.world.findMany({ + select: { + id: true, + }, + }); + const loreEntries = await transaction.loreEntry.findMany({ + select: { + id: true, + }, + where: { + status: LoreStatus.PUBLISHED_CANON, + }, + }); + + for (const world of worlds) { + await upsertWorldSearchIndex(transaction, world.id); + } + + for (const entry of loreEntries) { + await upsertLoreSearchIndex(transaction, entry.id); + } + + return { + loreEntries: loreEntries.length, + worlds: worlds.length, + }; + }); +} + +export async function searchWorldLore(database: SearchDatabase, input: SearchQueryInput) { + const q = cleanQuery(input.q); + + if (!q || q.length > MAX_QUERY_LENGTH) { + throw new Error('Search query must be between 1 and 120 characters.'); + } + + const page = cleanPage(input.page); + const pageSize = cleanPageSize(input.pageSize); + const offset = (page - 1) * pageSize; + const rows = await database.$queryRaw< + Array<{ + entityId: string; + entityType: SearchEntityType; + metadata: Prisma.JsonValue | null; + rank: number; + title: string; + worldId: string | null; + }> + >` + SELECT + "entityId", + "entityType", + "metadata", + ts_rank("searchVector", websearch_to_tsquery('english', ${q}))::float AS rank, + "title", + "worldId" + FROM "SearchIndex" + WHERE "searchVector" @@ websearch_to_tsquery('english', ${q}) + AND (${input.worldId ?? null}::text IS NULL OR "worldId" = ${input.worldId ?? null}) + AND (${input.type ?? null}::"SearchEntityType" IS NULL OR "entityType" = ${input.type ?? null}::"SearchEntityType") + ORDER BY rank DESC, "updatedAt" DESC, "id" DESC + LIMIT ${pageSize} + OFFSET ${offset} + `; + + return { + pageInfo: { + hasMore: rows.length === pageSize, + page, + pageSize, + }, + results: rows.map((row) => ({ + entityId: row.entityId, + entityType: row.entityType, + metadata: row.metadata, + rank: row.rank, + title: row.title, + worldId: row.worldId, + })), + }; +} diff --git a/apps/api/src/lib/user-profiles.ts b/apps/api/src/lib/user-profiles.ts new file mode 100644 index 0000000..417085c --- /dev/null +++ b/apps/api/src/lib/user-profiles.ts @@ -0,0 +1,212 @@ +import { normalizeHiveUsername } from './hive-username.js'; + +export type ReputationLevel = { + badge: string; + label: string; + nextScore: number | null; +}; + +export type UserProfileDatabase = { + user: { + findUnique(args: unknown): Promise<{ + avatarUrl: string | null; + bio: string | null; + createdAt: Date; + displayName: string | null; + hiveUsername: string; + id: string; + normalizedHiveUsername: string; + contributionDrafts: Array<{ + id: string; + kind: string; + proposal: { id: string; status: string; submittedAt: Date | null } | null; + status: string; + submittedAt: Date | null; + title: string; + updatedAt: Date; + world: { id: string; slug: string; title: string }; + }>; + loreEntries: Array<{ + id: string; + loreType: string; + slug: string; + status: string; + title: string; + updatedAt: Date; + world: { id: string; slug: string; title: string }; + }>; + reputationSnapshots: Array<{ + breakdown: unknown; + calculatedAt: Date; + calculationVersion: string; + score: { toString(): string } | number | string; + }>; + votes: Array<{ + choice: string; + createdAt: Date; + proposal: { + id: string; + status: string; + title: string; + world: { id: string; slug: string; title: string }; + }; + }>; + } | null>; + }; +}; + +export function getReputationLevel(score: number): ReputationLevel { + if (score >= 250) { + return { badge: 'Worldsmith', label: 'Worldsmith', nextScore: null }; + } + + if (score >= 100) { + return { badge: 'Canon Keeper', label: 'Canon Keeper', nextScore: 250 }; + } + + if (score >= 25) { + return { badge: 'Contributor', label: 'Contributor', nextScore: 100 }; + } + + return { badge: 'Seedling', label: 'Seedling', nextScore: 25 }; +} + +function scoreToNumber(score: { toString(): string } | number | string) { + return Number(score.toString()); +} + +function serializeDate(value: Date | null) { + return value?.toISOString() ?? null; +} + +export async function getUserProfile(database: UserProfileDatabase, username: string) { + const normalizedHiveUsername = normalizeHiveUsername(username); + const user = await database.user.findUnique({ + where: { normalizedHiveUsername }, + select: { + avatarUrl: true, + bio: true, + createdAt: true, + displayName: true, + hiveUsername: true, + id: true, + normalizedHiveUsername: true, + contributionDrafts: { + // Public endpoint: never expose unsubmitted drafts (ContributionStatus.DRAFT). + where: { status: 'SUBMITTED' }, + orderBy: { updatedAt: 'desc' }, + select: { + id: true, + kind: true, + proposal: { select: { id: true, status: true, submittedAt: true } }, + status: true, + submittedAt: true, + title: true, + updatedAt: true, + world: { select: { id: true, slug: true, title: true } }, + }, + take: 10, + }, + loreEntries: { + // Public endpoint: only canon is public. DRAFT/SUBMITTED/APPROVED_FOR_PUBLICATION + // and ARCHIVED entries stay private to the author. + where: { status: 'PUBLISHED_CANON' }, + orderBy: { updatedAt: 'desc' }, + select: { + id: true, + loreType: true, + slug: true, + status: true, + title: true, + updatedAt: true, + world: { select: { id: true, slug: true, title: true } }, + }, + take: 10, + }, + reputationSnapshots: { + orderBy: { calculatedAt: 'desc' }, + select: { + breakdown: true, + calculatedAt: true, + calculationVersion: true, + score: true, + }, + take: 1, + }, + votes: { + orderBy: { createdAt: 'desc' }, + select: { + choice: true, + createdAt: true, + proposal: { + select: { + id: true, + status: true, + title: true, + world: { select: { id: true, slug: true, title: true } }, + }, + }, + }, + take: 10, + }, + }, + }); + + if (!user) { + return null; + } + + const snapshot = user.reputationSnapshots[0] ?? null; + const score = snapshot ? scoreToNumber(snapshot.score) : 0; + + return { + user: { + avatarUrl: user.avatarUrl, + bio: user.bio, + createdAt: user.createdAt.toISOString(), + displayName: user.displayName, + hiveUsername: user.hiveUsername, + id: user.id, + normalizedHiveUsername: user.normalizedHiveUsername, + }, + reputation: { + breakdown: snapshot?.breakdown ?? null, + calculatedAt: serializeDate(snapshot?.calculatedAt ?? null), + calculationVersion: snapshot?.calculationVersion ?? null, + level: getReputationLevel(score), + score, + }, + history: { + contributions: user.contributionDrafts.map((draft) => ({ + id: draft.id, + kind: draft.kind, + proposal: draft.proposal + ? { + id: draft.proposal.id, + status: draft.proposal.status, + submittedAt: serializeDate(draft.proposal.submittedAt), + } + : null, + status: draft.status, + submittedAt: serializeDate(draft.submittedAt), + title: draft.title, + updatedAt: draft.updatedAt.toISOString(), + world: draft.world, + })), + loreEntries: user.loreEntries.map((entry) => ({ + id: entry.id, + loreType: entry.loreType, + slug: entry.slug, + status: entry.status, + title: entry.title, + updatedAt: entry.updatedAt.toISOString(), + world: entry.world, + })), + votes: user.votes.map((vote) => ({ + choice: vote.choice, + createdAt: vote.createdAt.toISOString(), + proposal: vote.proposal, + })), + }, + }; +} diff --git a/apps/api/src/lib/world-audit-log.test.ts b/apps/api/src/lib/world-audit-log.test.ts new file mode 100644 index 0000000..4a40633 --- /dev/null +++ b/apps/api/src/lib/world-audit-log.test.ts @@ -0,0 +1,98 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { ModerationStatus, WorldAuditAction } from '../generated/prisma/enums.js'; +import { + createModerationAuditLog, + createModerationAuditMetadata, + type WorldAuditLogWriter, +} from './world-audit-log.js'; + +describe('world audit log helpers', () => { + test('creates moderation audit logs with allowlisted metadata shape', async () => { + const calls: unknown[] = []; + const database: WorldAuditLogWriter = { + worldAuditLog: { + async create(args) { + calls.push(args); + return args; + }, + }, + }; + + await createModerationAuditLog(database, { + actorId: 'moderator-1', + worldId: 'world-1', + targetId: 'report-1', + metadata: { + before: { + status: ModerationStatus.IN_REVIEW, + reviewerId: null, + }, + after: { + status: ModerationStatus.RESOLVED, + reviewerId: 'moderator-1', + }, + reason: 'Confirmed spam report.', + }, + }); + + assert.deepEqual(calls, [ + { + data: { + actorId: 'moderator-1', + worldId: 'world-1', + action: WorldAuditAction.MODERATION_ACTION, + targetType: 'MODERATION_REPORT', + targetId: 'report-1', + metadata: { + before: { + status: ModerationStatus.IN_REVIEW, + reviewerId: null, + }, + after: { + status: ModerationStatus.RESOLVED, + reviewerId: 'moderator-1', + }, + reason: 'Confirmed spam report.', + }, + }, + }, + ]); + }); + + test('requires a reason for moderation audit metadata', () => { + assert.throws( + () => + createModerationAuditMetadata({ + before: { + status: ModerationStatus.IN_REVIEW, + }, + after: { + status: ModerationStatus.DISMISSED, + }, + reason: ' ', + }), + /Audit log reason is required/, + ); + }); + + test('rejects forbidden secret-bearing metadata keys', () => { + assert.throws( + () => + createModerationAuditMetadata({ + before: { + status: ModerationStatus.IN_REVIEW, + }, + after: { + status: ModerationStatus.RESOLVED, + }, + reason: 'Resolved report.', + requestPayload: { + signature: 'do-not-store', + }, + } as never), + /Audit metadata key is not allowed: requestPayload/, + ); + }); +}); diff --git a/apps/api/src/lib/world-audit-log.ts b/apps/api/src/lib/world-audit-log.ts new file mode 100644 index 0000000..4349947 --- /dev/null +++ b/apps/api/src/lib/world-audit-log.ts @@ -0,0 +1,104 @@ +import { ModerationStatus, WorldAuditAction } from '../generated/prisma/enums.js'; + +type ModerationAuditStatus = + | typeof ModerationStatus.IN_REVIEW + | typeof ModerationStatus.RESOLVED + | typeof ModerationStatus.DISMISSED; + +type ModerationAuditMetadata = { + before: { + status: ModerationAuditStatus; + reviewerId?: string | null; + }; + after: { + status: ModerationAuditStatus; + reviewerId?: string | null; + }; + reason: string; +}; + +export type CreateModerationAuditLogInput = { + actorId: string; + worldId: string; + targetId: string; + metadata: ModerationAuditMetadata; +}; + +export type WorldAuditLogWriter = { + worldAuditLog: { + create(args: { + data: { + actorId: string; + worldId: string; + action: typeof WorldAuditAction.MODERATION_ACTION; + targetType: 'MODERATION_REPORT'; + targetId: string; + metadata: ModerationAuditMetadata; + }; + }): Promise; + }; +}; + +const FORBIDDEN_METADATA_KEYS = [ + 'auth', + 'authentication', + 'challenge', + 'cookie', + 'cookies', + 'env', + 'environment', + 'headers', + 'payload', + 'request', + 'secret', + 'signature', + 'token', +] as const; + +function assertNonEmptyReason(reason: string) { + if (!reason.trim()) { + throw new Error('Audit log reason is required.'); + } +} + +function assertNoForbiddenMetadataKeys(value: unknown) { + if (!value || typeof value !== 'object') { + return; + } + + for (const [key, nestedValue] of Object.entries(value)) { + const normalizedKey = key.toLowerCase(); + const containsForbiddenKey = FORBIDDEN_METADATA_KEYS.some((forbiddenKey) => + normalizedKey.includes(forbiddenKey), + ); + + if (containsForbiddenKey) { + throw new Error(`Audit metadata key is not allowed: ${key}`); + } + + assertNoForbiddenMetadataKeys(nestedValue); + } +} + +export function createModerationAuditMetadata(metadata: ModerationAuditMetadata) { + assertNonEmptyReason(metadata.reason); + assertNoForbiddenMetadataKeys(metadata); + + return metadata; +} + +export async function createModerationAuditLog( + database: WorldAuditLogWriter, + input: CreateModerationAuditLogInput, +) { + return database.worldAuditLog.create({ + data: { + actorId: input.actorId, + worldId: input.worldId, + action: WorldAuditAction.MODERATION_ACTION, + targetType: 'MODERATION_REPORT', + targetId: input.targetId, + metadata: createModerationAuditMetadata(input.metadata), + }, + }); +} diff --git a/apps/api/src/lib/world-authorization.test.ts b/apps/api/src/lib/world-authorization.test.ts new file mode 100644 index 0000000..48af2d6 --- /dev/null +++ b/apps/api/src/lib/world-authorization.test.ts @@ -0,0 +1,267 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { PlatformRole } from '../generated/prisma/enums.js'; +import { + authorizeWorldPermission, + requireTrustedAuthenticatedUser, + requireWorldPermission, + resolveWorldMembership, + type AuthorizedWorldMembership, + type AuthenticatedUser, + type WorldAuthorizationRequest, + type WorldMembershipLookup, +} from './world-authorization.js'; +import { WORLD_PERMISSIONS, WORLD_ROLES } from './world-permissions.js'; + +type TestRequest = WorldAuthorizationRequest & { + body?: unknown; + headers?: Record; + params?: { + worldId?: string; + }; + query?: unknown; +}; + +type ReplyPayload = { + error: string; +}; + +function createReply() { + return { + statusCode: 200, + payload: undefined as ReplyPayload | undefined, + code(statusCode: number) { + this.statusCode = statusCode; + return this; + }, + send(payload: ReplyPayload) { + this.payload = payload; + return Promise.resolve(this); + }, + }; +} + +function createDatabase(membership: AuthorizedWorldMembership | null) { + const calls: Array<{ worldId: string; userId: string; revokedAt: null }> = []; + const database: WorldMembershipLookup = { + worldMembership: { + async findUnique(args) { + calls.push({ + ...args.where.worldId_userId, + revokedAt: args.where.revokedAt, + }); + return membership; + }, + }, + }; + + return { + calls, + database, + }; +} + +const user: AuthenticatedUser = { + id: 'user-1', + hiveUsername: 'emberquill.dev', + normalizedHiveUsername: 'emberquill.dev', + platformRole: PlatformRole.USER, +}; + +const platformAdminUser: AuthenticatedUser = { + ...user, + id: 'platform-admin-1', + platformRole: PlatformRole.ADMIN, +}; + +const contributorMembership: AuthorizedWorldMembership = { + id: 'membership-1', + worldId: 'world-1', + userId: user.id, + role: WORLD_ROLES.CONTRIBUTOR, + revokedAt: null, +}; + +describe('world authorization', () => { + test('allows an active member whose role includes the requested permission', async () => { + const request: TestRequest = { user }; + const reply = createReply(); + const { calls, database } = createDatabase(contributorMembership); + + const allowed = await authorizeWorldPermission( + request, + reply, + 'world-1', + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + database, + ); + + assert.equal(allowed, true); + assert.equal(reply.statusCode, 200); + assert.equal(reply.payload, undefined); + assert.deepEqual(calls, [{ worldId: 'world-1', userId: user.id, revokedAt: null }]); + assert.equal(request.worldMembership, contributorMembership); + }); + + test('denies a member whose role lacks the requested permission with 403', async () => { + const request: TestRequest = { user }; + const reply = createReply(); + const { database } = createDatabase(contributorMembership); + + const allowed = await authorizeWorldPermission( + request, + reply, + 'world-1', + WORLD_PERMISSIONS.MARK_SPAM_ABUSE, + database, + ); + + assert.equal(allowed, false); + assert.equal(reply.statusCode, 403); + assert.deepEqual(reply.payload, { error: 'Insufficient world permissions.' }); + assert.equal(request.worldMembership, undefined); + }); + + test('rejects unauthenticated requests with 401 and no membership lookup', async () => { + const request: TestRequest = {}; + const reply = createReply(); + const { calls, database } = createDatabase(contributorMembership); + + const allowed = await authorizeWorldPermission( + request, + reply, + 'world-1', + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + database, + ); + + assert.equal(allowed, false); + assert.equal(reply.statusCode, 401); + assert.deepEqual(reply.payload, { error: 'Authentication required.' }); + assert.deepEqual(calls, []); + }); + + test('rejects client-supplied identity data unless trusted auth populated request.user', async () => { + const request: TestRequest = { + headers: { + 'x-user-id': user.id, + }, + body: { + user, + }, + query: { + userId: user.id, + }, + }; + const reply = createReply(); + const { calls, database } = createDatabase(contributorMembership); + + const authenticatedUser = await requireTrustedAuthenticatedUser(request, reply); + const allowed = await authorizeWorldPermission( + request, + reply, + 'world-1', + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + database, + ); + + assert.equal(authenticatedUser, null); + assert.equal(allowed, false); + assert.equal(reply.statusCode, 401); + assert.deepEqual(reply.payload, { error: 'Authentication required.' }); + assert.deepEqual(calls, []); + }); + + test('rejects authenticated non-members with 403', async () => { + const request: TestRequest = { user }; + const reply = createReply(); + const { calls, database } = createDatabase(null); + + const allowed = await authorizeWorldPermission( + request, + reply, + 'world-1', + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + database, + ); + + assert.equal(allowed, false); + assert.equal(reply.statusCode, 403); + assert.deepEqual(reply.payload, { error: 'Insufficient world permissions.' }); + assert.deepEqual(calls, [{ worldId: 'world-1', userId: user.id, revokedAt: null }]); + }); + + test('does not grant platform admins implicit world permissions', async () => { + const request: TestRequest = { user: platformAdminUser }; + const reply = createReply(); + const { calls, database } = createDatabase(null); + + const allowed = await authorizeWorldPermission( + request, + reply, + 'world-1', + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + database, + ); + + assert.equal(allowed, false); + assert.equal(reply.statusCode, 403); + assert.deepEqual(reply.payload, { error: 'Insufficient world permissions.' }); + assert.deepEqual(calls, [ + { worldId: 'world-1', userId: platformAdminUser.id, revokedAt: null }, + ]); + }); + + test('rejects revoked memberships with 403', async () => { + const request: TestRequest = { user }; + const reply = createReply(); + const { calls, database } = createDatabase(null); + + const allowed = await authorizeWorldPermission( + request, + reply, + 'world-1', + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + database, + ); + + assert.equal(allowed, false); + assert.equal(reply.statusCode, 403); + assert.deepEqual(reply.payload, { error: 'Insufficient world permissions.' }); + assert.deepEqual(calls, [{ worldId: 'world-1', userId: user.id, revokedAt: null }]); + }); + + test('caches membership lookups per request and world', async () => { + const request: TestRequest = { user }; + const { calls, database } = createDatabase(contributorMembership); + + const first = await resolveWorldMembership(request, 'world-1', database); + const second = await resolveWorldMembership(request, 'world-1', database); + + assert.equal(first, contributorMembership); + assert.equal(second, contributorMembership); + assert.deepEqual(calls, [{ worldId: 'world-1', userId: user.id, revokedAt: null }]); + }); + + test('returns reusable pre-handler middleware without attaching it globally', async () => { + const request: TestRequest = { + user, + params: { + worldId: 'world-1', + }, + }; + const reply = createReply(); + const { database } = createDatabase(contributorMembership); + const preHandler = requireWorldPermission( + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + (fastifyRequest) => (fastifyRequest.params as TestRequest['params'] | undefined)?.worldId, + database, + ); + + await preHandler.call(undefined as never, request as never, reply as never, undefined as never); + + assert.equal(reply.statusCode, 200); + assert.equal(request.worldMembership, contributorMembership); + }); +}); diff --git a/apps/api/src/lib/world-authorization.ts b/apps/api/src/lib/world-authorization.ts new file mode 100644 index 0000000..6a973e0 --- /dev/null +++ b/apps/api/src/lib/world-authorization.ts @@ -0,0 +1,184 @@ +import type { FastifyRequest, preHandlerHookHandler } from 'fastify'; + +import type { PlatformRole } from '../generated/prisma/enums.js'; +import { roleHasWorldPermission } from './world-permissions.js'; +import type { WorldPermission, WorldRole } from './world-permissions.js'; + +export type AuthenticatedUser = { + id: string; + hiveUsername: string; + normalizedHiveUsername: string; + platformRole: PlatformRole; +}; + +export type AuthorizedWorldMembership = { + id: string; + worldId: string; + userId: string; + role: WorldRole; + revokedAt: Date | null; +}; + +export type WorldMembershipLookup = { + worldMembership: { + findUnique(args: { + where: { + worldId_userId: { + worldId: string; + userId: string; + }; + revokedAt: null; + }; + select: { + id: true; + worldId: true; + userId: true; + role: true; + revokedAt: true; + }; + }): Promise; + }; +}; + +export type WorldAuthorizationRequest = { + user?: AuthenticatedUser; + worldMembershipCache?: Map; + worldMembership?: AuthorizedWorldMembership; +}; + +type WorldAuthorizationReply = { + code(statusCode: number): { + send(payload: { error: string }): unknown | Promise; + }; +}; + +type WorldIdResolver = (request: FastifyRequest) => string | null | undefined; + +declare module 'fastify' { + interface FastifyRequest { + /** + * Trusted server-side identity. This must only be assigned by HiveLore's + * authentication plugin after verifying the request session/signature. + * Authorization code must never derive identity or roles from headers, + * params, query strings, or request bodies supplied by the client. + */ + user?: AuthenticatedUser; + worldMembershipCache?: Map; + worldMembership?: AuthorizedWorldMembership; + } +} + +async function getDefaultDatabase() { + const { prisma } = await import('./prisma.js'); + + return prisma; +} + +function getMembershipCache(request: WorldAuthorizationRequest) { + request.worldMembershipCache ??= new Map(); + + return request.worldMembershipCache; +} + +export async function requireTrustedAuthenticatedUser( + request: WorldAuthorizationRequest, + reply: WorldAuthorizationReply, +) { + if (!request.user) { + await reply.code(401).send({ + error: 'Authentication required.', + }); + + return null; + } + + return request.user; +} + +export async function resolveWorldMembership( + request: WorldAuthorizationRequest, + worldId: string, + database?: WorldMembershipLookup, +) { + const user = request.user; + + if (!user) { + return null; + } + + const membershipDatabase = database ?? (await getDefaultDatabase()); + const cache = getMembershipCache(request); + + if (cache.has(worldId)) { + return cache.get(worldId) ?? null; + } + + const membership = await membershipDatabase.worldMembership.findUnique({ + where: { + worldId_userId: { + worldId, + userId: user.id, + }, + revokedAt: null, + }, + select: { + id: true, + worldId: true, + userId: true, + role: true, + revokedAt: true, + }, + }); + + cache.set(worldId, membership); + + return membership; +} + +export async function authorizeWorldPermission( + request: WorldAuthorizationRequest, + reply: WorldAuthorizationReply, + worldId: string, + permission: WorldPermission, + database?: WorldMembershipLookup, +) { + const user = await requireTrustedAuthenticatedUser(request, reply); + + if (!user) { + return false; + } + + const membership = await resolveWorldMembership(request, worldId, database); + + if (!membership || !roleHasWorldPermission(membership.role, permission)) { + await reply.code(403).send({ + error: 'Insufficient world permissions.', + }); + + return false; + } + + request.worldMembership = membership; + + return true; +} + +export function requireWorldPermission( + permission: WorldPermission, + resolveWorldId: WorldIdResolver, + database?: WorldMembershipLookup, +): preHandlerHookHandler { + return async (request, reply) => { + const worldId = resolveWorldId(request); + + if (!worldId) { + await reply.code(400).send({ + error: 'World id is required.', + }); + + return; + } + + await authorizeWorldPermission(request, reply, worldId, permission, database); + }; +} diff --git a/apps/api/src/lib/world-permissions.test.ts b/apps/api/src/lib/world-permissions.test.ts new file mode 100644 index 0000000..ef940d3 --- /dev/null +++ b/apps/api/src/lib/world-permissions.test.ts @@ -0,0 +1,70 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { WORLD_PERMISSIONS, WORLD_ROLE_PERMISSIONS, WORLD_ROLES } from './world-permissions.js'; +import type { WorldPermission, WorldRole } from './world-permissions.js'; + +const sortPermissions = (permissions: readonly WorldPermission[]) => [...permissions].sort(); + +const EXPECTED_ROLE_PERMISSIONS = { + [WORLD_ROLES.READER]: [ + WORLD_PERMISSIONS.VIEW_PUBLIC_WORLD, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + WORLD_PERMISSIONS.REPORT_SPAM_ABUSE, + ], + [WORLD_ROLES.CONTRIBUTOR]: [ + WORLD_PERMISSIONS.VIEW_PUBLIC_WORLD, + WORLD_PERMISSIONS.CREATE_LORE_DRAFT, + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + WORLD_PERMISSIONS.EDIT_OWN_DRAFT, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + WORLD_PERMISSIONS.REPORT_SPAM_ABUSE, + ], + [WORLD_ROLES.FOUNDER]: [ + WORLD_PERMISSIONS.VIEW_PUBLIC_WORLD, + WORLD_PERMISSIONS.CREATE_LORE_DRAFT, + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + WORLD_PERMISSIONS.CREATE_WORLD, + WORLD_PERMISSIONS.EDIT_OWN_DRAFT, + WORLD_PERMISSIONS.EDIT_INITIAL_CANON, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + WORLD_PERMISSIONS.EXECUTE_CANON_STATUS_AFTER_THRESHOLD, + WORLD_PERMISSIONS.REPORT_SPAM_ABUSE, + WORLD_PERMISSIONS.COMMENT_ON_AI_WARNING, + ], + [WORLD_ROLES.CURATOR]: [ + WORLD_PERMISSIONS.VIEW_PUBLIC_WORLD, + WORLD_PERMISSIONS.CREATE_LORE_DRAFT, + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + WORLD_PERMISSIONS.EDIT_OWN_DRAFT, + WORLD_PERMISSIONS.EDIT_ANY_DRAFT, + WORLD_PERMISSIONS.EDIT_CANON_MODERATION_FIX, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + WORLD_PERMISSIONS.EXECUTE_CANON_STATUS_AFTER_THRESHOLD, + WORLD_PERMISSIONS.REPORT_SPAM_ABUSE, + WORLD_PERMISSIONS.MARK_SPAM_ABUSE, + WORLD_PERMISSIONS.RESOLVE_AI_WARNING_QUEUE, + ], +} as const satisfies Record; + +describe('WORLD_ROLE_PERMISSIONS', () => { + test('uses generated Prisma roles as the complete role source', () => { + assert.deepEqual(Object.values(WORLD_ROLES), ['READER', 'CONTRIBUTOR', 'FOUNDER', 'CURATOR']); + }); + + test('does not include admin as a world membership role', () => { + assert.equal(Object.values(WORLD_ROLES).includes('ADMIN' as WorldRole), false); + assert.equal('ADMIN' in WORLD_ROLES, false); + }); + + test('defines exact permissions for every Prisma role', () => { + assert.deepEqual(Object.keys(WORLD_ROLE_PERMISSIONS).sort(), Object.values(WORLD_ROLES).sort()); + + for (const role of Object.values(WORLD_ROLES)) { + assert.deepEqual( + sortPermissions(WORLD_ROLE_PERMISSIONS[role]), + sortPermissions(EXPECTED_ROLE_PERMISSIONS[role]), + ); + } + }); +}); diff --git a/apps/api/src/lib/world-permissions.ts b/apps/api/src/lib/world-permissions.ts new file mode 100644 index 0000000..3ee0a8f --- /dev/null +++ b/apps/api/src/lib/world-permissions.ts @@ -0,0 +1,70 @@ +import { WorldRole as PrismaWorldRole } from '../generated/prisma/enums.js'; +import type { WorldRole as PrismaWorldRoleType } from '../generated/prisma/enums.js'; + +export const WORLD_ROLES = PrismaWorldRole; + +export type WorldRole = PrismaWorldRoleType; + +export const WORLD_PERMISSIONS = { + VIEW_PUBLIC_WORLD: 'VIEW_PUBLIC_WORLD', + CREATE_LORE_DRAFT: 'CREATE_LORE_DRAFT', + SUBMIT_PROPOSAL: 'SUBMIT_PROPOSAL', + CREATE_WORLD: 'CREATE_WORLD', + EDIT_OWN_DRAFT: 'EDIT_OWN_DRAFT', + EDIT_ANY_DRAFT: 'EDIT_ANY_DRAFT', + EDIT_INITIAL_CANON: 'EDIT_INITIAL_CANON', + EDIT_CANON_MODERATION_FIX: 'EDIT_CANON_MODERATION_FIX', + VOTE_ON_PROPOSAL: 'VOTE_ON_PROPOSAL', + EXECUTE_CANON_STATUS_AFTER_THRESHOLD: 'EXECUTE_CANON_STATUS_AFTER_THRESHOLD', + REPORT_SPAM_ABUSE: 'REPORT_SPAM_ABUSE', + MARK_SPAM_ABUSE: 'MARK_SPAM_ABUSE', + COMMENT_ON_AI_WARNING: 'COMMENT_ON_AI_WARNING', + RESOLVE_AI_WARNING_QUEUE: 'RESOLVE_AI_WARNING_QUEUE', +} as const; + +export type WorldPermission = (typeof WORLD_PERMISSIONS)[keyof typeof WORLD_PERMISSIONS]; + +export const WORLD_ROLE_PERMISSIONS = { + [WORLD_ROLES.READER]: [ + WORLD_PERMISSIONS.VIEW_PUBLIC_WORLD, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + WORLD_PERMISSIONS.REPORT_SPAM_ABUSE, + ], + [WORLD_ROLES.CONTRIBUTOR]: [ + WORLD_PERMISSIONS.VIEW_PUBLIC_WORLD, + WORLD_PERMISSIONS.CREATE_LORE_DRAFT, + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + WORLD_PERMISSIONS.EDIT_OWN_DRAFT, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + WORLD_PERMISSIONS.REPORT_SPAM_ABUSE, + ], + [WORLD_ROLES.FOUNDER]: [ + WORLD_PERMISSIONS.VIEW_PUBLIC_WORLD, + WORLD_PERMISSIONS.CREATE_LORE_DRAFT, + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + WORLD_PERMISSIONS.CREATE_WORLD, + WORLD_PERMISSIONS.EDIT_OWN_DRAFT, + WORLD_PERMISSIONS.EDIT_INITIAL_CANON, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + WORLD_PERMISSIONS.EXECUTE_CANON_STATUS_AFTER_THRESHOLD, + WORLD_PERMISSIONS.REPORT_SPAM_ABUSE, + WORLD_PERMISSIONS.COMMENT_ON_AI_WARNING, + ], + [WORLD_ROLES.CURATOR]: [ + WORLD_PERMISSIONS.VIEW_PUBLIC_WORLD, + WORLD_PERMISSIONS.CREATE_LORE_DRAFT, + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + WORLD_PERMISSIONS.EDIT_OWN_DRAFT, + WORLD_PERMISSIONS.EDIT_ANY_DRAFT, + WORLD_PERMISSIONS.EDIT_CANON_MODERATION_FIX, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + WORLD_PERMISSIONS.EXECUTE_CANON_STATUS_AFTER_THRESHOLD, + WORLD_PERMISSIONS.REPORT_SPAM_ABUSE, + WORLD_PERMISSIONS.MARK_SPAM_ABUSE, + WORLD_PERMISSIONS.RESOLVE_AI_WARNING_QUEUE, + ], +} as const satisfies Record; + +export function roleHasWorldPermission(role: WorldRole, permission: WorldPermission) { + return (WORLD_ROLE_PERMISSIONS[role] as readonly WorldPermission[]).includes(permission); +} diff --git a/apps/api/src/lib/world-resource-policies.test.ts b/apps/api/src/lib/world-resource-policies.test.ts new file mode 100644 index 0000000..837ca4a --- /dev/null +++ b/apps/api/src/lib/world-resource-policies.test.ts @@ -0,0 +1,450 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { LoreStatus, PlatformRole } from '../generated/prisma/enums.js'; +import type { AuthorizedWorldMembership, AuthenticatedUser } from './world-authorization.js'; +import { + canCreateVote, + canEditAnyDraft, + canEditOwnDraft, + canReviewModerationReport, + ensureResourceBelongsToWorld, + type ExistingVoteLookup, +} from './world-resource-policies.js'; +import { WORLD_ROLES } from './world-permissions.js'; + +const user: AuthenticatedUser = { + id: 'user-1', + hiveUsername: 'emberquill.dev', + normalizedHiveUsername: 'emberquill.dev', + platformRole: PlatformRole.USER, +}; + +const contributorMembership: AuthorizedWorldMembership = { + id: 'membership-1', + worldId: 'world-1', + userId: user.id, + role: WORLD_ROLES.CONTRIBUTOR, + revokedAt: null, +}; + +const readerMembership: AuthorizedWorldMembership = { + ...contributorMembership, + role: WORLD_ROLES.READER, +}; + +const curatorMembership: AuthorizedWorldMembership = { + ...contributorMembership, + role: WORLD_ROLES.CURATOR, +}; + +const otherWorldCuratorMembership: AuthorizedWorldMembership = { + ...curatorMembership, + id: 'membership-2', + worldId: 'world-2', +}; + +function createVoteDatabase(existingVote: { id: string } | null) { + const calls: Array<{ proposalId: string; voterId: string }> = []; + const database: ExistingVoteLookup = { + appVote: { + async findUnique(args) { + calls.push(args.where.proposalId_voterId); + return existingVote; + }, + }, + }; + + return { + calls, + database, + }; +} + +describe('world resource policies', () => { + test('allows editing one own draft', () => { + const decision = canEditOwnDraft({ + user, + membership: contributorMembership, + routeWorldId: 'world-1', + resource: { + worldId: 'world-1', + authorId: user.id, + status: LoreStatus.DRAFT, + }, + }); + + assert.deepEqual(decision, { allowed: true }); + }); + + test('denies editing someone else own draft through own-draft policy', () => { + const decision = canEditOwnDraft({ + user, + membership: contributorMembership, + routeWorldId: 'world-1', + resource: { + worldId: 'world-1', + authorId: 'other-user', + status: LoreStatus.DRAFT, + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 403, + error: 'Only the draft author can edit this resource.', + }); + }); + + test('denies own-draft editing for non-draft resources', () => { + const decision = canEditOwnDraft({ + user, + membership: contributorMembership, + routeWorldId: 'world-1', + resource: { + worldId: 'world-1', + authorId: user.id, + status: LoreStatus.SUBMITTED, + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 403, + error: 'Only drafts can be edited by this policy.', + }); + }); + + test('denies own-draft editing without edit-own-draft permissions', () => { + const decision = canEditOwnDraft({ + user, + membership: readerMembership, + routeWorldId: 'world-1', + resource: { + worldId: 'world-1', + authorId: user.id, + status: LoreStatus.DRAFT, + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }); + }); + + test('denies own-draft editing for a resource from another world', () => { + const decision = canEditOwnDraft({ + user, + membership: contributorMembership, + routeWorldId: 'world-1', + resource: { + worldId: 'world-2', + authorId: user.id, + status: LoreStatus.DRAFT, + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 404, + error: 'Resource not found in this world.', + }); + }); + + test('allows curators to edit any draft', () => { + const decision = canEditAnyDraft({ + membership: curatorMembership, + routeWorldId: 'world-1', + resource: { + worldId: 'world-1', + authorId: 'other-user', + status: LoreStatus.DRAFT, + }, + }); + + assert.deepEqual(decision, { allowed: true }); + }); + + test('denies contributors editing any draft', () => { + const decision = canEditAnyDraft({ + membership: contributorMembership, + routeWorldId: 'world-1', + resource: { + worldId: 'world-1', + authorId: 'other-user', + status: LoreStatus.DRAFT, + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }); + }); + + test('denies own-draft editing with a membership from another world', () => { + const decision = canEditOwnDraft({ + user, + membership: { + ...contributorMembership, + worldId: 'world-2', + }, + routeWorldId: 'world-1', + resource: { + worldId: 'world-1', + authorId: user.id, + status: LoreStatus.DRAFT, + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }); + }); + + test('denies any-draft editing with a valid curator membership from another world', () => { + const decision = canEditAnyDraft({ + membership: otherWorldCuratorMembership, + routeWorldId: 'world-1', + resource: { + worldId: 'world-1', + authorId: 'other-user', + status: LoreStatus.DRAFT, + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }); + }); + + test('denies any-draft editing for a resource from another world', () => { + const decision = canEditAnyDraft({ + membership: curatorMembership, + routeWorldId: 'world-1', + resource: { + worldId: 'world-2', + authorId: 'other-user', + status: LoreStatus.DRAFT, + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 404, + error: 'Resource not found in this world.', + }); + }); + + test('prevents duplicate votes', async () => { + const { calls, database } = createVoteDatabase({ id: 'vote-1' }); + + const decision = await canCreateVote({ + user, + membership: contributorMembership, + proposalId: 'proposal-1', + proposal: { + worldId: 'world-1', + }, + routeWorldId: 'world-1', + database, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 409, + error: 'User has already voted on this proposal.', + }); + assert.deepEqual(calls, [{ proposalId: 'proposal-1', voterId: user.id }]); + }); + + test('allows first vote', async () => { + const { calls, database } = createVoteDatabase(null); + + const decision = await canCreateVote({ + user, + membership: contributorMembership, + proposalId: 'proposal-1', + proposal: { + worldId: 'world-1', + }, + routeWorldId: 'world-1', + database, + }); + + assert.deepEqual(decision, { allowed: true }); + assert.deepEqual(calls, [{ proposalId: 'proposal-1', voterId: user.id }]); + }); + + test('prevents self-moderation of a report', () => { + const decision = canReviewModerationReport({ + user, + membership: curatorMembership, + routeWorldId: 'world-1', + report: { + worldId: 'world-1', + reporterId: user.id, + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 403, + error: 'Users cannot moderate their own reports.', + }); + }); + + test('allows reviewing reports submitted by another user', () => { + const decision = canReviewModerationReport({ + user, + membership: curatorMembership, + routeWorldId: 'world-1', + report: { + worldId: 'world-1', + reporterId: 'other-user', + }, + }); + + assert.deepEqual(decision, { allowed: true }); + }); + + test('rejects resources outside the route world and skips duplicate vote lookup', async () => { + const { calls, database } = createVoteDatabase(null); + + const decision = await canCreateVote({ + user, + membership: contributorMembership, + proposalId: 'proposal-1', + proposal: { + worldId: 'world-2', + }, + routeWorldId: 'world-1', + database, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 404, + error: 'Resource not found in this world.', + }); + assert.deepEqual(calls, []); + }); + + test('rejects missing resources as not found in route world', () => { + const decision = ensureResourceBelongsToWorld(null, 'world-1'); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 404, + error: 'Resource not found in this world.', + }); + }); + + test('denies voting with a membership from another world', async () => { + const { calls, database } = createVoteDatabase(null); + + const decision = await canCreateVote({ + user, + membership: { + ...contributorMembership, + worldId: 'world-2', + }, + proposalId: 'proposal-1', + proposal: { + worldId: 'world-1', + }, + routeWorldId: 'world-1', + database, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }); + assert.deepEqual(calls, []); + }); + + test('denies voting for a proposal from another world', async () => { + const { calls, database } = createVoteDatabase(null); + + const decision = await canCreateVote({ + user, + membership: contributorMembership, + proposalId: 'proposal-1', + proposal: { + worldId: 'world-2', + }, + routeWorldId: 'world-1', + database, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 404, + error: 'Resource not found in this world.', + }); + assert.deepEqual(calls, []); + }); + + test('denies moderation review with a membership from another world', () => { + const decision = canReviewModerationReport({ + user, + membership: otherWorldCuratorMembership, + routeWorldId: 'world-1', + report: { + worldId: 'world-1', + reporterId: 'other-user', + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }); + }); + + test('denies moderation review for a report from another world', () => { + const decision = canReviewModerationReport({ + user, + membership: curatorMembership, + routeWorldId: 'world-1', + report: { + worldId: 'world-2', + reporterId: 'other-user', + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 404, + error: 'Resource not found in this world.', + }); + }); + + test('denies moderation review without curator permissions', () => { + const decision = canReviewModerationReport({ + user, + membership: contributorMembership, + routeWorldId: 'world-1', + report: { + worldId: 'world-1', + reporterId: 'other-user', + }, + }); + + assert.deepEqual(decision, { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }); + }); +}); diff --git a/apps/api/src/lib/world-resource-policies.ts b/apps/api/src/lib/world-resource-policies.ts new file mode 100644 index 0000000..ab155b0 --- /dev/null +++ b/apps/api/src/lib/world-resource-policies.ts @@ -0,0 +1,281 @@ +import { LoreStatus } from '../generated/prisma/enums.js'; +import { roleHasWorldPermission, WORLD_PERMISSIONS } from './world-permissions.js'; +import type { AuthorizedWorldMembership, AuthenticatedUser } from './world-authorization.js'; + +type ResourceScopedToWorld = { + worldId: string; +}; + +type AuthoredDraftResource = ResourceScopedToWorld & { + authorId: string; + status: typeof LoreStatus.DRAFT | string; +}; + +type ModerationReportResource = ResourceScopedToWorld & { + reporterId: string; + reviewerId?: string | null; +}; + +export type PolicyDecision = + | { + allowed: true; + } + | { + allowed: false; + statusCode: 403 | 404 | 409; + error: string; + }; + +export type ExistingVoteLookup = { + appVote: { + findUnique(args: { + where: { + proposalId_voterId: { + proposalId: string; + voterId: string; + }; + }; + select: { + id: true; + }; + }): Promise<{ id: string } | null>; + }; +}; + +export function ensureResourceBelongsToWorld( + resource: ResourceScopedToWorld | null, + routeWorldId: string, +): PolicyDecision { + if (!resource || resource.worldId !== routeWorldId) { + return { + allowed: false, + statusCode: 404, + error: 'Resource not found in this world.', + }; + } + + return { + allowed: true, + }; +} + +export function ensureMembershipBelongsToWorld( + membership: AuthorizedWorldMembership, + routeWorldId: string, +): PolicyDecision { + if (membership.worldId !== routeWorldId) { + return { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }; + } + + return { + allowed: true, + }; +} + +export function canEditOwnDraft(args: { + user: AuthenticatedUser; + membership: AuthorizedWorldMembership; + resource: AuthoredDraftResource | null; + routeWorldId: string; +}): PolicyDecision { + const membershipDecision = ensureMembershipBelongsToWorld(args.membership, args.routeWorldId); + + if (!membershipDecision.allowed) { + return membershipDecision; + } + + const worldDecision = ensureResourceBelongsToWorld(args.resource, args.routeWorldId); + + if (!worldDecision.allowed) { + return worldDecision; + } + + const resource = args.resource; + if (!resource) { + return { + allowed: false, + statusCode: 404, + error: 'Resource not found in this world.', + }; + } + + if (resource.status !== LoreStatus.DRAFT) { + return { + allowed: false, + statusCode: 403, + error: 'Only drafts can be edited by this policy.', + }; + } + + if (resource.authorId !== args.user.id) { + return { + allowed: false, + statusCode: 403, + error: 'Only the draft author can edit this resource.', + }; + } + + if (!roleHasWorldPermission(args.membership.role, WORLD_PERMISSIONS.EDIT_OWN_DRAFT)) { + return { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }; + } + + return { + allowed: true, + }; +} + +export function canEditAnyDraft(args: { + membership: AuthorizedWorldMembership; + resource: AuthoredDraftResource | null; + routeWorldId: string; +}): PolicyDecision { + const membershipDecision = ensureMembershipBelongsToWorld(args.membership, args.routeWorldId); + + if (!membershipDecision.allowed) { + return membershipDecision; + } + + const worldDecision = ensureResourceBelongsToWorld(args.resource, args.routeWorldId); + + if (!worldDecision.allowed) { + return worldDecision; + } + + const resource = args.resource; + if (!resource) { + return { + allowed: false, + statusCode: 404, + error: 'Resource not found in this world.', + }; + } + + if (resource.status !== LoreStatus.DRAFT) { + return { + allowed: false, + statusCode: 403, + error: 'Only drafts can be edited by this policy.', + }; + } + + if (!roleHasWorldPermission(args.membership.role, WORLD_PERMISSIONS.EDIT_ANY_DRAFT)) { + return { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }; + } + + return { + allowed: true, + }; +} + +export async function canCreateVote(args: { + user: AuthenticatedUser; + membership: AuthorizedWorldMembership; + proposal: ResourceScopedToWorld | null; + proposalId: string; + routeWorldId: string; + database: ExistingVoteLookup; +}): Promise { + const membershipDecision = ensureMembershipBelongsToWorld(args.membership, args.routeWorldId); + + if (!membershipDecision.allowed) { + return membershipDecision; + } + + if (!roleHasWorldPermission(args.membership.role, WORLD_PERMISSIONS.VOTE_ON_PROPOSAL)) { + return { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }; + } + + const worldDecision = ensureResourceBelongsToWorld(args.proposal, args.routeWorldId); + + if (!worldDecision.allowed) { + return worldDecision; + } + + const existingVote = await args.database.appVote.findUnique({ + where: { + proposalId_voterId: { + proposalId: args.proposalId, + voterId: args.user.id, + }, + }, + select: { + id: true, + }, + }); + + if (existingVote) { + return { + allowed: false, + statusCode: 409, + error: 'User has already voted on this proposal.', + }; + } + + return { + allowed: true, + }; +} + +export function canReviewModerationReport(args: { + user: AuthenticatedUser; + membership: AuthorizedWorldMembership; + report: ModerationReportResource | null; + routeWorldId: string; +}): PolicyDecision { + const membershipDecision = ensureMembershipBelongsToWorld(args.membership, args.routeWorldId); + + if (!membershipDecision.allowed) { + return membershipDecision; + } + + if (!roleHasWorldPermission(args.membership.role, WORLD_PERMISSIONS.MARK_SPAM_ABUSE)) { + return { + allowed: false, + statusCode: 403, + error: 'Insufficient world permissions.', + }; + } + + const worldDecision = ensureResourceBelongsToWorld(args.report, args.routeWorldId); + + if (!worldDecision.allowed) { + return worldDecision; + } + + const report = args.report; + if (!report) { + return { + allowed: false, + statusCode: 404, + error: 'Resource not found in this world.', + }; + } + + if (report.reporterId === args.user.id) { + return { + allowed: false, + statusCode: 403, + error: 'Users cannot moderate their own reports.', + }; + } + + return { + allowed: true, + }; +} diff --git a/apps/api/src/lib/worlds.ts b/apps/api/src/lib/worlds.ts new file mode 100644 index 0000000..77c8f9d --- /dev/null +++ b/apps/api/src/lib/worlds.ts @@ -0,0 +1,597 @@ +import type { Prisma, PrismaClient } from '../generated/prisma/client.js'; +import { + LoreStatus, + ProposalStatus, + WorldAuditAction, + WorldRole, +} from '../generated/prisma/enums.js'; +import { mapWorldSlugConflict } from './prisma-conflicts.js'; +import { upsertWorldSearchIndex } from './search-index.js'; + +export type WorldSeedInput = { + premise: string; + genre: string; + tone: string; + mainConflict: string; + startingLocation?: string | undefined; + firstCharacters?: string[] | undefined; + firstFactions?: string[] | undefined; + firstHistoricalEvent?: string | undefined; +}; + +export type WorldBibleInput = { + content: Prisma.InputJsonValue; + changeSummary?: string | undefined; +}; + +export type CreateWorldInput = { + creatorId: string; + title: string; + description: string; + seed: WorldSeedInput; + bible: WorldBibleInput; +}; + +export type UpdateWorldInput = { + worldId: string; + actorId: string; + title?: string | undefined; + description?: string | undefined; + seed?: Partial | undefined; + bible?: WorldBibleInput | undefined; +}; + +export type WorldDatabase = Pick< + PrismaClient, + | '$transaction' + | 'loreEntry' + | 'proposal' + | 'refreshSession' + | 'searchIndex' + | 'world' + | 'worldAuditLog' + | 'worldBibleVersion' + | 'worldMembership' + | 'worldSeed' +>; + +export class WorldError extends Error { + constructor( + public readonly statusCode: number, + message: string, + ) { + super(message); + } +} + +const worldInclude = { + bibleVersions: { + orderBy: { + versionNumber: 'desc', + }, + take: 1, + }, + founder: { + select: { + avatarUrl: true, + displayName: true, + hiveUsername: true, + id: true, + normalizedHiveUsername: true, + }, + }, + seed: true, +} as const; + +const worldListInclude = { + bibleVersions: { + orderBy: { + versionNumber: 'desc', + }, + select: { + changeSummary: true, + createdAt: true, + creatorId: true, + hiveReferenceId: true, + id: true, + publishedAt: true, + updatedAt: true, + versionNumber: true, + }, + take: 1, + }, + founder: { + select: { + avatarUrl: true, + displayName: true, + hiveUsername: true, + id: true, + normalizedHiveUsername: true, + }, + }, + seed: true, +} as const; + +type WorldWithRelations = Prisma.WorldGetPayload<{ + include: typeof worldInclude; +}>; + +type WorldListItemWithRelations = Prisma.WorldGetPayload<{ + include: typeof worldListInclude; +}>; + +export function createSlug(title: string) { + const slug = title + .trim() + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, '') + .slice(0, 80); + + return slug || 'world'; +} + +function normalizeSeedInput(seed: WorldSeedInput) { + return { + firstCharacters: seed.firstCharacters?.map((value) => value.trim()).filter(Boolean) ?? [], + firstFactions: seed.firstFactions?.map((value) => value.trim()).filter(Boolean) ?? [], + firstHistoricalEvent: seed.firstHistoricalEvent?.trim() || null, + genre: seed.genre.trim(), + mainConflict: seed.mainConflict.trim(), + premise: seed.premise.trim(), + startingLocation: seed.startingLocation?.trim() || null, + tone: seed.tone.trim(), + }; +} + +function serializeSeed(seed: NonNullable) { + return { + createdAt: seed.createdAt.toISOString(), + firstCharacters: Array.isArray(seed.firstCharacters) ? seed.firstCharacters : [], + firstFactions: Array.isArray(seed.firstFactions) ? seed.firstFactions : [], + firstHistoricalEvent: seed.firstHistoricalEvent, + genre: seed.genre, + id: seed.id, + mainConflict: seed.mainConflict, + premise: seed.premise, + startingLocation: seed.startingLocation, + tone: seed.tone, + updatedAt: seed.updatedAt.toISOString(), + }; +} + +function serializeBibleVersion( + version: + | WorldWithRelations['bibleVersions'][number] + | WorldListItemWithRelations['bibleVersions'][number] + | null, +) { + if (!version) { + return null; + } + + return { + changeSummary: version.changeSummary, + ...('content' in version ? { content: version.content } : {}), + createdAt: version.createdAt.toISOString(), + creatorId: version.creatorId, + hiveReferenceId: version.hiveReferenceId, + id: version.id, + publishedAt: version.publishedAt?.toISOString() ?? null, + updatedAt: version.updatedAt.toISOString(), + versionNumber: version.versionNumber, + }; +} + +export function serializeWorld(world: WorldWithRelations) { + return { + createdAt: world.createdAt.toISOString(), + currentBibleVersion: serializeBibleVersion(world.bibleVersions[0] ?? null), + description: world.description, + founder: world.founder, + founderId: world.founderId, + id: world.id, + seed: world.seed ? serializeSeed(world.seed) : null, + slug: world.slug, + title: world.title, + updatedAt: world.updatedAt.toISOString(), + }; +} + +export type SerializedWorld = ReturnType; + +export function serializeWorldListItem(world: WorldListItemWithRelations) { + return { + createdAt: world.createdAt.toISOString(), + currentBibleVersion: serializeBibleVersion(world.bibleVersions[0] ?? null), + description: world.description, + founder: world.founder, + founderId: world.founderId, + id: world.id, + seed: world.seed ? serializeSeed(world.seed) : null, + slug: world.slug, + title: world.title, + updatedAt: world.updatedAt.toISOString(), + }; +} + +async function generateUniqueWorldSlug(database: Pick, title: string) { + const baseSlug = createSlug(title); + let slug = baseSlug; + + for (let suffix = 2; suffix <= 50; suffix += 1) { + const existing = await database.world.findUnique({ + where: { + slug, + }, + select: { + id: true, + }, + }); + + if (!existing) { + return slug; + } + + slug = `${baseSlug}-${suffix}`; + } + + throw new WorldError(409, 'Unable to create a unique world slug.'); +} + +export async function createWorld(database: WorldDatabase, input: CreateWorldInput) { + const seed = normalizeSeedInput(input.seed); + + try { + const world = await database.$transaction(async (transaction: Prisma.TransactionClient) => { + const slug = await generateUniqueWorldSlug(transaction, input.title); + const createdWorld = await transaction.world.create({ + data: { + description: input.description.trim(), + founderId: input.creatorId, + slug, + title: input.title.trim(), + }, + }); + + await transaction.worldSeed.create({ + data: { + firstCharacters: seed.firstCharacters, + firstFactions: seed.firstFactions, + firstHistoricalEvent: seed.firstHistoricalEvent, + genre: seed.genre, + mainConflict: seed.mainConflict, + premise: seed.premise, + startingLocation: seed.startingLocation, + tone: seed.tone, + worldId: createdWorld.id, + }, + }); + + await transaction.worldBibleVersion.create({ + data: { + changeSummary: input.bible.changeSummary?.trim() || 'Initial world bible.', + content: input.bible.content, + creatorId: input.creatorId, + versionNumber: 1, + worldId: createdWorld.id, + }, + }); + + const membership = await transaction.worldMembership.create({ + data: { + grantedById: input.creatorId, + role: WorldRole.FOUNDER, + userId: input.creatorId, + worldId: createdWorld.id, + }, + }); + + await transaction.worldAuditLog.create({ + data: { + action: WorldAuditAction.ROLE_ASSIGNED, + actorId: input.creatorId, + metadata: { + role: WorldRole.FOUNDER, + }, + targetId: membership.id, + targetType: 'WORLD_MEMBERSHIP', + worldId: createdWorld.id, + }, + }); + + await upsertWorldSearchIndex(transaction, createdWorld.id); + + return transaction.world.findUniqueOrThrow({ + include: worldInclude, + where: { + id: createdWorld.id, + }, + }); + }); + + return serializeWorld(world); + } catch (error) { + const conflict = mapWorldSlugConflict(error); + + if (conflict) { + throw new WorldError(conflict.statusCode, conflict.error); + } + + throw error; + } +} + +export async function listWorlds( + database: WorldDatabase, + input: { + genre?: string | undefined; + page?: number | undefined; + pageSize?: number | undefined; + q?: string | undefined; + tone?: string | undefined; + }, +) { + const page = input.page ?? 1; + const pageSize = input.pageSize ?? 20; + const where: Prisma.WorldWhereInput = {}; + + if (input.q) { + where.OR = [ + { + title: { + contains: input.q, + mode: 'insensitive', + }, + }, + { + description: { + contains: input.q, + mode: 'insensitive', + }, + }, + ]; + } + + if (input.genre || input.tone) { + where.seed = { + ...(input.genre + ? { + genre: { + equals: input.genre, + mode: 'insensitive', + }, + } + : {}), + ...(input.tone + ? { + tone: { + equals: input.tone, + mode: 'insensitive', + }, + } + : {}), + }; + } + + const [worlds, total] = await Promise.all([ + database.world.findMany({ + include: worldListInclude, + orderBy: [ + { + createdAt: 'desc', + }, + { + id: 'desc', + }, + ], + skip: (page - 1) * pageSize, + take: pageSize, + where, + }), + database.world.count({ + where, + }), + ]); + + return { + pagination: { + page, + pageSize, + total, + }, + worlds: worlds.map(serializeWorldListItem), + }; +} + +export async function getWorld(database: WorldDatabase, worldId: string) { + const world = await database.world.findUnique({ + include: worldInclude, + where: { + id: worldId, + }, + }); + + return world ? serializeWorld(world) : null; +} + +export async function getWorldHub(database: WorldDatabase, worldId: string) { + const world = await getWorld(database, worldId); + + if (!world) { + return null; + } + + const [canonLoreCount, activeProposalCount, latestLoreEntries] = await Promise.all([ + database.loreEntry.count({ + where: { + status: LoreStatus.PUBLISHED_CANON, + worldId, + }, + }), + database.proposal.count({ + where: { + status: { + in: [ProposalStatus.SUBMITTED, ProposalStatus.VOTING], + }, + worldId, + }, + }), + database.loreEntry.findMany({ + orderBy: [ + { + updatedAt: 'desc', + }, + { + id: 'desc', + }, + ], + select: { + id: true, + loreType: true, + slug: true, + status: true, + title: true, + updatedAt: true, + }, + take: 6, + where: { + status: LoreStatus.PUBLISHED_CANON, + worldId, + }, + }), + ]); + + return { + latestLoreEntries: latestLoreEntries.map((entry: { updatedAt: Date }) => ({ + ...entry, + updatedAt: entry.updatedAt.toISOString(), + })), + stats: { + activeProposalCount, + canonLoreCount, + }, + world, + }; +} + +export async function updateWorld(database: WorldDatabase, input: UpdateWorldInput) { + const world = await database.$transaction(async (transaction: Prisma.TransactionClient) => { + const current = await transaction.world.findUnique({ + include: { + bibleVersions: { + orderBy: { + versionNumber: 'desc', + }, + take: 1, + }, + seed: true, + }, + where: { + id: input.worldId, + }, + }); + + if (!current) { + throw new WorldError(404, 'World not found.'); + } + + if (input.title || input.description) { + await transaction.world.update({ + data: { + ...(input.description ? { description: input.description.trim() } : {}), + ...(input.title ? { title: input.title.trim() } : {}), + }, + where: { + id: input.worldId, + }, + }); + } + + if (input.seed) { + const currentSeed = current.seed; + + if (!currentSeed) { + throw new WorldError(409, 'World seed is missing.'); + } + + const normalizedSeed = normalizeSeedInput({ + firstCharacters: + input.seed.firstCharacters ?? + (Array.isArray(currentSeed.firstCharacters) + ? currentSeed.firstCharacters.filter( + (value: unknown): value is string => typeof value === 'string', + ) + : []), + firstFactions: + input.seed.firstFactions ?? + (Array.isArray(currentSeed.firstFactions) + ? currentSeed.firstFactions.filter( + (value: unknown): value is string => typeof value === 'string', + ) + : []), + firstHistoricalEvent: + input.seed.firstHistoricalEvent ?? currentSeed.firstHistoricalEvent ?? undefined, + genre: input.seed.genre ?? currentSeed.genre, + mainConflict: input.seed.mainConflict ?? currentSeed.mainConflict, + premise: input.seed.premise ?? currentSeed.premise, + startingLocation: input.seed.startingLocation ?? currentSeed.startingLocation ?? undefined, + tone: input.seed.tone ?? currentSeed.tone, + }); + + await transaction.worldSeed.update({ + data: normalizedSeed, + where: { + worldId: input.worldId, + }, + }); + } + + if (input.bible) { + const currentBible = current.bibleVersions[0]; + + if (!currentBible) { + throw new WorldError(409, 'World bible version is missing.'); + } + + if (currentBible.publishedAt || currentBible.hiveReferenceId) { + throw new WorldError(409, 'Published world bible versions cannot be edited in place.'); + } + + await transaction.worldBibleVersion.update({ + data: { + changeSummary: input.bible.changeSummary?.trim() || currentBible.changeSummary, + content: input.bible.content, + }, + where: { + id: currentBible.id, + }, + }); + + await transaction.worldAuditLog.create({ + data: { + action: WorldAuditAction.WORLD_BIBLE_UPDATED, + actorId: input.actorId, + metadata: { + changeSummary: input.bible.changeSummary?.trim() || currentBible.changeSummary, + versionNumber: currentBible.versionNumber, + }, + targetId: currentBible.id, + targetType: 'WORLD_BIBLE_VERSION', + worldId: input.worldId, + }, + }); + } + + await upsertWorldSearchIndex(transaction, input.worldId); + + return transaction.world.findUniqueOrThrow({ + include: worldInclude, + where: { + id: input.worldId, + }, + }); + }); + + return serializeWorld(world); +} diff --git a/apps/api/src/routes/auth.ts b/apps/api/src/routes/auth.ts index 2956a0c..e37661a 100644 --- a/apps/api/src/routes/auth.ts +++ b/apps/api/src/routes/auth.ts @@ -1,99 +1,440 @@ -import { randomUUID } from 'node:crypto'; -import type { FastifyInstance } from 'fastify'; +import type { FastifyInstance, FastifyRequest } from 'fastify'; import { z } from 'zod'; +import { env } from '../config/env.js'; +import type { Prisma } from '../generated/prisma/client.js'; +import { prisma } from '../lib/prisma.js'; +import { + createAuthChallenge, + consumeAuthChallenge, + type AuthChallengeDatabase, +} from '../lib/auth-challenges.js'; +import { randomToken } from '../lib/auth-crypto.js'; +import { + clearRefreshCookie, + getRefreshCookieName, + readCookie, + setRefreshCookie, +} from '../lib/auth-cookies.js'; +import { authenticateRequest, requireSession } from '../lib/auth-middleware.js'; +import { + issueSession, + InvalidRefreshTokenError, + RefreshTokenReuseError, + revokeRefreshToken, + rotateRefreshSession, + upsertHiveUser, +} from '../lib/auth-sessions.js'; +import { + DhiveAccountClient, + DhivePostingSignatureVerifier, + type HiveSignatureVerifier, +} from '../lib/hive-signature.js'; +import { InvalidHiveUsernameError, normalizeHiveUsername } from '../lib/hive-username.js'; + +const providerSchema = z.enum(['keychain', 'hivesigner']); + const challengeSchema = z.object({ - hiveUsername: z.string().min(1).max(32), + provider: providerSchema.default('keychain'), + username: z.string().min(1).max(64).optional(), + hiveUsername: z.string().min(1).max(64).optional(), }); const verifySchema = z.object({ - hiveUsername: z.string().min(1).max(32), + challengeId: z.string().min(1), + provider: providerSchema, + username: z.string().min(1).max(64).optional(), + hiveUsername: z.string().min(1).max(64).optional(), message: z.string().min(1), signature: z.string().min(1), + publicKey: z.string().min(1).optional(), }); -const challenges = new Map< - string, - { - message: string; - expiresAt: number; +const refreshSchema = z.object({ + refreshToken: z.string().min(1).optional(), +}); + +const logoutSchema = z.object({ + refreshToken: z.string().min(1).optional(), + revokeFamily: z.boolean().optional(), +}); + +type RegisterAuthRoutesOptions = { + challengeDatabase?: AuthChallengeDatabase; + signatureVerifier?: HiveSignatureVerifier; +}; + +function isTrustedBrowserOrigin(request: FastifyRequest) { + const expectedOrigin = env.CORS_ORIGIN; + const origin = request.headers.origin; + + if (origin) { + return origin === expectedOrigin; } ->(); -export async function registerAuthRoutes(app: FastifyInstance) { - app.post('/auth/challenge', async (request, reply) => { - const parsed = challengeSchema.safeParse(request.body); + const referer = request.headers.referer; - if (!parsed.success) { - return reply.code(400).send({ - error: 'Invalid Hive username.', - }); - } + if (!referer) { + return false; + } - const normalizedHiveUsername = parsed.data.hiveUsername.trim().toLowerCase(); + try { + return new URL(referer).origin === expectedOrigin; + } catch { + return false; + } +} - const nonce = randomUUID(); - const issuedAt = new Date().toISOString(); - const message = [ - 'Sign in to HiveLore', - `Hive username: ${normalizedHiveUsername}`, - `Nonce: ${nonce}`, - `Issued at: ${issuedAt}`, - ].join('\n'); +function readSubmittedUsername(body: { + hiveUsername?: string | undefined; + username?: string | undefined; +}) { + const username = body.username ?? body.hiveUsername; - challenges.set(normalizedHiveUsername, { - message, - expiresAt: Date.now() + 5 * 60 * 1000, - }); + if (!username) { + throw new InvalidHiveUsernameError(); + } - return { - hiveUsername: normalizedHiveUsername, - message, - expiresInSeconds: 300, - }; - }); + return normalizeHiveUsername(username); +} - app.post('/auth/verify', async (request, reply) => { - const parsed = verifySchema.safeParse(request.body); +function cookieOptions() { + return { + domain: env.AUTH_COOKIE_DOMAIN, + secure: env.AUTH_COOKIE_SECURE ?? env.NODE_ENV === 'production', + }; +} - if (!parsed.success) { - return reply.code(400).send({ - error: 'Invalid verification payload.', - }); - } +function sessionOptions() { + return { + accessTtlSeconds: env.AUTH_ACCESS_TOKEN_TTL_SECONDS, + audience: env.AUTH_JWT_AUDIENCE, + issuer: env.AUTH_JWT_ISSUER, + jwtSecret: env.AUTH_JWT_SECRET, + refreshSecret: env.AUTH_REFRESH_SECRET, + refreshTtlSeconds: env.AUTH_REFRESH_TOKEN_TTL_SECONDS, + }; +} + +export async function registerAuthRoutes( + app: FastifyInstance, + options: RegisterAuthRoutesOptions = {}, +) { + const database = prisma; + const challengeDatabase = options.challengeDatabase ?? database; + const signatureVerifier = + options.signatureVerifier ?? + new DhivePostingSignatureVerifier(new DhiveAccountClient(env.HIVE_RPC_URL)); + + app.post( + '/auth/challenge', + { + config: { + rateLimit: { + max: 20, + timeWindow: '1 minute', + }, + }, + }, + async (request, reply) => { + const parsed = challengeSchema.safeParse(request.body); + + if (!parsed.success) { + return reply.code(400).send({ + error: 'Invalid challenge payload.', + }); + } + + try { + const normalizedHiveUsername = readSubmittedUsername(parsed.data); + const challenge = await createAuthChallenge(challengeDatabase, { + audience: env.HIVE_AUTH_AUDIENCE, + hmacSecret: env.AUTH_JWT_SECRET, + nonce: randomToken(32), + provider: parsed.data.provider, + ttlSeconds: env.AUTH_CHALLENGE_TTL_SECONDS, + username: normalizedHiveUsername, + }); + + return { + challengeId: challenge.challengeId, + expiresAt: challenge.expiresAt.toISOString(), + expiresInSeconds: env.AUTH_CHALLENGE_TTL_SECONDS, + hiveUsername: challenge.username, + message: challenge.message, + provider: parsed.data.provider, + }; + } catch (error) { + if (error instanceof InvalidHiveUsernameError) { + return reply.code(400).send({ + error: 'Invalid Hive username.', + }); + } + + throw error; + } + }, + ); + + app.post( + '/auth/verify', + { + config: { + rateLimit: { + max: 30, + timeWindow: '1 minute', + }, + }, + }, + async (request, reply) => { + const parsed = verifySchema.safeParse(request.body); + + if (!parsed.success) { + return reply.code(400).send({ + error: 'Invalid verification payload.', + }); + } - const normalizedHiveUsername = parsed.data.hiveUsername.trim().toLowerCase(); + try { + const normalizedHiveUsername = readSubmittedUsername(parsed.data); + const isValidSignature = await signatureVerifier.verifyPostingSignature({ + message: parsed.data.message, + publicKey: parsed.data.publicKey, + signature: parsed.data.signature, + username: normalizedHiveUsername, + }); - const challenge = challenges.get(normalizedHiveUsername); + if (!isValidSignature) { + return reply.code(401).send({ + error: 'Authentication failed.', + }); + } - if (!challenge) { + const issuedSession = await database.$transaction( + async (transaction: Prisma.TransactionClient) => { + await consumeAuthChallenge(transaction, { + challengeId: parsed.data.challengeId, + hmacSecret: env.AUTH_JWT_SECRET, + message: parsed.data.message, + provider: parsed.data.provider, + username: normalizedHiveUsername, + }); + + const user = await upsertHiveUser(transaction, { + normalizedHiveUsername, + }); + + return issueSession(transaction, { + ...sessionOptions(), + ipAddress: request.ip, + user, + userAgent: request.headers['user-agent'], + }); + }, + ); + + setRefreshCookie(reply, issuedSession.refreshToken, { + ...cookieOptions(), + maxAgeSeconds: env.AUTH_REFRESH_TOKEN_TTL_SECONDS, + }); + + return { + accessToken: issuedSession.accessToken, + expiresInSeconds: env.AUTH_ACCESS_TOKEN_TTL_SECONDS, + user: issuedSession.user, + }; + } catch (error) { + if (error instanceof InvalidHiveUsernameError) { + return reply.code(400).send({ + error: 'Invalid Hive username.', + }); + } + + return reply.code(401).send({ + error: 'Authentication failed.', + }); + } + }, + ); + + app.post( + '/auth/refresh', + { + config: { + rateLimit: { + max: 40, + timeWindow: '1 minute', + }, + }, + }, + async (request, reply) => { + const parsed = refreshSchema.safeParse(request.body ?? {}); + + if (!parsed.success) { + return reply.code(400).send({ + error: 'Invalid refresh payload.', + }); + } + + const bodyRefreshToken = parsed.data.refreshToken; + const cookieRefreshToken = readCookie(request, getRefreshCookieName()); + const refreshToken = bodyRefreshToken ?? cookieRefreshToken; + + if (!refreshToken) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + if (!bodyRefreshToken && !isTrustedBrowserOrigin(request)) { + return reply.code(403).send({ + error: 'Request origin is not allowed.', + }); + } + + try { + const issuedSession = await rotateRefreshSession(database, { + ...sessionOptions(), + refreshToken, + }); + + setRefreshCookie(reply, issuedSession.refreshToken, { + ...cookieOptions(), + maxAgeSeconds: env.AUTH_REFRESH_TOKEN_TTL_SECONDS, + }); + + return { + accessToken: issuedSession.accessToken, + expiresInSeconds: env.AUTH_ACCESS_TOKEN_TTL_SECONDS, + user: issuedSession.user, + }; + } catch (error) { + clearRefreshCookie(reply, cookieOptions()); + + if (error instanceof RefreshTokenReuseError) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + if (error instanceof InvalidRefreshTokenError) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + throw error; + } + }, + ); + + app.post('/auth/logout', async (request, reply) => { + const parsed = logoutSchema.safeParse(request.body ?? {}); + + if (!parsed.success) { return reply.code(400).send({ - error: 'No active challenge found.', + error: 'Invalid logout payload.', }); } - if (challenge.expiresAt < Date.now()) { - challenges.delete(normalizedHiveUsername); + const bodyRefreshToken = parsed.data.refreshToken; + const cookieRefreshToken = readCookie(request, getRefreshCookieName()); + const refreshToken = bodyRefreshToken ?? cookieRefreshToken; - return reply.code(400).send({ - error: 'Challenge expired.', + if (!bodyRefreshToken && cookieRefreshToken && !isTrustedBrowserOrigin(request)) { + clearRefreshCookie(reply, cookieOptions()); + + return reply.code(403).send({ + error: 'Request origin is not allowed.', }); } - if (challenge.message !== parsed.data.message) { - return reply.code(400).send({ - error: 'Challenge message does not match.', + if (refreshToken) { + const logoutInput = { + refreshSecret: env.AUTH_REFRESH_SECRET, + refreshToken, + ...(parsed.data.revokeFamily === undefined + ? {} + : { + revokeFamily: parsed.data.revokeFamily, + }), + }; + + await revokeRefreshToken(database, { + ...logoutInput, }); } - return reply.code(501).send({ - error: 'Hive signature verification is not implemented yet.', - }); - }); + clearRefreshCookie(reply, cookieOptions()); - app.get('/me', async () => { return { - user: null, + ok: true, }; }); + + app.get( + '/me', + { + preHandler: requireSession({ + audience: env.AUTH_JWT_AUDIENCE, + database, + issuer: env.AUTH_JWT_ISSUER, + jwtSecret: env.AUTH_JWT_SECRET, + }), + }, + async (request, reply) => { + const authenticatedUser = await authenticateRequest(request, { + audience: env.AUTH_JWT_AUDIENCE, + database, + issuer: env.AUTH_JWT_ISSUER, + jwtSecret: env.AUTH_JWT_SECRET, + }); + + if (!authenticatedUser) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + const user = await database.user.findUnique({ + where: { + id: authenticatedUser.id, + }, + select: { + avatarUrl: true, + displayName: true, + hiveUsername: true, + id: true, + normalizedHiveUsername: true, + platformRole: true, + }, + }); + + if (!user) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + return { + user, + }; + }, + ); + + if (!env.GOOGLE_AUTH_ENABLED) { + app.all('/auth/google/*', async (_request, reply) => + reply.code(404).send({ + error: 'Google authentication is not enabled.', + }), + ); + return; + } + + app.all('/auth/google/*', async (_request, reply) => + reply.code(501).send({ + error: + 'Google authentication is configured but OAuth handling is not implemented in this MVP build.', + }), + ); } diff --git a/apps/api/src/routes/contributions.test.ts b/apps/api/src/routes/contributions.test.ts new file mode 100644 index 0000000..c5b455c --- /dev/null +++ b/apps/api/src/routes/contributions.test.ts @@ -0,0 +1,967 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import Fastify from 'fastify'; + +import { env } from '../config/env.js'; +import { + ContributionKind, + ContributionStatus, + PlatformRole, + ProposalStatus, + ProposalType, + WorldAuditAction, + WorldRole, +} from '../generated/prisma/enums.js'; +import { signAccessToken } from '../lib/auth-crypto.js'; +import { + createContribution, + deleteContribution, + submitContribution, + updateContribution, +} from '../lib/contributions.js'; +import { registerContributionRoutes } from './contributions.js'; + +const author = { + hiveUsername: 'mira-vale.dev', + id: 'user-author', + normalizedHiveUsername: 'mira-vale.dev', +}; + +const otherUser = { + hiveUsername: 'emberquill.dev', + id: 'user-other', + normalizedHiveUsername: 'emberquill.dev', +}; + +function authHeader(user = author) { + const token = signAccessToken( + { + hiveUsername: user.hiveUsername, + normalizedHiveUsername: user.normalizedHiveUsername, + platformRole: PlatformRole.USER, + sid: `session-${user.id}`, + sub: user.id, + }, + { + audience: env.AUTH_JWT_AUDIENCE, + issuer: env.AUTH_JWT_ISSUER, + secret: env.AUTH_JWT_SECRET, + ttlSeconds: 900, + }, + ); + + return { + authorization: `Bearer ${token}`, + }; +} + +const structuredDoc = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'The northern gate fell during the third winter.' }], + }, + ], +}; + +const emptyDoc = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: ' ' }], + }, + ], +}; + +type StoredContribution = { + id: string; + worldId: string; + authorId: string; + targetLoreEntryId: string | null; + kind: ContributionKind; + title: string; + summary: string | null; + content: unknown; + status: ContributionStatus; + proposalId: string | null; + createdAt: Date; + updatedAt: Date; + submittedAt: Date | null; +}; + +type StoredProposal = { + id: string; + worldId: string; + authorId: string; + proposalType: ProposalType; + contributionKind: ContributionKind; + status: ProposalStatus; + title: string; + summary: string; + proposedContent: unknown; + targetLoreEntryId: string | null; + resultingLoreEntryId: string | null; + resultingBibleVersionId: string | null; + submittedAt: Date | null; + votingStartedAt: Date | null; + approvedAt: Date | null; + rejectedAt: Date | null; + publishedAt: Date | null; + createdAt: Date; + updatedAt: Date; +}; + +function now() { + return new Date('2026-08-05T12:00:00.000Z'); +} + +function createContributionRecord(input: Partial = {}): StoredContribution { + return { + authorId: author.id, + content: structuredDoc, + createdAt: now(), + id: `contribution-${Math.random().toString(36).slice(2)}`, + kind: ContributionKind.LORE, + proposalId: null, + status: ContributionStatus.DRAFT, + submittedAt: null, + summary: 'A short summary.', + targetLoreEntryId: 'lore-1', + title: 'The Fall of the Northern Gate', + updatedAt: now(), + worldId: 'world-1', + ...input, + }; +} + +function createDatabase() { + const worlds = [{ id: 'world-1' }, { id: 'world-2' }]; + const loreEntries = [ + { + id: 'lore-1', + loreType: 'LOCATION', + slug: 'north-gate', + title: 'North Gate', + worldId: 'world-1', + }, + { + id: 'lore-2', + loreType: 'EVENT', + slug: 'other-world-event', + title: 'Other Event', + worldId: 'world-2', + }, + ]; + const memberships = [ + { + id: 'membership-author', + revokedAt: null, + role: WorldRole.CONTRIBUTOR, + userId: author.id, + worldId: 'world-1', + }, + { + id: 'membership-other', + revokedAt: null, + role: WorldRole.READER, + userId: otherUser.id, + worldId: 'world-1', + }, + ]; + const contributions: StoredContribution[] = []; + const proposals: StoredProposal[] = []; + const auditLogs: unknown[] = []; + let failNextProposalCreate = false; + let failNextAuditCreate = false; + let submitBeforeNextDeleteMany = false; + let submitBeforeNextUpdateMany = false; + let transactionQueue = Promise.resolve(); + const externallySubmittedContributionIds = new Set(); + + function includeContribution(contribution: StoredContribution) { + return { + ...contribution, + proposal: contribution.proposalId + ? (proposals.find((proposal) => proposal.id === contribution.proposalId) ?? null) + : null, + targetLoreEntry: contribution.targetLoreEntryId + ? (loreEntries.find((entry) => entry.id === contribution.targetLoreEntryId) ?? null) + : null, + }; + } + + const database: Record = {}; + + Object.assign(database, { + async $transaction(callback: (transaction: unknown) => Promise) { + const previousTransaction = transactionQueue; + let releaseTransaction!: () => void; + transactionQueue = new Promise((resolve) => { + releaseTransaction = resolve; + }); + + await previousTransaction; + + const contributionSnapshot = contributions.map((contribution) => ({ ...contribution })); + const proposalSnapshot = proposals.map((proposal) => ({ ...proposal })); + const auditSnapshot = [...auditLogs]; + + try { + return await callback(database); + } catch (error) { + contributions.splice(0, contributions.length, ...contributionSnapshot); + proposals.splice(0, proposals.length, ...proposalSnapshot); + auditLogs.splice(0, auditLogs.length, ...auditSnapshot); + + for (const contributionId of externallySubmittedContributionIds) { + const contribution = contributions.find((candidate) => candidate.id === contributionId); + + if (contribution) { + contribution.status = ContributionStatus.SUBMITTED; + contribution.submittedAt = now(); + } + } + + externallySubmittedContributionIds.clear(); + throw error; + } finally { + releaseTransaction(); + } + }, + contributionDraft: { + async create(args: { data: Partial; include: unknown }) { + const contribution = createContributionRecord({ + id: `contribution-${contributions.length + 1}`, + proposalId: null, + status: ContributionStatus.DRAFT, + submittedAt: null, + ...args.data, + }); + contributions.push(contribution); + return includeContribution(contribution); + }, + async delete(args: { where: { id: string } }) { + const index = contributions.findIndex((contribution) => contribution.id === args.where.id); + const [deleted] = contributions.splice(index, 1); + return deleted; + }, + async deleteMany(args: { where: Partial }) { + if (submitBeforeNextDeleteMany) { + const contribution = contributions.find( + (candidate) => + candidate.id === args.where.id && candidate.authorId === args.where.authorId, + ); + + if (contribution) { + contribution.status = ContributionStatus.SUBMITTED; + contribution.submittedAt = now(); + externallySubmittedContributionIds.add(contribution.id); + } + + submitBeforeNextDeleteMany = false; + } + + const before = contributions.length; + + for (let index = contributions.length - 1; index >= 0; index -= 1) { + const contribution = contributions[index]!; + + if ( + Object.entries(args.where).every( + ([key, value]) => contribution[key as keyof StoredContribution] === value, + ) + ) { + contributions.splice(index, 1); + } + } + + return { count: before - contributions.length }; + }, + async findFirst(args: { where: Partial; include?: unknown }) { + const contribution = + contributions.find((candidate) => + Object.entries(args.where).every(([key, value]) => { + if (value && typeof value === 'object' && 'lt' in value) { + return String(candidate[key as keyof StoredContribution]) < String(value.lt); + } + + return candidate[key as keyof StoredContribution] === value; + }), + ) ?? null; + + return contribution ? includeContribution(contribution) : null; + }, + async findMany(args: { + where: Partial & { id?: { lt: string } }; + skip?: number; + take: number; + }) { + return contributions + .filter((candidate) => + Object.entries(args.where).every(([key, value]) => { + if (key === 'id' && value && typeof value === 'object' && 'lt' in value) { + return candidate.id < String(value.lt); + } + + return candidate[key as keyof StoredContribution] === value; + }), + ) + .sort((left, right) => { + const updatedAtOrder = right.updatedAt.getTime() - left.updatedAt.getTime(); + + if (updatedAtOrder !== 0) { + return updatedAtOrder; + } + + return right.id.localeCompare(left.id); + }) + .slice(args.skip ?? 0, (args.skip ?? 0) + args.take) + .map(includeContribution); + }, + async count(args: { where: Partial }) { + return contributions.filter((candidate) => + Object.entries(args.where).every( + ([key, value]) => candidate[key as keyof StoredContribution] === value, + ), + ).length; + }, + async update(args: { + data: Partial; + where: { id: string }; + include?: unknown; + }) { + const contribution = contributions.find((candidate) => candidate.id === args.where.id); + + if (!contribution) { + throw new Error('Contribution missing.'); + } + + if ('targetLoreEntry' in args.data) { + const relation = args.data.targetLoreEntry as + { connect: { id: string } } | { disconnect: true }; + contribution.targetLoreEntryId = 'disconnect' in relation ? null : relation.connect.id; + delete args.data.targetLoreEntry; + } + + Object.assign(contribution, args.data, { + updatedAt: now(), + }); + + return includeContribution(contribution); + }, + async updateMany(args: { + data: Partial; + where: Partial; + }) { + if (submitBeforeNextUpdateMany) { + const contribution = contributions.find( + (candidate) => + candidate.id === args.where.id && candidate.authorId === args.where.authorId, + ); + + if (contribution) { + contribution.status = ContributionStatus.SUBMITTED; + contribution.submittedAt = now(); + externallySubmittedContributionIds.add(contribution.id); + } + + submitBeforeNextUpdateMany = false; + } + + let count = 0; + + for (const contribution of contributions) { + if ( + Object.entries(args.where).every( + ([key, value]) => contribution[key as keyof StoredContribution] === value, + ) + ) { + Object.assign(contribution, args.data, { + updatedAt: now(), + }); + count += 1; + } + } + + return { count }; + }, + }, + loreEntry: { + async findUnique(args: { where: { id: string } }) { + return loreEntries.find((entry) => entry.id === args.where.id) ?? null; + }, + }, + proposal: { + async create(args: { data: Omit }) { + if (failNextProposalCreate) { + failNextProposalCreate = false; + throw new Error('Injected proposal create failure.'); + } + + const proposal: StoredProposal = { + ...args.data, + approvedAt: args.data.approvedAt ?? null, + createdAt: now(), + id: `proposal-${proposals.length + 1}`, + publishedAt: args.data.publishedAt ?? null, + rejectedAt: args.data.rejectedAt ?? null, + resultingBibleVersionId: args.data.resultingBibleVersionId ?? null, + resultingLoreEntryId: args.data.resultingLoreEntryId ?? null, + updatedAt: now(), + votingStartedAt: args.data.votingStartedAt ?? null, + }; + proposals.push(proposal); + return proposal; + }, + }, + refreshSession: { + async findUnique(args: { where: { id: string } }) { + if (!args.where.id.startsWith('session-')) { + return null; + } + const userId = args.where.id.replace(/^session-/, ''); + + return { + expiresAt: new Date(Date.now() + 60 * 60 * 1000), + revokedAt: null, + userId, + }; + }, + }, + world: { + async findUnique(args: { where: { id: string } }) { + return worlds.find((world) => world.id === args.where.id) ?? null; + }, + }, + worldBibleVersion: { + async findFirst(args: { where: { worldId: string } }) { + if (!worlds.some((world) => world.id === args.where.worldId)) { + return null; + } + + return { + id: `bible-${args.where.worldId}`, + }; + }, + }, + worldAuditLog: { + async create(args: { data: unknown }) { + if (failNextAuditCreate) { + failNextAuditCreate = false; + throw new Error('Injected audit failure.'); + } + + auditLogs.push(args.data); + return args.data; + }, + }, + worldMembership: { + async findUnique(args: { + where: { worldId_userId: { worldId: string; userId: string }; revokedAt: null }; + }) { + return ( + memberships.find( + (membership) => + membership.worldId === args.where.worldId_userId.worldId && + membership.userId === args.where.worldId_userId.userId && + !membership.revokedAt, + ) ?? null + ); + }, + }, + }); + + return { + auditLogs, + contributions, + database, + failNextProposalCreate() { + failNextProposalCreate = true; + }, + failNextAuditCreate() { + failNextAuditCreate = true; + }, + loreEntries, + memberships, + proposals, + submitBeforeNextDeleteMany() { + submitBeforeNextDeleteMany = true; + }, + submitBeforeNextUpdateMany() { + submitBeforeNextUpdateMany = true; + }, + }; +} + +async function createApp(database: ReturnType['database']) { + const app = Fastify(); + await registerContributionRoutes(app, { + database: database as never, + }); + return app; +} + +describe('contribution routes', () => { + test('authenticated contributor can create lore and story drafts with session-derived author', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + + const loreResponse = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + content: structuredDoc, + kind: ContributionKind.LORE, + targetLoreEntryId: 'lore-1', + title: ' The Fall of the Northern Gate ', + }, + url: '/worlds/world-1/contributions', + }); + const storyResponse = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + content: structuredDoc, + kind: ContributionKind.STORY, + title: 'A Winter Road', + }, + url: '/worlds/world-1/contributions', + }); + const protectedFieldResponse = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + authorId: otherUser.id, + content: structuredDoc, + kind: ContributionKind.STORY, + proposalId: 'proposal-injected', + title: 'A Winter Road', + }, + url: '/worlds/world-1/contributions', + }); + + assert.equal(loreResponse.statusCode, 201); + assert.equal(loreResponse.json().contribution.authorId, author.id); + assert.equal(loreResponse.json().contribution.title, 'The Fall of the Northern Gate'); + assert.equal(storyResponse.statusCode, 201); + assert.equal(storyResponse.json().contribution.kind, ContributionKind.STORY); + assert.equal(protectedFieldResponse.statusCode, 400); + assert.equal(state.contributions.length, 2); + await app.close(); + }); + + test('rejects unauthenticated users, users without world permission, invalid docs, oversized docs, missing content, missing worlds, and mismatched targets', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + const oversizedDoc = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'x'.repeat(101 * 1024) }], + }, + ], + }; + + const unauthenticated = await app.inject({ + method: 'POST', + payload: { content: structuredDoc, kind: ContributionKind.LORE, title: 'Gate' }, + url: '/worlds/world-1/contributions', + }); + const forbidden = await app.inject({ + headers: authHeader(otherUser), + method: 'POST', + payload: { content: structuredDoc, kind: ContributionKind.LORE, title: 'Gate' }, + url: '/worlds/world-1/contributions', + }); + const invalidDoc = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + content: { type: 'html', content: '

Nope

' }, + kind: ContributionKind.LORE, + title: 'Gate', + }, + url: '/worlds/world-1/contributions', + }); + const oversized = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + content: oversizedDoc, + kind: ContributionKind.LORE, + title: 'Gate', + }, + url: '/worlds/world-1/contributions', + }); + const missingContent = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + kind: ContributionKind.LORE, + title: 'Gate', + }, + url: '/worlds/world-1/contributions', + }); + const missingWorld = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + content: structuredDoc, + kind: ContributionKind.LORE, + title: 'Gate', + }, + url: '/worlds/world-missing/contributions', + }); + const mismatchedTarget = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + content: structuredDoc, + kind: ContributionKind.LORE, + targetLoreEntryId: 'lore-2', + title: 'Gate', + }, + url: '/worlds/world-1/contributions', + }); + + assert.equal(unauthenticated.statusCode, 401); + assert.equal(forbidden.statusCode, 403); + assert.equal(invalidDoc.statusCode, 400); + assert.equal(oversized.statusCode, 400); + assert.equal(missingContent.statusCode, 400); + assert.equal(missingWorld.statusCode, 404); + assert.equal(mismatchedTarget.statusCode, 400); + await app.close(); + }); + + test('author can list and read their draft while unauthorized routes do not reveal private data', async () => { + const state = createDatabase(); + state.memberships.find((membership) => membership.userId === otherUser.id)!.role = + WorldRole.CONTRIBUTOR; + state.memberships.push({ + id: 'membership-author-world-2', + revokedAt: null, + role: WorldRole.CONTRIBUTOR, + userId: author.id, + worldId: 'world-2', + }); + state.contributions.push(createContributionRecord({ id: 'draft-1' })); + state.contributions.push(createContributionRecord({ authorId: otherUser.id, id: 'draft-2' })); + const app = await createApp(state.database); + + const listResponse = await app.inject({ + headers: authHeader(), + method: 'GET', + url: '/worlds/world-1/contributions?status=DRAFT&kind=LORE&page=1&pageSize=1', + }); + const readResponse = await app.inject({ + headers: authHeader(), + method: 'GET', + url: '/worlds/world-1/contributions/draft-1', + }); + const otherReadResponse = await app.inject({ + headers: authHeader(otherUser), + method: 'GET', + url: '/worlds/world-1/contributions/draft-1', + }); + const wrongWorldResponse = await app.inject({ + headers: authHeader(), + method: 'GET', + url: '/worlds/world-2/contributions/draft-1', + }); + + assert.equal(listResponse.statusCode, 200); + assert.deepEqual(listResponse.json().pagination, { + page: 1, + pageSize: 1, + total: 1, + }); + assert.deepEqual( + listResponse.json().contributions.map((contribution: { id: string }) => contribution.id), + ['draft-1'], + ); + assert.equal(readResponse.statusCode, 200); + assert.equal(otherReadResponse.statusCode, 404); + assert.equal(wrongWorldResponse.statusCode, 404); + await app.close(); + }); + + test('author can update and delete draft, but protected fields and submitted rows are rejected', async () => { + const state = createDatabase(); + state.contributions.push(createContributionRecord({ id: 'draft-1' })); + state.contributions.push( + createContributionRecord({ + id: 'submitted-1', + proposalId: 'proposal-1', + status: ContributionStatus.SUBMITTED, + submittedAt: now(), + }), + ); + const app = await createApp(state.database); + + const updateResponse = await app.inject({ + headers: authHeader(), + method: 'PATCH', + payload: { + content: structuredDoc, + summary: 'Updated.', + targetLoreEntryId: null, + title: 'Updated Gate', + }, + url: '/worlds/world-1/contributions/draft-1', + }); + const protectedFieldResponse = await app.inject({ + headers: authHeader(), + method: 'PATCH', + payload: { + authorId: otherUser.id, + title: 'No', + }, + url: '/worlds/world-1/contributions/draft-1', + }); + const submittedUpdateResponse = await app.inject({ + headers: authHeader(), + method: 'PATCH', + payload: { title: 'No' }, + url: '/worlds/world-1/contributions/submitted-1', + }); + const invalidContentResponse = await app.inject({ + headers: authHeader(), + method: 'PATCH', + payload: { content: { type: 'doc', content: {} } }, + url: '/worlds/world-1/contributions/draft-1', + }); + const deleteResponse = await app.inject({ + headers: authHeader(), + method: 'DELETE', + url: '/worlds/world-1/contributions/draft-1', + }); + const submittedDeleteResponse = await app.inject({ + headers: authHeader(), + method: 'DELETE', + url: '/worlds/world-1/contributions/submitted-1', + }); + + assert.equal(updateResponse.statusCode, 200); + assert.equal(updateResponse.json().contribution.title, 'Updated Gate'); + assert.equal(updateResponse.json().contribution.targetLoreEntryId, null); + assert.equal(protectedFieldResponse.statusCode, 400); + assert.equal(submittedUpdateResponse.statusCode, 409); + assert.equal(invalidContentResponse.statusCode, 400); + assert.equal(deleteResponse.statusCode, 204); + assert.equal(submittedDeleteResponse.statusCode, 409); + await app.close(); + }); + + test('update and delete reject drafts that are submitted by a concurrent operation', async () => { + const updateState = createDatabase(); + updateState.contributions.push(createContributionRecord({ id: 'draft-update-race' })); + updateState.submitBeforeNextUpdateMany(); + + await assert.rejects( + updateContribution(updateState.database as never, { + authorId: author.id, + contributionId: 'draft-update-race', + title: 'Should Not Land', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof Error && error.message === 'Submitted contributions cannot be edited.', + ); + + assert.equal(updateState.contributions[0]?.title, 'The Fall of the Northern Gate'); + assert.equal(updateState.contributions[0]?.status, ContributionStatus.SUBMITTED); + + const deleteState = createDatabase(); + deleteState.contributions.push(createContributionRecord({ id: 'draft-delete-race' })); + deleteState.submitBeforeNextDeleteMany(); + + await assert.rejects( + deleteContribution(deleteState.database as never, { + authorId: author.id, + contributionId: 'draft-delete-race', + worldId: 'world-1', + }), + (error: unknown) => + error instanceof Error && error.message === 'Submitted contributions cannot be deleted.', + ); + + assert.equal(deleteState.contributions.length, 1); + assert.equal(deleteState.contributions[0]?.status, ContributionStatus.SUBMITTED); + }); + + test('another user cannot update or delete an author private draft', async () => { + const state = createDatabase(); + state.memberships.find((membership) => membership.userId === otherUser.id)!.role = + WorldRole.CONTRIBUTOR; + state.contributions.push(createContributionRecord({ id: 'draft-1' })); + const app = await createApp(state.database); + + const updateResponse = await app.inject({ + headers: authHeader(otherUser), + method: 'PATCH', + payload: { title: 'No' }, + url: '/worlds/world-1/contributions/draft-1', + }); + const deleteResponse = await app.inject({ + headers: authHeader(otherUser), + method: 'DELETE', + url: '/worlds/world-1/contributions/draft-1', + }); + + assert.equal(updateResponse.statusCode, 404); + assert.equal(deleteResponse.statusCode, 404); + await app.close(); + }); + + test('valid draft submission creates exactly one proposal and locks immutable proposed content', async () => { + const state = createDatabase(); + state.contributions.push(createContributionRecord({ id: 'draft-1' })); + const app = await createApp(state.database); + + const submitResponse = await app.inject({ + headers: authHeader(), + method: 'POST', + url: '/worlds/world-1/contributions/draft-1/submit', + }); + const duplicateResponse = await app.inject({ + headers: authHeader(), + method: 'POST', + url: '/worlds/world-1/contributions/draft-1/submit', + }); + + assert.equal(submitResponse.statusCode, 201); + assert.equal(duplicateResponse.statusCode, 200); + assert.equal(state.proposals.length, 1); + assert.equal(state.contributions[0]?.status, ContributionStatus.SUBMITTED); + assert.equal(state.contributions[0]?.proposalId, 'proposal-1'); + assert.equal(submitResponse.json().proposal.authorId, author.id); + assert.equal(submitResponse.json().proposal.status, ProposalStatus.VOTING); + assert.equal(submitResponse.json().proposal.proposalType, ProposalType.UPDATE_LORE); + assert.deepEqual(submitResponse.json().proposal.proposedContent, structuredDoc); + assert.equal( + state.auditLogs.some( + (entry) => + (entry as { action?: WorldAuditAction }).action === + WorldAuditAction.CONTRIBUTION_SUBMITTED, + ), + true, + ); + await app.close(); + }); + + test('create rollback leaves no contribution when audit logging fails', async () => { + const state = createDatabase(); + state.failNextAuditCreate(); + + await assert.rejects( + createContribution(state.database as never, { + authorId: author.id, + content: structuredDoc, + kind: ContributionKind.LORE, + title: 'Rollback Draft', + worldId: 'world-1', + }), + ); + + assert.equal(state.contributions.length, 0); + assert.equal(state.auditLogs.length, 0); + }); + + test('story draft submission creates an ADD_STORY proposal', async () => { + const state = createDatabase(); + state.contributions.push( + createContributionRecord({ + id: 'story-1', + kind: ContributionKind.STORY, + targetLoreEntryId: null, + }), + ); + const app = await createApp(state.database); + + const response = await app.inject({ + headers: authHeader(), + method: 'POST', + url: '/worlds/world-1/contributions/story-1/submit', + }); + + assert.equal(response.statusCode, 201); + assert.equal(response.json().proposal.proposalType, ProposalType.ADD_STORY); + assert.equal(response.json().proposal.contributionKind, ContributionKind.STORY); + await app.close(); + }); + + test('submission rejects empty content, missing submit permission, and mismatched target lore', async () => { + const state = createDatabase(); + state.contributions.push(createContributionRecord({ content: emptyDoc, id: 'empty-1' })); + state.contributions.push( + createContributionRecord({ id: 'mismatch-1', targetLoreEntryId: 'lore-2' }), + ); + const app = await createApp(state.database); + + const emptyResponse = await app.inject({ + headers: authHeader(), + method: 'POST', + url: '/worlds/world-1/contributions/empty-1/submit', + }); + const forbiddenResponse = await app.inject({ + headers: authHeader(otherUser), + method: 'POST', + url: '/worlds/world-1/contributions/empty-1/submit', + }); + const mismatchResponse = await app.inject({ + headers: authHeader(), + method: 'POST', + url: '/worlds/world-1/contributions/mismatch-1/submit', + }); + + assert.equal(emptyResponse.statusCode, 400); + assert.equal(forbiddenResponse.statusCode, 403); + assert.equal(mismatchResponse.statusCode, 400); + assert.equal(state.proposals.length, 0); + await app.close(); + }); + + test('concurrent submissions and rollback do not create duplicate or partial proposal state', async () => { + const concurrentState = createDatabase(); + concurrentState.contributions.push(createContributionRecord({ id: 'draft-1' })); + const [first, second] = await Promise.allSettled([ + submitContribution(concurrentState.database as never, { + authorId: author.id, + contributionId: 'draft-1', + worldId: 'world-1', + }), + submitContribution(concurrentState.database as never, { + authorId: author.id, + contributionId: 'draft-1', + worldId: 'world-1', + }), + ]); + + assert.equal(concurrentState.proposals.length, 1); + assert.equal( + [first, second].filter((result) => result.status === 'fulfilled').length >= 1, + true, + ); + + const rollbackState = createDatabase(); + rollbackState.contributions.push(createContributionRecord({ id: 'draft-rollback' })); + rollbackState.failNextProposalCreate(); + + await assert.rejects( + submitContribution(rollbackState.database as never, { + authorId: author.id, + contributionId: 'draft-rollback', + worldId: 'world-1', + }), + ); + + assert.equal(rollbackState.proposals.length, 0); + assert.equal(rollbackState.contributions[0]?.status, ContributionStatus.DRAFT); + assert.equal(rollbackState.contributions[0]?.proposalId, null); + }); +}); diff --git a/apps/api/src/routes/contributions.ts b/apps/api/src/routes/contributions.ts new file mode 100644 index 0000000..dc1cab1 --- /dev/null +++ b/apps/api/src/routes/contributions.ts @@ -0,0 +1,432 @@ +import type { FastifyInstance, FastifyReply } from 'fastify'; +import { z } from 'zod'; + +import { env } from '../config/env.js'; +import { ContributionKind, ContributionStatus } from '../generated/prisma/enums.js'; +import { requireSession } from '../lib/auth-middleware.js'; +import type { SessionVerificationDatabase } from '../lib/auth-sessions.js'; +import { + ContributionError, + createContribution, + deleteContribution, + getOwnedContribution, + listOwnedContributions, + submitContribution, + updateContribution, + type ContributionDatabase, +} from '../lib/contributions.js'; +import { prisma } from '../lib/prisma.js'; +import { authorizeWorldPermission } from '../lib/world-authorization.js'; +import { WORLD_PERMISSIONS } from '../lib/world-permissions.js'; +import type { WorldMembershipLookup } from '../lib/world-authorization.js'; + +const routeParamsSchema = z.object({ + contributionId: z.string().min(1).optional(), + worldId: z.string().min(1), +}); + +const contributionKindSchema = z.enum([ContributionKind.LORE, ContributionKind.STORY]); +const contributionStatusSchema = z.enum([ContributionStatus.DRAFT, ContributionStatus.SUBMITTED]); + +const createContributionBodySchema = z + .object({ + content: z.unknown(), + kind: contributionKindSchema, + summary: z.string().trim().max(1_000).optional(), + targetLoreEntryId: z.string().trim().min(1).optional(), + title: z.string().trim().min(1).max(200), + }) + .strict(); + +const updateContributionBodySchema = z + .object({ + content: z.unknown().optional(), + kind: contributionKindSchema.optional(), + summary: z.string().trim().max(1_000).nullable().optional(), + targetLoreEntryId: z.string().trim().min(1).nullable().optional(), + title: z.string().trim().min(1).max(200).optional(), + }) + .strict() + .refine((value) => Object.keys(value).length > 0, { + message: 'At least one editable contribution field is required.', + }); + +const listContributionsQuerySchema = z.object({ + kind: contributionKindSchema.optional(), + page: z.coerce.number().int().positive().default(1), + pageSize: z.coerce.number().int().positive().max(100).default(20), + status: contributionStatusSchema.optional(), +}); + +type RegisterContributionRoutesOptions = { + database?: ContributionDatabase & WorldMembershipLookup & SessionVerificationDatabase; +}; + +function authOptions(database: SessionVerificationDatabase) { + return { + audience: env.AUTH_JWT_AUDIENCE, + database, + issuer: env.AUTH_JWT_ISSUER, + jwtSecret: env.AUTH_JWT_SECRET, + }; +} + +function handleContributionError(error: unknown, reply: FastifyReply) { + if (error instanceof ContributionError) { + return reply.code(error.statusCode).send({ + error: error.message, + }); + } + + throw error; +} + +async function ensureWorldExists( + database: Pick, + worldId: string, + reply: FastifyReply, +) { + const world = await database.world.findUnique({ + select: { + id: true, + }, + where: { + id: worldId, + }, + }); + + if (!world) { + await reply.code(404).send({ + error: 'World not found.', + }); + + return false; + } + + return true; +} + +export async function registerContributionRoutes( + app: FastifyInstance, + options: RegisterContributionRoutesOptions = {}, +) { + const database = options.database ?? prisma; + + app.post( + '/worlds/:worldId/contributions', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = routeParamsSchema.safeParse(request.params); + const body = createContributionBodySchema.safeParse(request.body); + + if (!params.success || !body.success) { + return reply.code(400).send({ + error: 'Invalid contribution payload.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists) { + return; + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.CREATE_LORE_DRAFT, + database, + ); + + if (!authorized) { + return; + } + + if (!request.user) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + try { + const contribution = await createContribution(database, { + ...body.data, + authorId: request.user.id, + worldId: params.data.worldId, + }); + + return reply.code(201).send({ + contribution, + }); + } catch (error) { + return handleContributionError(error, reply); + } + }, + ); + + app.get( + '/worlds/:worldId/contributions', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = routeParamsSchema.safeParse(request.params); + const query = listContributionsQuerySchema.safeParse(request.query); + + if (!params.success || !query.success) { + return reply.code(400).send({ + error: 'Invalid contributions query.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists) { + return; + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.CREATE_LORE_DRAFT, + database, + ); + + if (!authorized) { + return; + } + + if (!request.user) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + return listOwnedContributions(database, { + ...query.data, + authorId: request.user.id, + worldId: params.data.worldId, + }); + }, + ); + + app.get( + '/worlds/:worldId/contributions/:contributionId', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = routeParamsSchema.required().safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + error: 'Invalid contribution route.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists) { + return; + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.CREATE_LORE_DRAFT, + database, + ); + + if (!authorized) { + return; + } + + if (!request.user) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + const contribution = await getOwnedContribution(database, { + authorId: request.user.id, + contributionId: params.data.contributionId, + worldId: params.data.worldId, + }); + + if (!contribution) { + return reply.code(404).send({ + error: 'Contribution not found.', + }); + } + + return { + contribution, + }; + }, + ); + + app.patch( + '/worlds/:worldId/contributions/:contributionId', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = routeParamsSchema.required().safeParse(request.params); + const body = updateContributionBodySchema.safeParse(request.body); + + if (!params.success || !body.success) { + return reply.code(400).send({ + error: 'Invalid contribution payload.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists) { + return; + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.EDIT_OWN_DRAFT, + database, + ); + + if (!authorized) { + return; + } + + if (!request.user) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + try { + const contribution = await updateContribution(database, { + ...body.data, + authorId: request.user.id, + contributionId: params.data.contributionId, + worldId: params.data.worldId, + }); + + return { + contribution, + }; + } catch (error) { + return handleContributionError(error, reply); + } + }, + ); + + app.delete( + '/worlds/:worldId/contributions/:contributionId', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = routeParamsSchema.required().safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + error: 'Invalid contribution route.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists) { + return; + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.EDIT_OWN_DRAFT, + database, + ); + + if (!authorized) { + return; + } + + if (!request.user) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + try { + await deleteContribution(database, { + authorId: request.user.id, + contributionId: params.data.contributionId, + worldId: params.data.worldId, + }); + + return reply.code(204).send(); + } catch (error) { + return handleContributionError(error, reply); + } + }, + ); + + app.post( + '/worlds/:worldId/contributions/:contributionId/submit', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = routeParamsSchema.required().safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + error: 'Invalid contribution route.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists) { + return; + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.SUBMIT_PROPOSAL, + database, + ); + + if (!authorized) { + return; + } + + if (!request.user) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + try { + const result = await submitContribution(database, { + authorId: request.user.id, + contributionId: params.data.contributionId, + worldId: params.data.worldId, + }); + + return reply.code(result.alreadySubmitted ? 200 : 201).send(result); + } catch (error) { + return handleContributionError(error, reply); + } + }, + ); +} diff --git a/apps/api/src/routes/health.test.ts b/apps/api/src/routes/health.test.ts new file mode 100644 index 0000000..1197a32 --- /dev/null +++ b/apps/api/src/routes/health.test.ts @@ -0,0 +1,144 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import Fastify from 'fastify'; + +import { registerHealthRoute } from './health.js'; +import { testDatabaseAdminUrl, withDisposablePrismaDatabase } from '../test/integration-db.js'; + +function createHealthDatabase(input: { + failDatabase?: boolean; + lastProcessedBlock?: bigint; + lastProcessedOperationIndex?: number; +}) { + return { + async $queryRaw() { + if (input.failDatabase) { + throw new Error('database unavailable'); + } + + return [{ ok: 1 }]; + }, + indexerWatermark: { + async findUnique() { + return { + lastProcessedBlock: input.lastProcessedBlock ?? 100n, + lastProcessedOperationIndex: input.lastProcessedOperationIndex ?? 2, + lastRunFinishedAt: new Date('2026-09-05T12:02:00.000Z'), + lastRunStartedAt: new Date('2026-09-05T12:00:00.000Z'), + }; + }, + }, + }; +} + +async function createApp(options: Parameters[1]) { + const app = Fastify(); + await registerHealthRoute(app, options); + return app; +} + +describe('health routes', () => { + test('health is a lightweight liveness check', async () => { + const app = await createApp({ + database: createHealthDatabase({ failDatabase: true }) as never, + getHeadBlock: async () => { + throw new Error('head lookup should not run'); + }, + }); + + const response = await app.inject({ + method: 'GET', + url: '/health', + }); + + assert.equal(response.statusCode, 200); + assert.deepEqual(response.json(), { + service: 'hivelore-api', + status: 'ok', + }); + await app.close(); + }); + + test('ready reports database connectivity and indexer lag', async () => { + const app = await createApp({ + database: createHealthDatabase({ + lastProcessedBlock: 100n, + lastProcessedOperationIndex: 3, + }) as never, + getHeadBlock: async () => 105, + indexerLagThresholdBlocks: 10, + indexerName: 'hivelore-haf', + }); + + const response = await app.inject({ + method: 'GET', + url: '/ready', + }); + + assert.equal(response.statusCode, 200); + assert.equal(response.json().status, 'ok'); + assert.equal(response.json().checks.database.status, 'ok'); + assert.equal(response.json().checks.indexer.status, 'ok'); + assert.equal(response.json().checks.indexer.lagBlocks, 5); + assert.equal(response.json().checks.indexer.lastProcessedOperationIndex, 3); + await app.close(); + }); + + test('ready returns degraded when dependencies fail or lag exceeds the threshold', async () => { + const app = await createApp({ + database: createHealthDatabase({ + failDatabase: true, + lastProcessedBlock: 50n, + }) as never, + getHeadBlock: async () => 105, + indexerLagThresholdBlocks: 10, + }); + + const response = await app.inject({ + method: 'GET', + url: '/ready', + }); + + assert.equal(response.statusCode, 503); + assert.equal(response.json().status, 'degraded'); + assert.equal(response.json().checks.database.status, 'degraded'); + assert.equal(response.json().checks.indexer.status, 'degraded'); + assert.equal(response.json().checks.indexer.lagBlocks, 55); + await app.close(); + }); + + test( + 'ready succeeds against a migrated PostgreSQL test database', + { skip: !testDatabaseAdminUrl ? 'TEST_DATABASE_ADMIN_URL is not configured.' : false }, + async () => { + await withDisposablePrismaDatabase('hivelore_health_ready', async (database) => { + await database.indexerWatermark.create({ + data: { + lastProcessedBlock: 90n, + lastProcessedOperationIndex: 4, + lastRunFinishedAt: new Date('2026-09-05T12:01:00.000Z'), + lastRunStartedAt: new Date('2026-09-05T12:00:00.000Z'), + name: 'hivelore-haf', + }, + }); + + const app = await createApp({ + database: database as never, + getHeadBlock: async () => 100, + indexerLagThresholdBlocks: 10, + indexerName: 'hivelore-haf', + }); + const response = await app.inject({ + method: 'GET', + url: '/ready', + }); + + assert.equal(response.statusCode, 200, response.body); + assert.equal(response.json().checks.database.status, 'ok'); + assert.equal(response.json().checks.indexer.lagBlocks, 10); + await app.close(); + }); + }, + ); +}); diff --git a/apps/api/src/routes/health.ts b/apps/api/src/routes/health.ts index 301cb7e..53edfac 100644 --- a/apps/api/src/routes/health.ts +++ b/apps/api/src/routes/health.ts @@ -1,10 +1,134 @@ import type { FastifyInstance } from 'fastify'; -export async function registerHealthRoute(app: FastifyInstance) { +import { env } from '../config/env.js'; +import { prisma } from '../lib/prisma.js'; + +type HealthDatabase = { + $queryRaw(query: TemplateStringsArray, ...values: unknown[]): Promise; + indexerWatermark: { + findUnique(args: { + where: { + name: string; + }; + select: { + lastProcessedBlock: true; + lastProcessedOperationIndex: true; + lastRunFinishedAt: true; + lastRunStartedAt: true; + }; + }): Promise<{ + lastProcessedBlock: bigint; + lastProcessedOperationIndex: number; + lastRunFinishedAt: Date | null; + lastRunStartedAt: Date | null; + } | null>; + }; +}; + +type RegisterHealthRouteOptions = { + database?: HealthDatabase; + getHeadBlock?: () => Promise; + indexerLagThresholdBlocks?: number; + indexerName?: string; +}; + +type CheckStatus = 'ok' | 'degraded'; + +async function checkDatabase(database: HealthDatabase) { + await database.$queryRaw`SELECT 1`; + + return { + status: 'ok' as CheckStatus, + }; +} + +async function checkIndexer( + database: HealthDatabase, + getHeadBlock: () => Promise, + input: { + indexerLagThresholdBlocks: number; + indexerName: string; + }, +) { + const [headBlock, watermark] = await Promise.all([ + getHeadBlock(), + database.indexerWatermark.findUnique({ + select: { + lastProcessedBlock: true, + lastProcessedOperationIndex: true, + lastRunFinishedAt: true, + lastRunStartedAt: true, + }, + where: { + name: input.indexerName, + }, + }), + ]); + const lastProcessedBlock = Number(watermark?.lastProcessedBlock ?? 0n); + const lagBlocks = Math.max(headBlock - lastProcessedBlock, 0); + + return { + headBlock, + lagBlocks, + lastProcessedBlock, + lastProcessedOperationIndex: watermark?.lastProcessedOperationIndex ?? -1, + lastRunFinishedAt: watermark?.lastRunFinishedAt?.toISOString() ?? null, + lastRunStartedAt: watermark?.lastRunStartedAt?.toISOString() ?? null, + status: lagBlocks <= input.indexerLagThresholdBlocks ? ('ok' as CheckStatus) : 'degraded', + thresholdBlocks: input.indexerLagThresholdBlocks, + }; +} + +export async function registerHealthRoute( + app: FastifyInstance, + options: RegisterHealthRouteOptions = {}, +) { + const database = options.database ?? prisma; + const getHeadBlock = options.getHeadBlock ?? (() => Promise.resolve(0)); + const indexerName = options.indexerName ?? env.INDEXER_NAME; + const indexerLagThresholdBlocks = + options.indexerLagThresholdBlocks ?? env.INDEXER_MAX_READY_LAG_BLOCKS; + app.get('/health', async () => { return { status: 'ok', service: 'hivelore-api', }; }); + + app.get('/ready', async (_request, reply) => { + const checks: { + database?: Awaited> | { status: 'degraded'; error: string }; + indexer?: Awaited> | { status: 'degraded'; error: string }; + } = {}; + + try { + checks.database = await checkDatabase(database); + } catch (error) { + checks.database = { + error: error instanceof Error ? error.message : 'Database readiness check failed.', + status: 'degraded', + }; + } + + try { + checks.indexer = await checkIndexer(database, getHeadBlock, { + indexerLagThresholdBlocks, + indexerName, + }); + } catch (error) { + checks.indexer = { + error: error instanceof Error ? error.message : 'Indexer readiness check failed.', + status: 'degraded', + }; + } + + const ready = Object.values(checks).every((check) => check?.status === 'ok'); + + return reply.code(ready ? 200 : 503).send({ + checks, + service: 'hivelore-api', + status: ready ? 'ok' : 'degraded', + }); + }); } diff --git a/apps/api/src/routes/lore.test.ts b/apps/api/src/routes/lore.test.ts new file mode 100644 index 0000000..4180f1c --- /dev/null +++ b/apps/api/src/routes/lore.test.ts @@ -0,0 +1,1253 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import Fastify from 'fastify'; + +import { env } from '../config/env.js'; +import { LoreStatus, LoreType, PlatformRole, WorldRole } from '../generated/prisma/enums.js'; +import { signAccessToken } from '../lib/auth-crypto.js'; +import { registerLoreRoutes } from './lore.js'; + +const author = { + hiveUsername: 'mira-vale.dev', + id: 'user-author', + normalizedHiveUsername: 'mira-vale.dev', +}; + +const otherUser = { + hiveUsername: 'emberquill.dev', + id: 'user-other', + normalizedHiveUsername: 'emberquill.dev', +}; + +const curator = { + hiveUsername: 'curator.dev', + id: 'user-curator', + normalizedHiveUsername: 'curator.dev', +}; + +function authHeader(user = author) { + const token = signAccessToken( + { + hiveUsername: user.hiveUsername, + normalizedHiveUsername: user.normalizedHiveUsername, + platformRole: PlatformRole.USER, + sid: `session-${user.id}`, + sub: user.id, + }, + { + audience: env.AUTH_JWT_AUDIENCE, + issuer: env.AUTH_JWT_ISSUER, + secret: env.AUTH_JWT_SECRET, + ttlSeconds: 900, + }, + ); + + return { + authorization: `Bearer ${token}`, + }; +} + +function now() { + return new Date('2026-08-08T12:00:00.000Z'); +} + +type StoredLoreEntry = { + id: string; + worldId: string; + authorId: string; + title: string; + slug: string; + loreType: LoreType; + content: unknown; + status: LoreStatus; + publishedAt: Date | null; + hiveReferenceId: string | null; + createdAt: Date; + updatedAt: Date; +}; + +type StoredLoreRelationship = { + id: string; + worldId: string; + sourceId: string; + targetId: string; + relationType: string; + metadata: unknown; + createdAt: Date; + updatedAt: Date; +}; + +function createLoreRecord(input: Partial = {}): StoredLoreEntry { + return { + authorId: author.id, + content: { + body: 'A safe body.', + summary: 'A short summary.', + }, + createdAt: now(), + hiveReferenceId: null, + id: `lore-${Math.random().toString(36).slice(2)}`, + loreType: LoreType.CHARACTER, + publishedAt: null, + slug: 'safe-body', + status: LoreStatus.DRAFT, + title: 'Safe Body', + updatedAt: now(), + worldId: 'world-1', + ...input, + }; +} + +function createDatabase() { + const worlds = [{ id: 'world-1' }, { id: 'world-2' }]; + const users = [author, otherUser, curator]; + const loreEntries: StoredLoreEntry[] = []; + const loreRelationships: StoredLoreRelationship[] = []; + const searchIndexes: unknown[] = []; + const worldAuditLogs: unknown[] = []; + const memberships = [ + { + id: 'membership-author', + revokedAt: null, + role: WorldRole.CONTRIBUTOR, + userId: author.id, + worldId: 'world-1', + }, + { + id: 'membership-other', + revokedAt: null, + role: WorldRole.READER, + userId: otherUser.id, + worldId: 'world-1', + }, + { + id: 'membership-curator', + revokedAt: null, + role: WorldRole.CURATOR, + userId: curator.id, + worldId: 'world-1', + }, + ]; + + function includeLore(entry: StoredLoreEntry) { + const user = users.find((candidate) => candidate.id === entry.authorId) ?? author; + const selectRelatedEntry = (entryId: string) => + loreEntries.find((candidate) => candidate.id === entryId)!; + + return { + ...entry, + author: { + avatarUrl: null, + displayName: null, + hiveUsername: user.hiveUsername, + id: user.id, + }, + incomingRelations: loreRelationships + .filter((relationship) => relationship.targetId === entry.id) + .map((relationship) => ({ + id: relationship.id, + relationType: relationship.relationType, + source: includeRelatedEntry(selectRelatedEntry(relationship.sourceId)), + })), + outgoingRelations: loreRelationships + .filter((relationship) => relationship.sourceId === entry.id) + .map((relationship) => ({ + id: relationship.id, + relationType: relationship.relationType, + target: includeRelatedEntry(selectRelatedEntry(relationship.targetId)), + })), + }; + } + + function includeRelatedEntry(entry: StoredLoreEntry) { + return { + authorId: entry.authorId, + id: entry.id, + loreType: entry.loreType, + slug: entry.slug, + status: entry.status, + title: entry.title, + }; + } + + function matchesWhere(entry: StoredLoreEntry, where: Record): boolean { + return Object.entries(where).every(([key, value]) => { + if (key === 'OR' && Array.isArray(value)) { + return value.some((condition): boolean => + matchesWhere(entry, condition as Record), + ); + } + + if (key === 'title' && value && typeof value === 'object' && 'contains' in value) { + return entry.title + .toLowerCase() + .includes(String((value as { contains: string }).contains).toLowerCase()); + } + + return entry[key as keyof StoredLoreEntry] === value; + }); + } + + const database = { + async $transaction(callback: (transaction: unknown) => Promise, options?: unknown) { + void options; + return callback(database); + }, + loreEntry: { + async count(args: { where: Record }) { + return loreEntries.filter((entry) => matchesWhere(entry, args.where)).length; + }, + async create(args: { data: Partial }) { + const entry = createLoreRecord({ + id: `lore-${loreEntries.length + 1}`, + ...args.data, + }); + loreEntries.push(entry); + return includeLore(entry); + }, + async delete(args: { where: { id: string } }) { + const index = loreEntries.findIndex((entry) => entry.id === args.where.id); + const [deleted] = loreEntries.splice(index, 1); + return deleted; + }, + async findFirst(args: { where: Record }) { + const entry = loreEntries.find((candidate) => matchesWhere(candidate, args.where)) ?? null; + return entry ? includeLore(entry) : null; + }, + async findUnique(args: { where: { id: string } }) { + const entry = loreEntries.find((candidate) => candidate.id === args.where.id) ?? null; + return entry ? includeLore(entry) : null; + }, + async findMany(args: { skip: number; take: number; where: Record }) { + return loreEntries + .filter((entry) => matchesWhere(entry, args.where)) + .sort((left, right) => right.updatedAt.getTime() - left.updatedAt.getTime()) + .slice(args.skip, args.skip + args.take) + .map(includeLore); + }, + async update(args: { data: Partial; where: { id: string } }) { + const entry = loreEntries.find((candidate) => candidate.id === args.where.id); + + if (!entry) { + throw new Error('Lore entry missing.'); + } + + Object.assign(entry, args.data, { + updatedAt: now(), + }); + + return includeLore(entry); + }, + }, + loreRelationship: { + async count(args: { where: Record }) { + return loreRelationships.filter((relationship) => + Object.entries(args.where).every(([key, value]) => { + if (key === 'OR' && Array.isArray(value)) { + return value.some((condition) => + Object.entries(condition as Record).every( + ([nestedKey, nestedValue]) => + relationship[nestedKey as keyof StoredLoreRelationship] === nestedValue, + ), + ); + } + + if (key === 'source' && value && typeof value === 'object' && 'authorId' in value) { + const source = loreEntries.find((entry) => entry.id === relationship.sourceId); + + return source?.authorId === (value as { authorId: string }).authorId; + } + + if (key === 'target' && value && typeof value === 'object' && 'authorId' in value) { + const target = loreEntries.find((entry) => entry.id === relationship.targetId); + const authorFilter = (value as { authorId: string | { not: string } }).authorId; + + if (typeof authorFilter === 'object' && 'not' in authorFilter) { + return target?.authorId !== authorFilter.not; + } + + return target?.authorId === authorFilter; + } + + return relationship[key as keyof StoredLoreRelationship] === value; + }), + ).length; + }, + async create(args: { data: Partial; select?: unknown }) { + if ( + loreRelationships.some( + (relationship) => + relationship.worldId === args.data.worldId && + relationship.sourceId === args.data.sourceId && + relationship.targetId === args.data.targetId && + relationship.relationType === args.data.relationType, + ) + ) { + throw Object.assign(new Error('Duplicate relationship.'), { code: 'P2002' }); + } + + const relationship: StoredLoreRelationship = { + createdAt: now(), + id: `relationship-${loreRelationships.length + 1}`, + metadata: null, + relationType: '', + sourceId: '', + targetId: '', + updatedAt: now(), + worldId: '', + ...args.data, + }; + loreRelationships.push(relationship); + + return { + id: relationship.id, + relationType: relationship.relationType, + target: includeRelatedEntry( + loreEntries.find((entry) => entry.id === relationship.targetId)!, + ), + }; + }, + async delete(args: { where: { id: string } }) { + const index = loreRelationships.findIndex( + (relationship) => relationship.id === args.where.id, + ); + const [deleted] = loreRelationships.splice(index, 1); + return deleted; + }, + async deleteMany(args: { where: { OR?: Array>; worldId: string } }) { + const before = loreRelationships.length; + for (let index = loreRelationships.length - 1; index >= 0; index -= 1) { + const relationship = loreRelationships[index]!; + const matchesWorld = relationship.worldId === args.where.worldId; + const matchesRelation = args.where.OR?.some((condition) => + Object.entries(condition).every( + ([key, value]) => relationship[key as keyof StoredLoreRelationship] === value, + ), + ); + + if (matchesWorld && matchesRelation) { + loreRelationships.splice(index, 1); + } + } + + return { count: before - loreRelationships.length }; + }, + async findFirst(args: { where: Record }) { + const relationship = + loreRelationships.find((candidate) => + Object.entries(args.where).every( + ([key, value]) => candidate[key as keyof StoredLoreRelationship] === value, + ), + ) ?? null; + + if (!relationship) { + return null; + } + + return { + ...relationship, + source: { + authorId: loreEntries.find((entry) => entry.id === relationship.sourceId)!.authorId, + status: loreEntries.find((entry) => entry.id === relationship.sourceId)!.status, + }, + target: { + status: loreEntries.find((entry) => entry.id === relationship.targetId)!.status, + }, + }; + }, + }, + searchIndex: { + async deleteMany(args: { where?: { entityId?: string; entityType?: string } } = {}) { + const before = searchIndexes.length; + + for (let index = searchIndexes.length - 1; index >= 0; index -= 1) { + const row = searchIndexes[index] as { entityId?: string; entityType?: string }; + const matchesEntity = !args.where?.entityId || row.entityId === args.where.entityId; + const matchesType = !args.where?.entityType || row.entityType === args.where.entityType; + + if (matchesEntity && matchesType) { + searchIndexes.splice(index, 1); + } + } + + return { count: before - searchIndexes.length }; + }, + async upsert(args: { + create: { entityId: string; entityType: string }; + update: Record; + where: { entityType_entityId: { entityId: string; entityType: string } }; + }) { + const existing = searchIndexes.find( + (row) => + (row as { entityId: string; entityType: string }).entityId === + args.where.entityType_entityId.entityId && + (row as { entityId: string; entityType: string }).entityType === + args.where.entityType_entityId.entityType, + ); + + if (existing) { + Object.assign(existing as Record, args.update); + return existing; + } + + searchIndexes.push(args.create); + return args.create; + }, + }, + refreshSession: { + async findUnique(args: { where: { id: string } }) { + const userId = args.where.id.replace(/^session-/, ''); + + return { + expiresAt: new Date(Date.now() + 60 * 60 * 1000), + revokedAt: null, + userId, + }; + }, + }, + world: { + async findUnique(args: { where: { id: string } }) { + return worlds.find((world) => world.id === args.where.id) ?? null; + }, + }, + worldAuditLog: { + async create(args: { data: unknown }) { + worldAuditLogs.push(args.data); + return args.data; + }, + }, + worldMembership: { + async findUnique(args: { + where: { worldId_userId: { worldId: string; userId: string }; revokedAt: null }; + }) { + return ( + memberships.find( + (membership) => + membership.worldId === args.where.worldId_userId.worldId && + membership.userId === args.where.worldId_userId.userId && + !membership.revokedAt, + ) ?? null + ); + }, + }, + }; + + return { + database, + loreEntries, + loreRelationships, + memberships, + worldAuditLogs, + }; +} + +async function createApp(database: ReturnType['database']) { + const app = Fastify(); + await registerLoreRoutes(app, { + database: database as never, + }); + return app; +} + +describe('lore routes', () => { + test('public list and read expose only published canon by default', async () => { + const state = createDatabase(); + state.loreEntries.push( + createLoreRecord({ + id: 'published-1', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + title: 'Published Canon', + }), + ); + state.loreEntries.push(createLoreRecord({ id: 'draft-1', title: 'Private Draft' })); + const app = await createApp(state.database); + + const listResponse = await app.inject({ + method: 'GET', + url: '/worlds/world-1/lore', + }); + const draftReadResponse = await app.inject({ + method: 'GET', + url: '/worlds/world-1/lore/draft-1', + }); + + assert.equal(listResponse.statusCode, 200); + assert.deepEqual( + listResponse.json().entries.map((entry: { id: string }) => entry.id), + ['published-1'], + ); + assert.equal(draftReadResponse.statusCode, 404); + await app.close(); + }); + + test('draft lists require auth and scope contributors to their own drafts', async () => { + const state = createDatabase(); + state.memberships.find((membership) => membership.userId === otherUser.id)!.role = + WorldRole.CONTRIBUTOR; + state.loreEntries.push(createLoreRecord({ id: 'own-draft' })); + state.loreEntries.push(createLoreRecord({ authorId: otherUser.id, id: 'other-draft' })); + state.loreRelationships.push({ + createdAt: now(), + id: 'relationship-private', + metadata: null, + relationType: 'knows', + sourceId: 'own-draft', + targetId: 'other-draft', + updatedAt: now(), + worldId: 'world-1', + }); + const app = await createApp(state.database); + + const anonymousResponse = await app.inject({ + method: 'GET', + url: '/worlds/world-1/lore?status=DRAFT', + }); + const authorResponse = await app.inject({ + headers: authHeader(), + method: 'GET', + url: '/worlds/world-1/lore?status=DRAFT', + }); + const curatorResponse = await app.inject({ + headers: authHeader(curator), + method: 'GET', + url: '/worlds/world-1/lore?status=DRAFT', + }); + + assert.equal(anonymousResponse.statusCode, 401); + assert.deepEqual( + authorResponse.json().entries.map((entry: { id: string }) => entry.id), + ['own-draft'], + ); + assert.equal('outgoingRelations' in authorResponse.json().entries[0], false); + assert.deepEqual( + curatorResponse + .json() + .entries.map((entry: { id: string }) => entry.id) + .sort(), + ['other-draft', 'own-draft'], + ); + assert.equal( + 'incomingRelations' in + curatorResponse.json().entries.find((entry: { id: string }) => entry.id === 'own-draft'), + false, + ); + await app.close(); + }); + + test('create is draft-only, permission gated, validates caps, and stores JSON verbatim', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + + const unauthenticated = await app.inject({ + method: 'POST', + payload: { + content: { body: 'A body.', summary: 'A summary.' }, + loreType: LoreType.QUEST, + title: 'Quest', + }, + url: '/worlds/world-1/lore', + }); + const forbidden = await app.inject({ + headers: authHeader(otherUser), + method: 'POST', + payload: { + content: { body: 'A body.', summary: 'A summary.' }, + loreType: LoreType.QUEST, + title: 'Quest', + }, + url: '/worlds/world-1/lore', + }); + const selfPublish = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + content: { body: 'A body.', summary: 'A summary.' }, + loreType: LoreType.QUEST, + status: LoreStatus.PUBLISHED_CANON, + title: 'Quest', + }, + url: '/worlds/world-1/lore', + }); + const oversizedSummary = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + content: { body: 'A body.', summary: 'x'.repeat(1_001) }, + loreType: LoreType.QUEST, + title: 'Quest', + }, + url: '/worlds/world-1/lore', + }); + const mismatchedEntityType = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + content: { body: 'A body.', entityType: 'QUEST', summary: 'A summary.' }, + loreType: LoreType.OTHER, + title: 'Mismatched entity type', + }, + url: '/worlds/world-1/lore', + }); + const created = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + content: { + body: '', + fields: { + hook: '', + }, + summary: 'A summary.', + }, + loreType: LoreType.QUEST, + title: ' The First Quest ', + }, + url: '/worlds/world-1/lore', + }); + + assert.equal(unauthenticated.statusCode, 401); + assert.equal(forbidden.statusCode, 403); + assert.equal(selfPublish.statusCode, 400); + assert.equal(oversizedSummary.statusCode, 400); + assert.equal(mismatchedEntityType.statusCode, 400); + assert.equal(created.statusCode, 201); + assert.equal(created.json().entry.status, LoreStatus.DRAFT); + assert.equal(created.json().entry.loreType, LoreType.QUEST); + assert.equal(created.json().entry.title, 'The First Quest'); + assert.equal(created.json().entry.content.body, ''); + await app.close(); + }); + + test('update and delete are limited to editable drafts and never mutate canon', async () => { + const state = createDatabase(); + state.memberships.find((membership) => membership.userId === otherUser.id)!.role = + WorldRole.CONTRIBUTOR; + state.loreEntries.push(createLoreRecord({ id: 'draft-1' })); + state.loreEntries.push( + createLoreRecord({ + id: 'canon-1', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + }), + ); + const app = await createApp(state.database); + + const otherUpdate = await app.inject({ + headers: authHeader(otherUser), + method: 'PATCH', + payload: { title: 'Nope' }, + url: '/worlds/world-1/lore/draft-1', + }); + const selfPublishUpdate = await app.inject({ + headers: authHeader(), + method: 'PATCH', + payload: { status: LoreStatus.PUBLISHED_CANON }, + url: '/worlds/world-1/lore/draft-1', + }); + const update = await app.inject({ + headers: authHeader(), + method: 'PATCH', + payload: { + content: { body: 'Updated.', summary: 'Updated summary.' }, + loreType: LoreType.STORY, + title: 'Updated Draft', + }, + url: '/worlds/world-1/lore/draft-1', + }); + const mismatchedEntityType = await app.inject({ + headers: authHeader(), + method: 'PATCH', + payload: { + content: { body: 'Updated.', entityType: 'QUEST', summary: 'Updated summary.' }, + loreType: LoreType.OTHER, + }, + url: '/worlds/world-1/lore/draft-1', + }); + const canonDelete = await app.inject({ + headers: authHeader(curator), + method: 'DELETE', + url: '/worlds/world-1/lore/canon-1', + }); + const deleteResponse = await app.inject({ + headers: authHeader(), + method: 'DELETE', + url: '/worlds/world-1/lore/draft-1', + }); + + assert.equal(otherUpdate.statusCode, 403); + assert.equal(selfPublishUpdate.statusCode, 400); + assert.equal(update.statusCode, 200); + assert.equal(update.json().entry.loreType, LoreType.STORY); + assert.equal(mismatchedEntityType.statusCode, 400); + assert.equal(canonDelete.statusCode, 409); + assert.equal(deleteResponse.statusCode, 200); + assert.equal(deleteResponse.json().ok, true); + assert.equal( + state.loreEntries.some((entry) => entry.id === 'draft-1'), + false, + ); + assert.equal( + state.loreEntries.some((entry) => entry.id === 'canon-1'), + true, + ); + await app.close(); + }); + + test('quest and story are distinct filterable lore types', async () => { + const state = createDatabase(); + state.loreEntries.push( + createLoreRecord({ + id: 'quest-1', + loreType: LoreType.QUEST, + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + }), + ); + state.loreEntries.push( + createLoreRecord({ + id: 'story-1', + loreType: LoreType.STORY, + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + }), + ); + const app = await createApp(state.database); + + const questResponse = await app.inject({ + method: 'GET', + url: '/worlds/world-1/lore?loreType=QUEST', + }); + const storyResponse = await app.inject({ + method: 'GET', + url: '/worlds/world-1/lore?loreType=STORY', + }); + + assert.deepEqual( + questResponse.json().entries.map((entry: { id: string }) => entry.id), + ['quest-1'], + ); + assert.deepEqual( + storyResponse.json().entries.map((entry: { id: string }) => entry.id), + ['story-1'], + ); + await app.close(); + }); + + test('relationships can be created, read from entry pages, deduplicated, and deleted', async () => { + const state = createDatabase(); + state.loreEntries.push(createLoreRecord({ id: 'source-1', title: 'Source' })); + state.loreEntries.push(createLoreRecord({ id: 'target-1', title: 'Target' })); + const app = await createApp(state.database); + + const selfLink = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + relationType: 'member_of', + targetId: 'source-1', + }, + url: '/worlds/world-1/lore/source-1/relationships', + }); + const created = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + metadata: { certainty: 'high' }, + relationType: 'member_of', + targetId: 'target-1', + }, + url: '/worlds/world-1/lore/source-1/relationships', + }); + const duplicate = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + relationType: 'member_of', + targetId: 'target-1', + }, + url: '/worlds/world-1/lore/source-1/relationships', + }); + const read = await app.inject({ + headers: authHeader(), + method: 'GET', + url: '/worlds/world-1/lore/source-1', + }); + const deleted = await app.inject({ + headers: authHeader(), + method: 'DELETE', + url: `/worlds/world-1/lore/source-1/relationships/${created.json().relationship.id}`, + }); + + assert.equal(selfLink.statusCode, 400); + assert.equal(created.statusCode, 201); + assert.equal(created.json().relationship.relationType, 'member_of'); + assert.equal(duplicate.statusCode, 409); + assert.equal(read.statusCode, 200); + assert.equal(read.json().entry.outgoingRelations.length, 1); + assert.equal(read.json().entry.outgoingRelations[0].target.id, 'target-1'); + assert.equal(deleted.statusCode, 204); + assert.equal(state.loreRelationships.length, 0); + assert.equal(state.worldAuditLogs.length >= 2, true); + await app.close(); + }); + + test('relationships cannot mutate canon entries without proposal governance', async () => { + const state = createDatabase(); + state.loreEntries.push(createLoreRecord({ id: 'draft-source', title: 'Draft Source' })); + state.loreEntries.push( + createLoreRecord({ + id: 'canon-source', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + title: 'Canon Source', + }), + ); + state.loreEntries.push( + createLoreRecord({ + id: 'canon-target', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + title: 'Canon Target', + }), + ); + state.loreRelationships.push({ + createdAt: now(), + id: 'canon-relationship', + metadata: null, + relationType: 'enemy_of', + sourceId: 'canon-source', + targetId: 'canon-target', + updatedAt: now(), + worldId: 'world-1', + }); + const app = await createApp(state.database); + + const draftToCanon = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + relationType: 'allied_with', + targetId: 'canon-target', + }, + url: '/worlds/world-1/lore/draft-source/relationships', + }); + const created = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + relationType: 'allied_with', + targetId: 'canon-target', + }, + url: '/worlds/world-1/lore/canon-source/relationships', + }); + const deleted = await app.inject({ + headers: authHeader(curator), + method: 'DELETE', + url: '/worlds/world-1/lore/canon-source/relationships/canon-relationship', + }); + + assert.equal(draftToCanon.statusCode, 201); + assert.equal(created.statusCode, 409); + assert.equal( + created.json().error, + 'Draft lore can only link to draft or published canon entries here.', + ); + assert.equal(deleted.statusCode, 409); + assert.equal( + deleted.json().error, + 'Only relationships owned by draft lore can be deleted here.', + ); + assert.equal(state.loreRelationships.length, 2); + await app.close(); + }); + + test('relationship creation hides unauthorized sources before revealing status', async () => { + const state = createDatabase(); + state.memberships.find((membership) => membership.userId === otherUser.id)!.role = + WorldRole.CONTRIBUTOR; + state.loreEntries.push( + createLoreRecord({ + id: 'other-canon-source', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + title: 'Other Canon Source', + }), + ); + state.loreEntries.push( + createLoreRecord({ + id: 'canon-target', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + title: 'Canon Target', + }), + ); + const app = await createApp(state.database); + + const response = await app.inject({ + headers: authHeader(otherUser), + method: 'POST', + payload: { + relationType: 'allied_with', + targetId: 'canon-target', + }, + url: '/worlds/world-1/lore/other-canon-source/relationships', + }); + + assert.equal(response.statusCode, 404); + assert.equal(response.json().error, 'Lore entry not found.'); + assert.equal(state.loreRelationships.length, 0); + await app.close(); + }); + + test('relationship creation does not reveal unreadable draft targets', async () => { + const state = createDatabase(); + state.loreEntries.push(createLoreRecord({ id: 'attacker-draft', title: 'Attacker Draft' })); + state.loreEntries.push( + createLoreRecord({ + authorId: otherUser.id, + id: 'victim-draft', + title: 'Secret Plot Twist', + }), + ); + const app = await createApp(state.database); + + const response = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + relationType: 'related_to', + targetId: 'victim-draft', + }, + url: '/worlds/world-1/lore/attacker-draft/relationships', + }); + + assert.equal(response.statusCode, 404); + assert.equal(response.json().error, 'Related lore entry not found.'); + assert.equal(JSON.stringify(response.json()).includes('Secret Plot Twist'), false); + assert.equal(state.loreRelationships.length, 0); + await app.close(); + }); + + test('cross-author relationship cap limits abusive inbound edges per source author', async () => { + const state = createDatabase(); + state.memberships.find((membership) => membership.userId === otherUser.id)!.role = + WorldRole.CONTRIBUTOR; + state.loreEntries.push( + createLoreRecord({ + authorId: otherUser.id, + id: 'draft-source', + title: 'Draft Source', + }), + ); + state.loreEntries.push( + createLoreRecord({ + id: 'popular-target', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + title: 'Popular Target', + }), + ); + + for (let index = 0; index < 50; index += 1) { + const sourceId = `existing-source-${index}`; + state.loreEntries.push( + createLoreRecord({ + authorId: otherUser.id, + id: sourceId, + title: `Existing Source ${index}`, + }), + ); + state.loreRelationships.push({ + createdAt: now(), + id: `existing-relationship-${index}`, + metadata: null, + relationType: 'related_to', + sourceId, + targetId: 'popular-target', + updatedAt: now(), + worldId: 'world-1', + }); + } + + const app = await createApp(state.database); + + const response = await app.inject({ + headers: authHeader(otherUser), + method: 'POST', + payload: { + relationType: 'allied_with', + targetId: 'popular-target', + }, + url: '/worlds/world-1/lore/draft-source/relationships', + }); + + assert.equal(response.statusCode, 409); + assert.equal( + response.json().error, + 'This author has reached the cross-author relationship limit for that entry.', + ); + assert.equal(state.loreRelationships.length, 50); + await app.close(); + }); + + test('same-author hubs can collect more than ten incoming links', async () => { + const state = createDatabase(); + state.loreEntries.push(createLoreRecord({ id: 'faction-hub', title: 'Faction Hub' })); + + for (let index = 0; index < 10; index += 1) { + const sourceId = `member-${index}`; + state.loreEntries.push(createLoreRecord({ id: sourceId, title: `Member ${index}` })); + state.loreRelationships.push({ + createdAt: now(), + id: `existing-relationship-${index}`, + metadata: null, + relationType: 'member_of', + sourceId, + targetId: 'faction-hub', + updatedAt: now(), + worldId: 'world-1', + }); + } + + state.loreEntries.push(createLoreRecord({ id: 'member-10', title: 'Member 10' })); + const app = await createApp(state.database); + + const response = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + relationType: 'member_of', + targetId: 'faction-hub', + }, + url: '/worlds/world-1/lore/member-10/relationships', + }); + + assert.equal(response.statusCode, 201); + assert.equal(state.loreRelationships.length, 11); + await app.close(); + }); + + test('relationship target total does not let one author freeze another author out', async () => { + const state = createDatabase(); + state.loreEntries.push(createLoreRecord({ id: 'fresh-source', title: 'Fresh Source' })); + state.loreEntries.push( + createLoreRecord({ + id: 'popular-target', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + title: 'Popular Target', + }), + ); + + for (let index = 0; index < 100; index += 1) { + const sourceId = `other-source-${index}`; + state.loreEntries.push( + createLoreRecord({ + authorId: otherUser.id, + id: sourceId, + title: `Other Source ${index}`, + }), + ); + state.loreRelationships.push({ + createdAt: now(), + id: `existing-relationship-${index}`, + metadata: null, + relationType: 'related_to', + sourceId, + targetId: 'popular-target', + updatedAt: now(), + worldId: 'world-1', + }); + } + + const app = await createApp(state.database); + + const response = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + relationType: 'allied_with', + targetId: 'popular-target', + }, + url: '/worlds/world-1/lore/fresh-source/relationships', + }); + + assert.equal(response.statusCode, 201); + assert.equal(state.loreRelationships.length, 101); + await app.close(); + }); + + test('relationship creation retries driver-adapter transaction conflicts', async () => { + const state = createDatabase(); + state.loreEntries.push(createLoreRecord({ id: 'source-1', title: 'Source' })); + state.loreEntries.push(createLoreRecord({ id: 'target-1', title: 'Target' })); + const originalTransaction = state.database.$transaction; + let attempts = 0; + + state.database.$transaction = async ( + callback: (transaction: unknown) => Promise, + options?: unknown, + ) => { + attempts += 1; + + if (attempts < 9) { + throw Object.assign(new Error('TransactionWriteConflict'), { + cause: { + kind: 'TransactionWriteConflict', + }, + name: 'DriverAdapterError', + }); + } + + return originalTransaction(callback, options); + }; + + const app = await createApp(state.database); + + const response = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + relationType: 'member_of', + targetId: 'target-1', + }, + url: '/worlds/world-1/lore/source-1/relationships', + }); + + assert.equal(response.statusCode, 201); + assert.equal(attempts, 9); + assert.equal(state.loreRelationships.length, 1); + await app.close(); + }); + + test('relationship type accepts only supported values', async () => { + const state = createDatabase(); + state.loreEntries.push(createLoreRecord({ id: 'source-1', title: 'Source' })); + state.loreEntries.push(createLoreRecord({ id: 'target-1', title: 'Target' })); + const app = await createApp(state.database); + + const response = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + relationType: '', + targetId: 'target-1', + }, + url: '/worlds/world-1/lore/source-1/relationships', + }); + + assert.equal(response.statusCode, 400); + assert.equal(response.json().error, 'Invalid lore relationship payload.'); + assert.equal(state.loreRelationships.length, 0); + await app.close(); + }); + + test('curator relation projection ranks canon edges before non-canon edges', async () => { + const state = createDatabase(); + state.loreEntries.push( + createLoreRecord({ + id: 'canon-target', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + title: 'Canon Target', + }), + ); + state.loreEntries.push( + createLoreRecord({ + id: 'archived-source', + publishedAt: null, + status: LoreStatus.ARCHIVED, + title: 'Archived Source', + }), + ); + state.loreEntries.push( + createLoreRecord({ + id: 'canon-source', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + title: 'Canon Source', + }), + ); + state.loreRelationships.push( + { + createdAt: now(), + id: 'archived-relationship', + metadata: null, + relationType: 'related_to', + sourceId: 'archived-source', + targetId: 'canon-target', + updatedAt: now(), + worldId: 'world-1', + }, + { + createdAt: now(), + id: 'canon-relationship', + metadata: null, + relationType: 'related_to', + sourceId: 'canon-source', + targetId: 'canon-target', + updatedAt: now(), + worldId: 'world-1', + }, + ); + const app = await createApp(state.database); + + const response = await app.inject({ + headers: authHeader(curator), + method: 'GET', + url: '/worlds/world-1/lore/canon-target', + }); + + assert.equal(response.statusCode, 200); + assert.deepEqual( + response + .json() + .entry.incomingRelations.map( + (relationship: { source: { id: string } }) => relationship.source.id, + ), + ['canon-source', 'archived-source'], + ); + await app.close(); + }); + + test('public relation projection hides draft related entries', async () => { + const state = createDatabase(); + state.loreEntries.push( + createLoreRecord({ + id: 'published-source', + publishedAt: now(), + status: LoreStatus.PUBLISHED_CANON, + }), + ); + state.loreEntries.push(createLoreRecord({ id: 'private-target', title: 'Private Target' })); + state.loreRelationships.push({ + createdAt: now(), + id: 'relationship-1', + metadata: null, + relationType: 'knows', + sourceId: 'published-source', + targetId: 'private-target', + updatedAt: now(), + worldId: 'world-1', + }); + const app = await createApp(state.database); + + const publicRead = await app.inject({ + method: 'GET', + url: '/worlds/world-1/lore/published-source', + }); + const authorRead = await app.inject({ + headers: authHeader(), + method: 'GET', + url: '/worlds/world-1/lore/published-source', + }); + + assert.equal(publicRead.statusCode, 200); + assert.equal(publicRead.json().entry.outgoingRelations.length, 0); + assert.equal(authorRead.statusCode, 200); + assert.equal(authorRead.json().entry.outgoingRelations.length, 1); + await app.close(); + }); +}); diff --git a/apps/api/src/routes/lore.ts b/apps/api/src/routes/lore.ts new file mode 100644 index 0000000..2ba88d0 --- /dev/null +++ b/apps/api/src/routes/lore.ts @@ -0,0 +1,1639 @@ +import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; +import { z } from 'zod'; + +import { env } from '../config/env.js'; +import { Prisma } from '../generated/prisma/client.js'; +import type { PrismaClient } from '../generated/prisma/client.js'; +import { LoreStatus, LoreType, WorldAuditAction } from '../generated/prisma/enums.js'; +import { authenticateRequest, requireSession } from '../lib/auth-middleware.js'; +import type { SessionVerificationDatabase } from '../lib/auth-sessions.js'; +import { prisma } from '../lib/prisma.js'; +import { upsertLoreSearchIndex } from '../lib/search-index.js'; +import { + authorizeWorldPermission, + resolveWorldMembership, + type WorldMembershipLookup, +} from '../lib/world-authorization.js'; +import { roleHasWorldPermission, WORLD_PERMISSIONS } from '../lib/world-permissions.js'; + +const STRUCTURED_CONTENT_MAX_BYTES = 100 * 1024; +const STRUCTURED_CONTENT_MAX_DEPTH = 32; +const RELATIONSHIP_METADATA_MAX_BYTES = 16 * 1024; +const MAX_RELATIONSHIPS_PER_ENTRY = 100; +const MAX_CROSS_AUTHOR_INBOUND_RELATIONSHIPS_PER_AUTHOR_PER_ENTRY = 50; +const RELATIONSHIP_TRANSACTION_RETRIES = 10; +const RELATIONSHIP_TYPES = [ + 'allied_with', + 'enemy_of', + 'member_of', + 'rules', + 'located_in', + 'involved_in', + 'created_by', + 'related_to', +] as const; +const CONTENT_ENTITY_TYPE_BY_LORE_TYPE: Record = { + [LoreType.ARTIFACT]: 'ARTIFACT', + [LoreType.CHARACTER]: 'CHARACTER', + [LoreType.EVENT]: 'HISTORICAL_EVENT', + [LoreType.FACTION]: 'FACTION', + [LoreType.HISTORY]: 'HISTORY', + [LoreType.LOCATION]: 'CITY_KINGDOM', + [LoreType.OTHER]: 'OTHER', + [LoreType.QUEST]: 'QUEST', + [LoreType.RULE]: 'RULE', + [LoreType.STORY]: 'STORY_CONTRIBUTION', +}; + +type LoreDatabase = Pick< + PrismaClient, + | '$transaction' + | 'loreEntry' + | 'loreRelationship' + | 'searchIndex' + | 'world' + | 'worldAuditLog' + | 'worldMembership' +>; + +type RegisterLoreRoutesOptions = { + database?: LoreDatabase & WorldMembershipLookup & SessionVerificationDatabase; +}; + +const routeParamsSchema = z.object({ + entryId: z.string().min(1).optional(), + worldId: z.string().min(1), +}); + +const loreTypeSchema = z.enum([ + LoreType.CHARACTER, + LoreType.LOCATION, + LoreType.FACTION, + LoreType.QUEST, + LoreType.EVENT, + LoreType.STORY, + LoreType.ARTIFACT, + LoreType.HISTORY, + LoreType.RULE, + LoreType.OTHER, +]); + +const loreStatusSchema = z.enum([ + LoreStatus.DRAFT, + LoreStatus.SUBMITTED, + LoreStatus.APPROVED_FOR_PUBLICATION, + LoreStatus.PUBLISHED_CANON, + LoreStatus.ARCHIVED, +]); + +const listLoreQuerySchema = z.object({ + loreType: loreTypeSchema.optional(), + page: z.coerce.number().int().positive().max(100).default(1), + pageSize: z.coerce.number().int().positive().max(100).default(20), + q: z.string().trim().max(200).optional(), + status: loreStatusSchema.optional(), +}); + +const createLoreBodySchema = z + .object({ + content: z.unknown(), + loreType: loreTypeSchema, + status: z.literal(LoreStatus.DRAFT).optional(), + title: z.string().trim().min(1).max(200), + }) + .strict(); + +const updateLoreBodySchema = z + .object({ + content: z.unknown().optional(), + loreType: loreTypeSchema.optional(), + title: z.string().trim().min(1).max(200).optional(), + }) + .strict() + .refine((value) => Object.keys(value).length > 0, { + message: 'At least one editable lore field is required.', + }); + +const createRelationshipBodySchema = z + .object({ + metadata: z.unknown().optional(), + relationType: z.enum(RELATIONSHIP_TYPES), + targetId: z.string().trim().min(1), + }) + .strict(); + +function visibleRelatedEntryWhere( + side: 'source' | 'target', + options: { + includeAllNonPublicRelations?: boolean; + viewerId?: string | undefined; + }, +): Prisma.LoreRelationshipWhereInput { + if (options.includeAllNonPublicRelations) { + return {}; + } + + const relatedEntryWhere: Prisma.LoreEntryWhereInput = { + OR: [ + { + status: LoreStatus.PUBLISHED_CANON, + }, + ...(options.viewerId + ? [ + { + authorId: options.viewerId, + }, + ] + : []), + ], + }; + + return side === 'source' ? { source: relatedEntryWhere } : { target: relatedEntryWhere }; +} + +function loreEntryInclude( + options: { + includeAllNonPublicRelations?: boolean; + viewerId?: string | undefined; + } = {}, +) { + const incomingRelationOrderBy: Prisma.LoreRelationshipOrderByWithRelationInput[] = [ + { + source: { + publishedAt: { + sort: 'desc', + nulls: 'last', + }, + }, + }, + { + updatedAt: 'desc', + }, + { + id: 'desc', + }, + ]; + const outgoingRelationOrderBy: Prisma.LoreRelationshipOrderByWithRelationInput[] = [ + { + target: { + publishedAt: { + sort: 'desc', + nulls: 'last', + }, + }, + }, + { + updatedAt: 'desc', + }, + { + id: 'desc', + }, + ]; + + return { + author: { + select: { + avatarUrl: true, + displayName: true, + hiveUsername: true, + id: true, + }, + }, + incomingRelations: { + orderBy: incomingRelationOrderBy, + select: { + id: true, + relationType: true, + source: { + select: { + authorId: true, + id: true, + loreType: true, + slug: true, + status: true, + title: true, + }, + }, + }, + take: MAX_RELATIONSHIPS_PER_ENTRY, + where: visibleRelatedEntryWhere('source', options), + }, + outgoingRelations: { + orderBy: outgoingRelationOrderBy, + select: { + id: true, + relationType: true, + target: { + select: { + authorId: true, + id: true, + loreType: true, + slug: true, + status: true, + title: true, + }, + }, + }, + take: MAX_RELATIONSHIPS_PER_ENTRY, + where: visibleRelatedEntryWhere('target', options), + }, + } satisfies Prisma.LoreEntryInclude; +} + +type LoreEntryWithRelations = Prisma.LoreEntryGetPayload<{ + include: ReturnType; +}>; + +function loreEntryListInclude() { + return { + author: { + select: { + avatarUrl: true, + displayName: true, + hiveUsername: true, + id: true, + }, + }, + } satisfies Prisma.LoreEntryInclude; +} + +type LoreEntryListItem = Prisma.LoreEntryGetPayload<{ + include: ReturnType; +}>; + +class LoreRouteError extends Error { + constructor( + public readonly statusCode: number, + message: string, + ) { + super(message); + } +} + +function authOptions(database: SessionVerificationDatabase) { + return { + audience: env.AUTH_JWT_AUDIENCE, + database, + issuer: env.AUTH_JWT_ISSUER, + jwtSecret: env.AUTH_JWT_SECRET, + }; +} + +function serializeDate(value: Date | null) { + return value?.toISOString() ?? null; +} + +function serializeLoreEntry( + entry: LoreEntryWithRelations, + options: { + includeAllNonPublicRelations?: boolean; + viewerId?: string | undefined; + } = {}, +) { + const canShowRelatedEntry = (relatedEntry: { authorId?: string; status: LoreStatus }) => + relatedEntry.status === LoreStatus.PUBLISHED_CANON || + options.includeAllNonPublicRelations || + ('authorId' in relatedEntry && relatedEntry.authorId === options.viewerId); + const relationshipStatusRank = (status: LoreStatus) => + status === LoreStatus.PUBLISHED_CANON ? 0 : 1; + + return { + author: entry.author, + authorId: entry.authorId, + content: entry.content, + createdAt: entry.createdAt.toISOString(), + hiveReferenceId: entry.hiveReferenceId, + id: entry.id, + incomingRelations: entry.incomingRelations + .filter((relation) => canShowRelatedEntry(relation.source)) + .sort( + (left, right) => + relationshipStatusRank(left.source.status) - relationshipStatusRank(right.source.status), + ) + .map((relation) => ({ + id: relation.id, + relationType: relation.relationType, + source: { + id: relation.source.id, + loreType: relation.source.loreType, + slug: relation.source.slug, + status: relation.source.status, + title: relation.source.title, + }, + })), + loreType: entry.loreType, + outgoingRelations: entry.outgoingRelations + .filter((relation) => canShowRelatedEntry(relation.target)) + .sort( + (left, right) => + relationshipStatusRank(left.target.status) - relationshipStatusRank(right.target.status), + ) + .map((relation) => ({ + id: relation.id, + relationType: relation.relationType, + target: { + id: relation.target.id, + loreType: relation.target.loreType, + slug: relation.target.slug, + status: relation.target.status, + title: relation.target.title, + }, + })), + publishedAt: serializeDate(entry.publishedAt), + slug: entry.slug, + status: entry.status, + title: entry.title, + updatedAt: entry.updatedAt.toISOString(), + worldId: entry.worldId, + }; +} + +function serializeLoreListEntry(entry: LoreEntryListItem) { + return { + author: entry.author, + authorId: entry.authorId, + content: entry.content, + createdAt: entry.createdAt.toISOString(), + hiveReferenceId: entry.hiveReferenceId, + id: entry.id, + loreType: entry.loreType, + publishedAt: serializeDate(entry.publishedAt), + slug: entry.slug, + status: entry.status, + title: entry.title, + updatedAt: entry.updatedAt.toISOString(), + worldId: entry.worldId, + }; +} + +function isPlainObject(value: unknown): value is Record { + return ( + typeof value === 'object' && + value !== null && + !Array.isArray(value) && + (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null) + ); +} + +function validateJsonValue(value: unknown, depth = 0): Prisma.InputJsonValue { + if (depth > STRUCTURED_CONTENT_MAX_DEPTH) { + throw new LoreRouteError(400, 'Lore content nesting is too deep.'); + } + + if ( + value === null || + typeof value === 'string' || + typeof value === 'boolean' || + (typeof value === 'number' && Number.isFinite(value)) + ) { + return value as Prisma.InputJsonValue; + } + + if (Array.isArray(value)) { + return value.map((item) => validateJsonValue(item, depth + 1)) as Prisma.InputJsonArray; + } + + if (isPlainObject(value)) { + return Object.fromEntries( + Object.entries(value).map(([key, nestedValue]) => [ + key, + validateJsonValue(nestedValue, depth + 1), + ]), + ) as Prisma.InputJsonObject; + } + + throw new LoreRouteError(400, 'Lore content must be JSON-serializable.'); +} + +function validateLoreContent(value: unknown, loreType: LoreType): Prisma.InputJsonValue { + if (!isPlainObject(value)) { + throw new LoreRouteError(400, 'Lore content must be a JSON object.'); + } + + const serialized = JSON.stringify(value); + + if (!serialized || Buffer.byteLength(serialized, 'utf8') > STRUCTURED_CONTENT_MAX_BYTES) { + throw new LoreRouteError(400, 'Lore content exceeds the 100 KB limit.'); + } + + const summary = value.summary; + + if (summary !== undefined && (typeof summary !== 'string' || summary.trim().length > 1_000)) { + throw new LoreRouteError(400, 'Lore summary must be at most 1000 characters.'); + } + + const body = value.body; + + if (body !== undefined && typeof body !== 'string') { + throw new LoreRouteError(400, 'Lore body must be a string.'); + } + + const entityType = value.entityType; + const expectedEntityType = CONTENT_ENTITY_TYPE_BY_LORE_TYPE[loreType]; + + if (entityType !== undefined) { + if (typeof entityType !== 'string') { + throw new LoreRouteError(400, 'Lore entity type must be a string.'); + } + + if (entityType !== expectedEntityType) { + throw new LoreRouteError(400, 'Lore entity type must match the lore type.'); + } + } + + return validateJsonValue(value); +} + +function validateRelationshipMetadata(value: unknown): Prisma.InputJsonValue { + const serialized = JSON.stringify(value); + + if (!serialized || Buffer.byteLength(serialized, 'utf8') > RELATIONSHIP_METADATA_MAX_BYTES) { + throw new LoreRouteError(400, 'Relationship metadata exceeds the 16 KB limit.'); + } + + return validateJsonValue(value); +} + +function normalizeTitle(title: string) { + const normalized = title.trim(); + + if (!normalized) { + throw new LoreRouteError(400, 'Lore title is required.'); + } + + if (normalized.length > 200) { + throw new LoreRouteError(400, 'Lore title must be at most 200 characters.'); + } + + return normalized; +} + +function slugify(title: string) { + const slug = title + .toLowerCase() + .normalize('NFKD') + .replace(/[\u0300-\u036f]/g, '') + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, '') + .slice(0, 80); + + return slug || 'lore-entry'; +} + +async function createUniqueSlug( + database: Pick, + worldId: string, + title: string, + excludeEntryId?: string, +) { + const baseSlug = slugify(title); + + for (let suffix = 0; suffix < 100; suffix += 1) { + const slug = suffix === 0 ? baseSlug : `${baseSlug}-${suffix + 1}`; + const existing = await database.loreEntry.findFirst({ + select: { + id: true, + }, + where: { + slug, + worldId, + }, + }); + + if (!existing || existing.id === excludeEntryId) { + return slug; + } + } + + throw new LoreRouteError(409, 'Unable to generate a unique lore slug.'); +} + +async function ensureWorldExists( + database: Pick, + worldId: string, + reply: FastifyReply, +) { + const world = await database.world.findUnique({ + select: { + id: true, + }, + where: { + id: worldId, + }, + }); + + if (!world) { + await reply.code(404).send({ + error: 'World not found.', + }); + + return false; + } + + return true; +} + +function sendLoreError(error: unknown, reply: FastifyReply) { + if (error instanceof LoreRouteError) { + return reply.code(error.statusCode).send({ + error: error.message, + }); + } + + throw error; +} + +function isPrismaUniqueConflict(error: unknown) { + return typeof error === 'object' && error !== null && 'code' in error && error.code === 'P2002'; +} + +function isPrismaTransactionConflict(error: unknown) { + if (typeof error !== 'object' || error === null) { + return false; + } + + const record = error as { + cause?: { code?: unknown; kind?: unknown }; + code?: unknown; + }; + + return ( + record.code === 'P2034' || + record.code === '40001' || + record.code === '40P01' || + record.cause?.kind === 'TransactionWriteConflict' || + record.cause?.code === '40001' || + record.cause?.code === '40P01' + ); +} + +function delay(ms: number) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} + +function relationshipRetryDelay(attempt: number) { + return 25 * attempt + Math.floor(Math.random() * 25); +} + +async function createLoreAuditLog( + database: Pick, + input: { + action: (typeof WorldAuditAction)[keyof typeof WorldAuditAction]; + actorId: string; + metadata?: Prisma.InputJsonObject | undefined; + targetId: string; + targetType: string; + worldId: string; + }, +) { + await database.worldAuditLog.create({ + data: { + action: input.action, + actorId: input.actorId, + metadata: input.metadata ?? {}, + targetId: input.targetId, + targetType: input.targetType, + worldId: input.worldId, + }, + }); +} + +async function authenticateOptional( + request: FastifyRequest, + database: SessionVerificationDatabase, +) { + return authenticateRequest(request, authOptions(database)); +} + +async function canReadNonPublicLore( + request: FastifyRequest, + database: LoreDatabase & WorldMembershipLookup, + worldId: string, + authorId?: string, +) { + const user = request.user; + + if (!user) { + return false; + } + + const membership = await resolveWorldMembership(request, worldId, database); + + if (!membership) { + return false; + } + + if (roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.EDIT_ANY_DRAFT)) { + return true; + } + + return ( + authorId === user.id && + roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.EDIT_OWN_DRAFT) + ); +} + +async function scopeNonPublicLoreList( + request: FastifyRequest, + database: LoreDatabase & WorldMembershipLookup, + worldId: string, +) { + const user = request.user; + + if (!user) { + return { + allowed: false as const, + statusCode: 401 as const, + where: {}, + }; + } + + const membership = await resolveWorldMembership(request, worldId, database); + + if (!membership) { + return { + allowed: false as const, + statusCode: 403 as const, + where: {}, + }; + } + + if (roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.EDIT_ANY_DRAFT)) { + return { + allowed: true as const, + includeAllNonPublicRelations: true, + where: {}, + }; + } + + if (roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.EDIT_OWN_DRAFT)) { + return { + allowed: true as const, + includeAllNonPublicRelations: false, + where: { + authorId: user.id, + }, + }; + } + + return { + allowed: false as const, + statusCode: 403 as const, + where: {}, + }; +} + +async function canMutateDraft( + request: FastifyRequest, + database: LoreDatabase & WorldMembershipLookup, + worldId: string, + authorId: string, +) { + const user = request.user; + + if (!user) { + return false; + } + + const membership = await resolveWorldMembership(request, worldId, database); + + if (!membership) { + return false; + } + + if (roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.EDIT_ANY_DRAFT)) { + return true; + } + + return ( + authorId === user.id && + roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.EDIT_OWN_DRAFT) + ); +} + +async function canAttemptDraftMutation( + request: FastifyRequest, + database: LoreDatabase & WorldMembershipLookup, + worldId: string, +) { + const user = request.user; + + if (!user) { + return false; + } + + const membership = await resolveWorldMembership(request, worldId, database); + + return Boolean( + membership && + (roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.EDIT_ANY_DRAFT) || + roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.EDIT_OWN_DRAFT)), + ); +} + +async function canViewAllNonPublicLore( + request: FastifyRequest, + database: LoreDatabase & WorldMembershipLookup, + worldId: string, +) { + if (!request.user) { + return false; + } + + const membership = await resolveWorldMembership(request, worldId, database); + + return Boolean( + membership && roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.EDIT_ANY_DRAFT), + ); +} + +export async function registerLoreRoutes( + app: FastifyInstance, + options: RegisterLoreRoutesOptions = {}, +) { + const database = options.database ?? prisma; + const routeAuthOptions = authOptions(database); + + app.get( + '/worlds/:worldId/lore', + { + config: { + rateLimit: { + max: 120, + timeWindow: '1 minute', + }, + }, + }, + async (request, reply) => { + const params = routeParamsSchema.safeParse(request.params); + const query = listLoreQuerySchema.safeParse(request.query); + + if (!params.success || !query.success) { + return reply.code(400).send({ + error: 'Invalid lore query.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists) { + return; + } + + await authenticateOptional(request, database); + + const requestedStatus = query.data.status ?? LoreStatus.PUBLISHED_CANON; + const page = query.data.page; + const pageSize = query.data.pageSize; + const where: Prisma.LoreEntryWhereInput = { + ...(query.data.loreType ? { loreType: query.data.loreType } : {}), + ...(query.data.q + ? { + OR: [ + { + title: { + contains: query.data.q, + mode: 'insensitive', + }, + }, + ], + } + : {}), + status: requestedStatus, + worldId: params.data.worldId, + }; + + if (requestedStatus !== LoreStatus.PUBLISHED_CANON) { + const scope = await scopeNonPublicLoreList(request, database, params.data.worldId); + + if (!scope.allowed) { + return reply.code(scope.statusCode).send({ + error: + scope.statusCode === 401 + ? 'Authentication required.' + : 'Insufficient world permissions.', + }); + } + + Object.assign(where, scope.where); + } + + const [entries, total] = await Promise.all([ + database.loreEntry.findMany({ + include: loreEntryListInclude(), + orderBy: [ + { + updatedAt: 'desc', + }, + { + id: 'desc', + }, + ], + skip: (page - 1) * pageSize, + take: pageSize, + where, + }), + database.loreEntry.count({ + where, + }), + ]); + + return { + entries: entries.map((entry) => serializeLoreListEntry(entry)), + pagination: { + page, + pageSize, + total, + }, + }; + }, + ); + + app.get( + '/worlds/:worldId/lore/:entryId', + { + config: { + rateLimit: { + max: 120, + timeWindow: '1 minute', + }, + }, + }, + async (request, reply) => { + const params = routeParamsSchema.required().safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + error: 'Invalid lore route.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists) { + return; + } + + await authenticateOptional(request, database); + const includeAllNonPublicRelations = await canViewAllNonPublicLore( + request, + database, + params.data.worldId, + ); + + const entry = await database.loreEntry.findFirst({ + include: loreEntryInclude({ + includeAllNonPublicRelations, + viewerId: request.user?.id, + }), + where: { + id: params.data.entryId, + worldId: params.data.worldId, + }, + }); + + if (!entry) { + return reply.code(404).send({ + error: 'Lore entry not found.', + }); + } + + const canReadEntry = await canReadNonPublicLore( + request, + database, + params.data.worldId, + entry.authorId, + ); + + if (entry.status !== LoreStatus.PUBLISHED_CANON) { + if (!canReadEntry) { + return reply.code(404).send({ + error: 'Lore entry not found.', + }); + } + } + + return { + entry: serializeLoreEntry(entry, { + includeAllNonPublicRelations, + viewerId: request.user?.id, + }), + }; + }, + ); + + app.post( + '/worlds/:worldId/lore/:entryId/relationships', + { + config: { + rateLimit: { + max: 30, + timeWindow: '1 minute', + }, + }, + preHandler: requireSession(routeAuthOptions), + }, + async (request, reply) => { + const params = routeParamsSchema.required().safeParse(request.params); + const body = createRelationshipBodySchema.safeParse(request.body); + + if (!params.success || !body.success) { + return reply.code(400).send({ + error: 'Invalid lore relationship payload.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists || !request.user) { + return; + } + + const canAttemptMutation = await canAttemptDraftMutation( + request, + database, + params.data.worldId, + ); + + if (!canAttemptMutation) { + return reply.code(403).send({ + error: 'Insufficient world permissions.', + }); + } + + if (params.data.entryId === body.data.targetId) { + return reply.code(400).send({ + error: 'A lore entry cannot be related to itself.', + }); + } + + const [source, target] = await Promise.all([ + database.loreEntry.findFirst({ + select: { + authorId: true, + id: true, + status: true, + }, + where: { + id: params.data.entryId, + worldId: params.data.worldId, + }, + }), + database.loreEntry.findFirst({ + select: { + authorId: true, + id: true, + status: true, + }, + where: { + id: body.data.targetId, + worldId: params.data.worldId, + }, + }), + ]); + + if (!source || !target) { + return reply.code(404).send({ + error: 'Related lore entry not found.', + }); + } + + const canReadTarget = + target.status === LoreStatus.PUBLISHED_CANON || + (await canReadNonPublicLore(request, database, params.data.worldId, target.authorId)); + + if (!canReadTarget) { + return reply.code(404).send({ + error: 'Related lore entry not found.', + }); + } + + const permitted = await canMutateDraft( + request, + database, + params.data.worldId, + source.authorId, + ); + + if (!permitted) { + return reply.code(404).send({ + error: 'Lore entry not found.', + }); + } + + if ( + source.status !== LoreStatus.DRAFT || + (target.status !== LoreStatus.DRAFT && target.status !== LoreStatus.PUBLISHED_CANON) + ) { + return reply.code(409).send({ + error: 'Draft lore can only link to draft or published canon entries here.', + }); + } + + for (let attempt = 1; attempt <= RELATIONSHIP_TRANSACTION_RETRIES; attempt += 1) { + try { + const relationship = await database.$transaction( + async (transaction) => { + const sourceRelationshipCount = await transaction.loreRelationship.count({ + where: { + OR: [{ sourceId: source.id }, { targetId: source.id }], + worldId: params.data.worldId, + }, + }); + + if (sourceRelationshipCount >= MAX_RELATIONSHIPS_PER_ENTRY) { + throw new LoreRouteError(409, 'A lore entry has reached the relationship limit.'); + } + + if (source.authorId !== target.authorId) { + const crossAuthorInboundCount = await transaction.loreRelationship.count({ + where: { + source: { + authorId: source.authorId, + }, + target: { + authorId: { + not: source.authorId, + }, + }, + targetId: target.id, + worldId: params.data.worldId, + }, + }); + + if ( + crossAuthorInboundCount >= + MAX_CROSS_AUTHOR_INBOUND_RELATIONSHIPS_PER_AUTHOR_PER_ENTRY + ) { + throw new LoreRouteError( + 409, + 'This author has reached the cross-author relationship limit for that entry.', + ); + } + } + + const created = await transaction.loreRelationship.create({ + data: { + ...(body.data.metadata === undefined + ? {} + : { metadata: validateRelationshipMetadata(body.data.metadata) }), + relationType: body.data.relationType, + sourceId: source.id, + targetId: target.id, + worldId: params.data.worldId, + }, + select: { + id: true, + relationType: true, + target: { + select: { + id: true, + loreType: true, + slug: true, + status: true, + title: true, + }, + }, + }, + }); + + await transaction.worldAuditLog.create({ + data: { + action: WorldAuditAction.LORE_RELATIONSHIP_CREATED, + actorId: request.user!.id, + metadata: { + relationType: created.relationType, + sourceId: source.id, + targetId: target.id, + }, + targetId: created.id, + targetType: 'LORE_RELATIONSHIP', + worldId: params.data.worldId, + }, + }); + + return created; + }, + { + isolationLevel: Prisma.TransactionIsolationLevel.Serializable, + }, + ); + + return reply.code(201).send({ + relationship, + }); + } catch (error) { + if (isPrismaTransactionConflict(error) && attempt < RELATIONSHIP_TRANSACTION_RETRIES) { + await delay(relationshipRetryDelay(attempt)); + continue; + } + + if (isPrismaTransactionConflict(error)) { + return reply.code(409).send({ + error: 'Relationship write conflicted. Please retry.', + }); + } + + if (isPrismaUniqueConflict(error)) { + return reply.code(409).send({ + error: 'This lore relationship already exists.', + }); + } + + return sendLoreError(error, reply); + } + } + }, + ); + + app.delete( + '/worlds/:worldId/lore/:entryId/relationships/:relationshipId', + { + config: { + rateLimit: { + max: 60, + timeWindow: '1 minute', + }, + }, + preHandler: requireSession(routeAuthOptions), + }, + async (request, reply) => { + const params = z + .object({ + entryId: z.string().min(1), + relationshipId: z.string().min(1), + worldId: z.string().min(1), + }) + .safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + error: 'Invalid lore relationship route.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists || !request.user) { + return; + } + + const canAttemptMutation = await canAttemptDraftMutation( + request, + database, + params.data.worldId, + ); + + if (!canAttemptMutation) { + return reply.code(403).send({ + error: 'Insufficient world permissions.', + }); + } + + const relationship = await database.loreRelationship.findFirst({ + include: { + source: { + select: { + authorId: true, + status: true, + }, + }, + target: { + select: { + status: true, + }, + }, + }, + where: { + id: params.data.relationshipId, + sourceId: params.data.entryId, + worldId: params.data.worldId, + }, + }); + + if (!relationship) { + return reply.code(404).send({ + error: 'Lore relationship not found.', + }); + } + + const permitted = await canMutateDraft( + request, + database, + params.data.worldId, + relationship.source.authorId, + ); + + if (!permitted) { + return reply.code(403).send({ + error: 'Insufficient world permissions.', + }); + } + + if (relationship.source.status !== LoreStatus.DRAFT) { + return reply.code(409).send({ + error: 'Only relationships owned by draft lore can be deleted here.', + }); + } + + await database.$transaction(async (transaction) => { + await transaction.loreRelationship.delete({ + where: { + id: relationship.id, + }, + }); + + await transaction.worldAuditLog.create({ + data: { + action: WorldAuditAction.LORE_RELATIONSHIP_DELETED, + actorId: request.user!.id, + metadata: { + relationType: relationship.relationType, + sourceId: relationship.sourceId, + targetId: relationship.targetId, + }, + targetId: relationship.id, + targetType: 'LORE_RELATIONSHIP', + worldId: params.data.worldId, + }, + }); + }); + + return reply.code(204).send(); + }, + ); + + app.post( + '/worlds/:worldId/lore', + { + config: { + rateLimit: { + max: 30, + timeWindow: '1 minute', + }, + }, + preHandler: requireSession(routeAuthOptions), + }, + async (request, reply) => { + const params = routeParamsSchema.safeParse(request.params); + const body = createLoreBodySchema.safeParse(request.body); + + if (!params.success || !body.success) { + return reply.code(400).send({ + error: 'Invalid lore payload.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists) { + return; + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.CREATE_LORE_DRAFT, + database, + ); + + if (!authorized || !request.user) { + return; + } + + const includeAllNonPublicRelations = await canViewAllNonPublicLore( + request, + database, + params.data.worldId, + ); + + try { + const title = normalizeTitle(body.data.title); + const content = validateLoreContent(body.data.content, body.data.loreType); + const slug = await createUniqueSlug(database, params.data.worldId, title); + const entry = await database.$transaction(async (transaction) => { + const created = await transaction.loreEntry.create({ + data: { + authorId: request.user!.id, + content, + loreType: body.data.loreType, + publishedAt: null, + slug, + status: LoreStatus.DRAFT, + title, + worldId: params.data.worldId, + }, + include: loreEntryInclude({ + includeAllNonPublicRelations, + viewerId: request.user!.id, + }), + }); + + await createLoreAuditLog(transaction, { + action: WorldAuditAction.LORE_ENTRY_CREATED, + actorId: request.user!.id, + metadata: { + loreType: created.loreType, + status: created.status, + }, + targetId: created.id, + targetType: 'LORE_ENTRY', + worldId: params.data.worldId, + }); + + await upsertLoreSearchIndex(transaction, created.id); + + return created; + }); + + return reply.code(201).send({ + entry: serializeLoreEntry(entry, { + includeAllNonPublicRelations, + viewerId: request.user.id, + }), + }); + } catch (error) { + if (isPrismaUniqueConflict(error)) { + return reply.code(409).send({ + error: 'A lore entry with this title already exists.', + }); + } + + return sendLoreError(error, reply); + } + }, + ); + + app.patch( + '/worlds/:worldId/lore/:entryId', + { + config: { + rateLimit: { + max: 60, + timeWindow: '1 minute', + }, + }, + preHandler: requireSession(routeAuthOptions), + }, + async (request, reply) => { + const params = routeParamsSchema.required().safeParse(request.params); + const body = updateLoreBodySchema.safeParse(request.body); + + if (!params.success || !body.success) { + return reply.code(400).send({ + error: 'Invalid lore payload.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists || !request.user) { + return; + } + + const canAttemptMutation = await canAttemptDraftMutation( + request, + database, + params.data.worldId, + ); + + if (!canAttemptMutation) { + return reply.code(403).send({ + error: 'Insufficient world permissions.', + }); + } + + const existing = await database.loreEntry.findFirst({ + select: { + authorId: true, + content: true, + id: true, + loreType: true, + status: true, + }, + where: { + id: params.data.entryId, + worldId: params.data.worldId, + }, + }); + + if (!existing) { + return reply.code(404).send({ + error: 'Lore entry not found.', + }); + } + + const permitted = await canMutateDraft( + request, + database, + params.data.worldId, + existing.authorId, + ); + + if (!permitted) { + return reply.code(403).send({ + error: 'Insufficient world permissions.', + }); + } + + if (existing.status !== LoreStatus.DRAFT) { + return reply.code(409).send({ + error: 'Only draft lore entries can be edited here.', + }); + } + + const includeAllNonPublicRelations = await canViewAllNonPublicLore( + request, + database, + params.data.worldId, + ); + + try { + const data: Prisma.LoreEntryUpdateInput = {}; + + if (body.data.title !== undefined) { + const title = normalizeTitle(body.data.title); + data.title = title; + data.slug = await createUniqueSlug(database, params.data.worldId, title, existing.id); + } + + if (body.data.loreType !== undefined) { + data.loreType = body.data.loreType; + } + + if (body.data.content !== undefined || body.data.loreType !== undefined) { + const nextLoreType = body.data.loreType ?? existing.loreType; + const nextContent = body.data.content ?? existing.content; + const validatedContent = validateLoreContent(nextContent, nextLoreType); + + if (body.data.content !== undefined) { + data.content = validatedContent; + } + } + + const entry = await database.$transaction(async (transaction) => { + const updated = await transaction.loreEntry.update({ + data, + include: loreEntryInclude({ + includeAllNonPublicRelations, + viewerId: request.user!.id, + }), + where: { + id: existing.id, + }, + }); + + await createLoreAuditLog(transaction, { + action: WorldAuditAction.LORE_ENTRY_UPDATED, + actorId: request.user!.id, + metadata: { + changedFields: Object.keys(data).sort(), + }, + targetId: updated.id, + targetType: 'LORE_ENTRY', + worldId: params.data.worldId, + }); + + await upsertLoreSearchIndex(transaction, updated.id); + + return updated; + }); + + return { + entry: serializeLoreEntry(entry, { + includeAllNonPublicRelations, + viewerId: request.user.id, + }), + }; + } catch (error) { + if (isPrismaUniqueConflict(error)) { + return reply.code(409).send({ + error: 'A lore entry with this title already exists.', + }); + } + + return sendLoreError(error, reply); + } + }, + ); + + app.delete( + '/worlds/:worldId/lore/:entryId', + { + config: { + rateLimit: { + max: 30, + timeWindow: '1 minute', + }, + }, + preHandler: requireSession(routeAuthOptions), + }, + async (request, reply) => { + const params = routeParamsSchema.required().safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + error: 'Invalid lore route.', + }); + } + + const worldExists = await ensureWorldExists(database, params.data.worldId, reply); + + if (!worldExists || !request.user) { + return; + } + + const canAttemptMutation = await canAttemptDraftMutation( + request, + database, + params.data.worldId, + ); + + if (!canAttemptMutation) { + return reply.code(403).send({ + error: 'Insufficient world permissions.', + }); + } + + const existing = await database.loreEntry.findFirst({ + select: { + authorId: true, + id: true, + loreType: true, + status: true, + title: true, + }, + where: { + id: params.data.entryId, + worldId: params.data.worldId, + }, + }); + + if (!existing) { + return reply.code(404).send({ + error: 'Lore entry not found.', + }); + } + + const permitted = await canMutateDraft( + request, + database, + params.data.worldId, + existing.authorId, + ); + + if (!permitted) { + return reply.code(403).send({ + error: 'Insufficient world permissions.', + }); + } + + if (existing.status !== LoreStatus.DRAFT) { + return reply.code(409).send({ + error: 'Only draft lore entries can be deleted here.', + }); + } + + await database.$transaction(async (transaction) => { + await transaction.loreRelationship.deleteMany({ + where: { + OR: [{ sourceId: existing.id }, { targetId: existing.id }], + worldId: params.data.worldId, + }, + }); + + await transaction.loreEntry.delete({ + where: { + id: existing.id, + }, + }); + + await transaction.searchIndex.deleteMany({ + where: { + entityId: existing.id, + entityType: 'LORE_ENTRY', + }, + }); + + await createLoreAuditLog(transaction, { + action: WorldAuditAction.LORE_ENTRY_DELETED, + actorId: request.user!.id, + metadata: { + loreType: existing.loreType, + title: existing.title, + }, + targetId: existing.id, + targetType: 'LORE_ENTRY', + worldId: params.data.worldId, + }); + }); + + return { + ok: true, + }; + }, + ); +} diff --git a/apps/api/src/routes/profiles.test.ts b/apps/api/src/routes/profiles.test.ts new file mode 100644 index 0000000..735ca29 --- /dev/null +++ b/apps/api/src/routes/profiles.test.ts @@ -0,0 +1,257 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import Fastify from 'fastify'; + +import type { UserProfileDatabase } from '../lib/user-profiles.js'; +import { registerProfileRoutes } from './profiles.js'; + +const user = { + avatarUrl: null, + bio: 'Builder of small myths.', + createdAt: new Date('2026-08-01T10:00:00.000Z'), + displayName: 'Mira Vale', + hiveUsername: 'mira-vale.dev', + id: 'user-1', + normalizedHiveUsername: 'mira-vale.dev', +}; + +function createDatabase(): UserProfileDatabase { + return { + user: { + async findUnique(args) { + const query = args as { + where?: { normalizedHiveUsername?: string }; + select?: { + contributionDrafts?: { where?: { status?: string } }; + loreEntries?: { where?: { status?: string } }; + }; + }; + + // Honour the nested relation filters the way Prisma would, so that a + // missing `where` in the query surfaces as leaked rows in the response. + const applyStatusFilter = ( + rows: T[], + filter: { status?: string } | undefined, + ) => (filter?.status ? rows.filter((row) => row.status === filter.status) : rows); + + if (query.where?.normalizedHiveUsername !== user.normalizedHiveUsername) { + return null; + } + + return { + ...user, + contributionDrafts: applyStatusFilter( + [ + { + id: 'draft-1', + kind: 'LORE', + proposal: { + id: 'proposal-1', + status: 'VOTING', + submittedAt: new Date('2026-08-03T12:00:00.000Z'), + }, + status: 'SUBMITTED', + submittedAt: new Date('2026-08-03T12:00:00.000Z'), + title: 'The amber gate opens', + updatedAt: new Date('2026-08-03T12:00:00.000Z'), + world: { id: 'world-1', slug: 'ember-city', title: 'Ember City' }, + }, + { + id: 'draft-secret', + kind: 'LORE', + proposal: null, + status: 'DRAFT', + submittedAt: null, + title: 'UNSUBMITTED private draft', + updatedAt: new Date('2026-08-07T12:00:00.000Z'), + world: { id: 'world-1', slug: 'ember-city', title: 'Ember City' }, + }, + ], + query.select?.contributionDrafts?.where, + ), + loreEntries: applyStatusFilter( + [ + { + id: 'entry-1', + loreType: 'LOCATION', + slug: 'amber-gate', + status: 'PUBLISHED_CANON', + title: 'Amber Gate', + updatedAt: new Date('2026-08-04T12:00:00.000Z'), + world: { id: 'world-1', slug: 'ember-city', title: 'Ember City' }, + }, + { + id: 'entry-secret', + loreType: 'LOCATION', + slug: 'unpublished-vault', + status: 'DRAFT', + title: 'UNPUBLISHED private lore', + updatedAt: new Date('2026-08-08T12:00:00.000Z'), + world: { id: 'world-1', slug: 'ember-city', title: 'Ember City' }, + }, + ], + query.select?.loreEntries?.where, + ), + reputationSnapshots: [ + { + breakdown: { signals: { canonizedContributions: 1 } }, + calculatedAt: new Date('2026-08-05T12:00:00.000Z'), + calculationVersion: 'hivelore-reputation-v1', + score: 125, + }, + ], + votes: [ + { + choice: 'APPROVE', + createdAt: new Date('2026-08-06T12:00:00.000Z'), + proposal: { + id: 'proposal-2', + status: 'APPROVED_FOR_PUBLICATION', + title: 'A foundry oath', + world: { id: 'world-1', slug: 'ember-city', title: 'Ember City' }, + }, + }, + ], + }; + }, + }, + }; +} + +async function buildTestApp(database = createDatabase()) { + const app = Fastify(); + await registerProfileRoutes(app, { database }); + + return app; +} + +describe('profile routes', () => { + test('returns reputation, badge, and contribution history for a Hive user', async () => { + const app = await buildTestApp(); + + const response = await app.inject({ + method: 'GET', + url: '/profiles/Mira-Vale.dev', + }); + + assert.equal(response.statusCode, 200); + assert.deepEqual(response.json(), { + history: { + contributions: [ + { + id: 'draft-1', + kind: 'LORE', + proposal: { + id: 'proposal-1', + status: 'VOTING', + submittedAt: '2026-08-03T12:00:00.000Z', + }, + status: 'SUBMITTED', + submittedAt: '2026-08-03T12:00:00.000Z', + title: 'The amber gate opens', + updatedAt: '2026-08-03T12:00:00.000Z', + world: { id: 'world-1', slug: 'ember-city', title: 'Ember City' }, + }, + ], + loreEntries: [ + { + id: 'entry-1', + loreType: 'LOCATION', + slug: 'amber-gate', + status: 'PUBLISHED_CANON', + title: 'Amber Gate', + updatedAt: '2026-08-04T12:00:00.000Z', + world: { id: 'world-1', slug: 'ember-city', title: 'Ember City' }, + }, + ], + votes: [ + { + choice: 'APPROVE', + createdAt: '2026-08-06T12:00:00.000Z', + proposal: { + id: 'proposal-2', + status: 'APPROVED_FOR_PUBLICATION', + title: 'A foundry oath', + world: { id: 'world-1', slug: 'ember-city', title: 'Ember City' }, + }, + }, + ], + }, + reputation: { + breakdown: { signals: { canonizedContributions: 1 } }, + calculatedAt: '2026-08-05T12:00:00.000Z', + calculationVersion: 'hivelore-reputation-v1', + level: { + badge: 'Canon Keeper', + label: 'Canon Keeper', + nextScore: 250, + }, + score: 125, + }, + user: { + avatarUrl: null, + bio: 'Builder of small myths.', + createdAt: '2026-08-01T10:00:00.000Z', + displayName: 'Mira Vale', + hiveUsername: 'mira-vale.dev', + id: 'user-1', + normalizedHiveUsername: 'mira-vale.dev', + }, + }); + }); + + test('never exposes unsubmitted drafts or non-canon lore on the public profile', async () => { + const app = await buildTestApp(); + + const response = await app.inject({ + method: 'GET', + url: '/profiles/mira-vale.dev', + }); + + assert.equal(response.statusCode, 200); + + const body = response.json(); + const serialised = JSON.stringify(body); + + // The endpoint is unauthenticated, so private work must never appear. + assert.ok( + !serialised.includes('UNSUBMITTED private draft'), + 'unsubmitted contribution draft leaked on a public profile', + ); + assert.ok( + !serialised.includes('UNPUBLISHED private lore'), + 'non-canon lore entry leaked on a public profile', + ); + assert.ok(!serialised.includes('draft-secret'), 'unsubmitted draft id leaked'); + assert.ok(!serialised.includes('entry-secret'), 'non-canon lore id leaked'); + + // and the legitimately public rows are still present + assert.ok(serialised.includes('The amber gate opens')); + assert.ok(serialised.includes('Amber Gate')); + }); + + test('returns 404 for an unknown profile', async () => { + const app = await buildTestApp(); + + const response = await app.inject({ + method: 'GET', + url: '/profiles/unknown.dev', + }); + + assert.equal(response.statusCode, 404); + assert.deepEqual(response.json(), { error: 'Profile not found.' }); + }); + + test('rejects invalid Hive usernames', async () => { + const app = await buildTestApp(); + + const response = await app.inject({ + method: 'GET', + url: '/profiles/not_valid', + }); + + assert.equal(response.statusCode, 400); + assert.deepEqual(response.json(), { error: 'Invalid Hive username.' }); + }); +}); diff --git a/apps/api/src/routes/profiles.ts b/apps/api/src/routes/profiles.ts new file mode 100644 index 0000000..8a2b2b5 --- /dev/null +++ b/apps/api/src/routes/profiles.ts @@ -0,0 +1,51 @@ +import type { FastifyInstance } from 'fastify'; +import { z } from 'zod'; + +import { InvalidHiveUsernameError } from '../lib/hive-username.js'; +import { getUserProfile, type UserProfileDatabase } from '../lib/user-profiles.js'; + +const profileParamsSchema = z.object({ + username: z.string().min(1).max(64), +}); + +type RegisterProfileRoutesOptions = { + database?: UserProfileDatabase; +}; + +export async function registerProfileRoutes( + app: FastifyInstance, + options: RegisterProfileRoutesOptions = {}, +) { + const database = + options.database ?? ((await import('../lib/prisma.js')).prisma as UserProfileDatabase); + + app.get('/profiles/:username', async (request, reply) => { + const params = profileParamsSchema.safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + error: 'Invalid profile route.', + }); + } + + try { + const profile = await getUserProfile(database, params.data.username); + + if (!profile) { + return reply.code(404).send({ + error: 'Profile not found.', + }); + } + + return profile; + } catch (error) { + if (error instanceof InvalidHiveUsernameError) { + return reply.code(400).send({ + error: 'Invalid Hive username.', + }); + } + + throw error; + } + }); +} diff --git a/apps/api/src/routes/proposals.test.ts b/apps/api/src/routes/proposals.test.ts new file mode 100644 index 0000000..d3e1548 --- /dev/null +++ b/apps/api/src/routes/proposals.test.ts @@ -0,0 +1,918 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import Fastify from 'fastify'; +import rateLimit from '@fastify/rate-limit'; + +import { env } from '../config/env.js'; +import { + PlatformRole, + ProposalDecisionOutcome, + ProposalStatus, + WorldAuditAction, + WorldRole, +} from '../generated/prisma/enums.js'; +import { signAccessToken } from '../lib/auth-crypto.js'; +import { hashCanonicalJson } from '../lib/canon-voting-policy.js'; +import { HIVELORE_CUSTOM_JSON_ID } from '../lib/hive/constants.js'; +import { buildHiveLoreCustomJsonOperation } from '../lib/hive/operations.js'; +import { PROPOSAL_COMMENT_MAX_LENGTH } from '../lib/proposal-comments.js'; +import { registerProposalRoutes } from './proposals.js'; + +const author = { + hiveUsername: 'mira-vale.dev', + id: 'user-author', + normalizedHiveUsername: 'mira-vale.dev', +}; + +const reader = { + hiveUsername: 'emberquill.dev', + id: 'user-reader', + normalizedHiveUsername: 'emberquill.dev', +}; + +const outsider = { + hiveUsername: 'stranger.dev', + id: 'user-outsider', + normalizedHiveUsername: 'stranger.dev', +}; + +function authHeader(user = reader) { + const token = signAccessToken( + { + hiveUsername: user.hiveUsername, + normalizedHiveUsername: user.normalizedHiveUsername, + platformRole: PlatformRole.USER, + sid: `session-${user.id}`, + sub: user.id, + }, + { + audience: env.AUTH_JWT_AUDIENCE, + issuer: env.AUTH_JWT_ISSUER, + secret: env.AUTH_JWT_SECRET, + ttlSeconds: 900, + }, + ); + + return { + authorization: `Bearer ${token}`, + }; +} + +function now(offsetMs = 0) { + return new Date(new Date('2026-08-10T12:00:00.000Z').getTime() + offsetMs); +} + +const openVotingEndsAt = new Date('2099-08-12T12:00:00.000Z'); + +type StoredComment = { + authorId: string; + body: string; + createdAt: Date; + deletedAt: Date | null; + deletedById: string | null; + id: string; + proposalId: string; +}; + +function encodeCursor(input: { createdAt: string; id: string }) { + return Buffer.from(JSON.stringify(input), 'utf8').toString('base64url'); +} + +const decisionPayload = { + counts: { + alternateTimeline: 0, + approve: 7, + needsRevision: 0, + reject: 3, + total: 10, + }, + eventType: 'canon_decision', + outcome: ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION, + proposalId: 'proposal-1', + worldId: 'world-1', +}; + +function createDecision() { + return { + aiWarningAcknowledged: false, + aiWarningSummary: null, + alternateTimelineCount: 0, + approvalDenominator: 10, + approvalNumerator: 7, + approvalPercentageBps: 7000, + approvalThresholdBps: 7000, + approveCount: 7, + blockchainTimestamp: null, + blockNumber: null, + contentHash: 'content-hash', + createdAt: now(), + customJsonId: HIVELORE_CUSTOM_JSON_ID, + decidedAt: now(), + decisionPayload, + decisionPayloadHash: hashCanonicalJson(decisionPayload), + expectedSigner: 'mira-vale.dev', + hiveEventId: null, + id: 'decision-1', + minimumVotes: 5, + needsRevisionCount: 0, + operationIndex: null, + outcome: ProposalDecisionOutcome.APPROVED_FOR_PUBLICATION, + rejectCount: 3, + rulesVersion: 'canon-voting-mvp-2026-08-12', + totalVotes: 10, + transactionId: null, + updatedAt: now(), + votingWindowHours: 48, + }; +} + +function createConfirmedOperation(transactionId = 'tx-valid') { + return { + blockNumber: BigInt(100), + blockchainTimestamp: new Date('2026-08-12T12:05:00.000Z'), + operation: buildHiveLoreCustomJsonOperation({ + action: 'canon_approval', + entityId: 'decision-1', + entityType: 'CANON_DECISION', + payload: decisionPayload, + proposalId: 'proposal-1', + signer: 'mira-vale.dev', + worldId: 'world-1', + }), + operationIndex: 0, + transactionId, + }; +} + +function createDatabase() { + const decision = createDecision(); + const users = [ + { ...author, avatarUrl: null, displayName: 'Mira Vale' }, + { ...reader, avatarUrl: null, displayName: null }, + { ...outsider, avatarUrl: null, displayName: null }, + ]; + const proposals = [ + { + author: { + hiveUsername: author.hiveUsername, + id: author.id, + }, + authorId: author.id, + decision: null, + id: 'proposal-1', + status: ProposalStatus.VOTING, + votingEndsAt: openVotingEndsAt, + worldId: 'world-1', + }, + { + author: { + hiveUsername: author.hiveUsername, + id: author.id, + }, + authorId: author.id, + decision: null, + id: 'proposal-closed', + status: ProposalStatus.REJECTED, + votingEndsAt: now(-1), + worldId: 'world-1', + }, + { + author: { + hiveUsername: author.hiveUsername, + id: author.id, + }, + authorId: author.id, + decision: null, + id: 'proposal-same-world', + status: ProposalStatus.VOTING, + votingEndsAt: openVotingEndsAt, + worldId: 'world-1', + }, + { + author: { + hiveUsername: author.hiveUsername, + id: author.id, + }, + authorId: author.id, + decision: null, + id: 'proposal-2', + status: ProposalStatus.VOTING, + votingEndsAt: openVotingEndsAt, + worldId: 'world-2', + }, + ]; + const memberships = [ + { + id: 'membership-reader', + revokedAt: null, + role: WorldRole.READER, + userId: reader.id, + worldId: 'world-1', + }, + { + id: 'membership-author', + revokedAt: null, + role: WorldRole.CONTRIBUTOR, + userId: author.id, + worldId: 'world-1', + }, + ]; + const comments: StoredComment[] = []; + const appVotes: unknown[] = []; + const auditLogs: unknown[] = []; + const events: unknown[] = []; + const touchedVotes: string[] = []; + + function includeAuthor(comment: StoredComment) { + const user = users.find((candidate) => candidate.id === comment.authorId)!; + + return { + ...comment, + author: { + avatarUrl: user.avatarUrl, + displayName: user.displayName, + hiveUsername: user.hiveUsername, + id: user.id, + }, + }; + } + + const database = { + appVote: { + async create() { + touchedVotes.push('create'); + }, + async update() { + touchedVotes.push('update'); + }, + async upsert(args: { create: { choice: string; proposalId: string; voterId: string } }) { + touchedVotes.push('upsert'); + const vote = { + ...args.create, + createdAt: now(), + id: `vote-${touchedVotes.length}`, + updatedAt: now(), + }; + appVotes.push(vote); + return vote; + }, + }, + proposal: { + async findFirst(args: { where: { id: string; worldId: string } }) { + return ( + proposals.find( + (proposal) => proposal.id === args.where.id && proposal.worldId === args.where.worldId, + ) ?? null + ); + }, + }, + proposalComment: { + async count(args: { where: { deletedAt?: null; proposalId: string } }) { + return comments.filter( + (comment) => + comment.proposalId === args.where.proposalId && + (!('deletedAt' in args.where) || comment.deletedAt === args.where.deletedAt), + ).length; + }, + async create(args: { data: { authorId: string; body: string; proposalId: string } }) { + const comment = { + ...args.data, + createdAt: now(comments.length), + deletedAt: null, + deletedById: null, + id: `comment-${comments.length + 1}`, + }; + comments.push(comment); + return includeAuthor(comment); + }, + async findMany(args: { + orderBy: unknown; + take: number; + where: { + OR?: Array<{ + createdAt: Date | { gt: Date }; + id?: { gt: string }; + }>; + proposalId: string; + }; + }) { + return comments + .filter((comment) => comment.proposalId === args.where.proposalId) + .filter((comment) => { + if (!args.where.OR) { + return true; + } + + return args.where.OR.some((condition) => { + if ( + condition.createdAt instanceof Date && + condition.id && + comment.createdAt.getTime() === condition.createdAt.getTime() + ) { + return comment.id > condition.id.gt; + } + + if ( + typeof condition.createdAt === 'object' && + 'gt' in condition.createdAt && + condition.createdAt.gt instanceof Date + ) { + return comment.createdAt.getTime() > condition.createdAt.gt.getTime(); + } + + return false; + }); + }) + .sort((left, right) => { + const createdAtOrder = left.createdAt.getTime() - right.createdAt.getTime(); + + if (createdAtOrder !== 0) { + return createdAtOrder; + } + + return left.id.localeCompare(right.id); + }) + .slice(0, args.take) + .map(includeAuthor); + }, + }, + proposalDecision: { + async findUnique(args: { where: { id: string } }) { + return args.where.id === decision.id ? decision : null; + }, + async update(args: { data: Record }) { + Object.assign(decision, args.data); + return decision; + }, + async updateMany(args: { + data: Record; + where: { + hiveEventId: null; + id: string; + operationIndex: null; + transactionId: null; + }; + }) { + if ( + args.where.id === decision.id && + decision.hiveEventId === null && + decision.operationIndex === null && + decision.transactionId === null + ) { + Object.assign(decision, args.data); + return { count: 1 }; + } + + return { count: 0 }; + }, + }, + hiveEvent: { + async upsert(args: { + create: { operationIndex: number; transactionId: string }; + update: Record; + where: { transactionId_operationIndex: { operationIndex: number; transactionId: string } }; + }) { + const existing = events.find( + (event) => + (event as { operationIndex: number; transactionId: string }).operationIndex === + args.where.transactionId_operationIndex.operationIndex && + (event as { operationIndex: number; transactionId: string }).transactionId === + args.where.transactionId_operationIndex.transactionId, + ); + + if (existing) { + Object.assign(existing, args.update); + return existing; + } + + const event = { + id: `event-${events.length + 1}`, + ...args.create, + }; + events.push(event); + return event; + }, + }, + refreshSession: { + async findUnique(args: { where: { id: string } }) { + if (!args.where.id.startsWith('session-')) { + return null; + } + + return { + expiresAt: new Date(Date.now() + 60 * 60 * 1000), + revokedAt: null, + userId: args.where.id.replace('session-', ''), + }; + }, + }, + worldMembership: { + async findUnique(args: { + where: { worldId_userId: { userId: string; worldId: string }; revokedAt: null }; + }) { + return ( + memberships.find( + (membership) => + membership.userId === args.where.worldId_userId.userId && + membership.worldId === args.where.worldId_userId.worldId && + !membership.revokedAt, + ) ?? null + ); + }, + }, + worldAuditLog: { + async create(args: { data: unknown }) { + auditLogs.push(args.data); + return args.data; + }, + }, + $transaction(callback: (transaction: unknown) => Promise) { + return callback(database); + }, + }; + + return { + appVotes, + auditLogs, + comments, + database, + decision, + events, + memberships, + proposals, + touchedVotes, + }; +} + +async function createApp( + database: ReturnType['database'], + options: Parameters[1] = {}, +) { + const app = Fastify(); + await app.register(rateLimit, { + global: false, + }); + await registerProposalRoutes(app, { + database: database as never, + ...options, + }); + return app; +} + +function attachConfirmedDecision(state: ReturnType) { + (state.proposals[0] as { decision: ReturnType | null }).decision = + state.decision; +} + +describe('proposal comment routes', () => { + test('authenticated eligible user can create a trimmed comment without creating votes or trusting protected fields', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + + const protectedFieldResponse = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + authorId: author.id, + body: 'Nope', + createdAt: '2026-08-10T00:00:00.000Z', + role: WorldRole.CURATOR, + }, + url: '/worlds/world-1/proposals/proposal-1/comments', + }); + const response = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + body: ' \nUseful note. ', + }, + url: '/worlds/world-1/proposals/proposal-1/comments', + }); + + assert.equal(protectedFieldResponse.statusCode, 400); + assert.equal(response.statusCode, 201); + assert.equal(response.json().comment.authorId, reader.id); + assert.equal(response.json().comment.body, '\nUseful note.'); + assert.equal(state.comments.length, 1); + assert.equal(state.comments[0]?.proposalId, 'proposal-1'); + assert.equal(state.comments[0]?.authorId, reader.id); + assert.equal(state.touchedVotes.length, 0); + assert.equal(state.appVotes.length, 0); + await app.close(); + }); + + test('rejects unauthenticated, unauthorized, empty, whitespace, oversized, unknown, and world-mismatched comment writes', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + + const unauthenticated = await app.inject({ + method: 'POST', + payload: { body: 'Hello' }, + url: '/worlds/world-1/proposals/proposal-1/comments', + }); + const forbidden = await app.inject({ + headers: authHeader(outsider), + method: 'POST', + payload: { body: 'Hello' }, + url: '/worlds/world-1/proposals/proposal-1/comments', + }); + const empty = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { body: '' }, + url: '/worlds/world-1/proposals/proposal-1/comments', + }); + const whitespace = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { body: ' \n\t' }, + url: '/worlds/world-1/proposals/proposal-1/comments', + }); + const maxLength = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { body: 'x'.repeat(PROPOSAL_COMMENT_MAX_LENGTH) }, + url: '/worlds/world-1/proposals/proposal-1/comments', + }); + const oversized = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { body: 'x'.repeat(PROPOSAL_COMMENT_MAX_LENGTH + 1) }, + url: '/worlds/world-1/proposals/proposal-1/comments', + }); + const missingProposal = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { body: 'Hello' }, + url: '/worlds/world-1/proposals/missing/comments', + }); + const wrongWorld = await app.inject({ + headers: authHeader(author), + method: 'POST', + payload: { body: 'Hello' }, + url: '/worlds/world-2/proposals/proposal-1/comments', + }); + + assert.equal(unauthenticated.statusCode, 401); + assert.equal(forbidden.statusCode, 403); + assert.equal(empty.statusCode, 400); + assert.equal(whitespace.statusCode, 400); + assert.equal(maxLength.statusCode, 201); + assert.equal(oversized.statusCode, 400); + assert.equal(missingProposal.statusCode, 404); + assert.equal(wrongWorld.statusCode, 403, wrongWorld.body); + assert.equal(state.comments.length, 1); + await app.close(); + }); + + test('comments are readable in deterministic pages, scoped to the proposal, and deleted bodies are tombstoned', async () => { + const state = createDatabase(); + const sharedCreatedAt = now(); + state.comments.push( + { + authorId: reader.id, + body: 'First', + createdAt: sharedCreatedAt, + deletedAt: null, + deletedById: null, + id: 'comment-a', + proposalId: 'proposal-1', + }, + { + authorId: author.id, + body: 'Hidden body', + createdAt: sharedCreatedAt, + deletedAt: now(10), + deletedById: author.id, + id: 'comment-b', + proposalId: 'proposal-1', + }, + { + authorId: reader.id, + body: 'Other proposal', + createdAt: now(20), + deletedAt: null, + deletedById: null, + id: 'comment-c', + proposalId: 'proposal-2', + }, + ); + const app = await createApp(state.database); + + const firstPage = await app.inject({ + method: 'GET', + url: '/worlds/world-1/proposals/proposal-1/comments?pageSize=1', + }); + const secondPage = await app.inject({ + method: 'GET', + url: `/worlds/world-1/proposals/proposal-1/comments?pageSize=50&cursor=${firstPage.json().pageInfo.nextCursor}`, + }); + const cappedPage = await app.inject({ + method: 'GET', + url: '/worlds/world-1/proposals/proposal-1/comments?pageSize=500', + }); + + assert.equal(firstPage.statusCode, 200); + assert.deepEqual( + firstPage.json().comments.map((comment: { id: string }) => comment.id), + ['comment-a'], + ); + assert.equal(firstPage.json().pageInfo.hasMore, true); + assert.equal(firstPage.json().totalCount, 2); + assert.equal(secondPage.statusCode, 200); + assert.deepEqual( + secondPage + .json() + .comments.map((comment: { body: string | null; id: string }) => [comment.id, comment.body]), + [['comment-b', null]], + ); + assert.equal(secondPage.json().comments[0].isDeleted, true); + assert.equal(secondPage.json().comments[0].body, null); + assert.equal(secondPage.json().pageInfo.hasMore, false); + assert.equal(secondPage.json().pageInfo.nextCursor, null); + assert.equal(secondPage.json().totalCount, 2); + assert.equal(cappedPage.json().comments.length, 2); + assert.equal(cappedPage.json().totalCount, 2); + assert.equal(cappedPage.json().pageInfo.hasMore, false); + await app.close(); + }); + + test('comment write rate limit is per authenticated user across proposals and does not affect reads or votes', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + + for (let index = 0; index < 5; index += 1) { + const response = await app.inject({ + headers: authHeader(reader), + method: 'POST', + payload: { body: `Allowed comment ${index}` }, + url: + index === 4 + ? '/worlds/world-1/proposals/proposal-same-world/comments' + : '/worlds/world-1/proposals/proposal-1/comments', + }); + + assert.equal(response.statusCode, 201); + } + + const limited = await app.inject({ + headers: authHeader(reader), + method: 'POST', + payload: { body: 'This body must not be stored or echoed.' }, + url: '/worlds/world-1/proposals/proposal-same-world/comments', + }); + const otherUser = await app.inject({ + headers: authHeader(author), + method: 'POST', + payload: { body: 'Independent author allowance.' }, + url: '/worlds/world-1/proposals/proposal-1/comments', + }); + const readAfterLimit = await app.inject({ + method: 'GET', + url: '/worlds/world-1/proposals/proposal-1/comments', + }); + const voteAfterLimit = await app.inject({ + headers: authHeader(reader), + method: 'POST', + payload: { choice: 'REJECT' }, + url: '/worlds/world-1/proposals/proposal-1/votes', + }); + + assert.equal(limited.statusCode, 429, limited.body); + assert.equal(limited.json().code, 'COMMENT_RATE_LIMITED'); + assert.equal(limited.json().error.includes('This body'), false); + assert.ok(limited.headers['retry-after']); + assert.equal(state.comments.length, 6); + assert.equal(otherUser.statusCode, 201); + assert.equal(readAfterLimit.statusCode, 200); + assert.equal(voteAfterLimit.statusCode, 200, voteAfterLimit.body); + assert.equal(state.appVotes.length, 1); + await app.close(); + }); + + test('malformed cursors and world mismatches are rejected safely while closed proposal comments remain readable and writable', async () => { + const state = createDatabase(); + state.comments.push({ + authorId: reader.id, + body: 'Still readable', + createdAt: now(), + deletedAt: null, + deletedById: null, + id: 'comment-closed', + proposalId: 'proposal-closed', + }); + const app = await createApp(state.database); + + const malformedCursor = await app.inject({ + method: 'GET', + url: '/worlds/world-1/proposals/proposal-1/comments?cursor=not-a-cursor', + }); + const mismatchedRead = await app.inject({ + method: 'GET', + url: '/worlds/world-2/proposals/proposal-1/comments', + }); + const closedRead = await app.inject({ + method: 'GET', + url: `/worlds/world-1/proposals/proposal-closed/comments?cursor=${encodeCursor({ + createdAt: new Date('2020-01-01T00:00:00.000Z').toISOString(), + id: 'comment-0', + })}`, + }); + const closedWrite = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { body: 'Comment after the vote window.' }, + url: '/worlds/world-1/proposals/proposal-closed/comments', + }); + + assert.equal(malformedCursor.statusCode, 400); + assert.deepEqual(malformedCursor.json(), { + code: 'INVALID_COMMENT_CURSOR', + error: 'Invalid comment cursor.', + }); + assert.notEqual(malformedCursor.json().error, 'Bad Request'); + assert.equal('statusCode' in malformedCursor.json(), false); + assert.equal('message' in malformedCursor.json(), false); + assert.equal(mismatchedRead.statusCode, 404); + assert.equal(closedRead.statusCode, 200); + assert.equal(closedRead.json().comments[0].body, 'Still readable'); + assert.equal(closedWrite.statusCode, 201); + assert.equal(state.touchedVotes.length, 0); + await app.close(); + }); +}); + +describe('proposal route async error mapping', () => { + test('async canon voting errors use the application error response body', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + + const closedVote = await app.inject({ + headers: authHeader(reader), + method: 'POST', + payload: { choice: 'REJECT' }, + url: '/worlds/world-1/proposals/proposal-closed/votes', + }); + + assert.equal(closedVote.statusCode, 409); + assert.deepEqual(closedVote.json(), { + code: 'PROPOSAL_NOT_VOTING', + error: 'Proposal is not open for voting.', + }); + assert.notEqual(closedVote.json().error, 'Conflict'); + assert.equal('statusCode' in closedVote.json(), false); + assert.equal('message' in closedVote.json(), false); + await app.close(); + }); +}); + +describe('canon transaction confirmation route', () => { + test('rejects unauthenticated confirmation before lookup or mutation', async () => { + const state = createDatabase(); + attachConfirmedDecision(state); + let lookups = 0; + const app = await createApp(state.database, { + hiveBroadcaster: { + async confirmTransactionOperation() { + lookups += 1; + return createConfirmedOperation(); + }, + } as never, + }); + + const response = await app.inject({ + method: 'POST', + payload: { + operationIndex: 0, + transactionId: 'tx-valid', + }, + url: '/worlds/world-1/proposals/proposal-1/canon-transaction/confirm', + }); + + assert.equal(response.statusCode, 401); + assert.equal(lookups, 0); + assert.equal(state.decision.transactionId, null); + assert.equal(state.events.length, 0); + assert.equal(state.auditLogs.length, 0); + await app.close(); + }); + + test('rejects unrelated and insufficient-role users with typed authorization bodies', async () => { + const state = createDatabase(); + attachConfirmedDecision(state); + let lookups = 0; + const app = await createApp(state.database, { + hiveBroadcaster: { + async confirmTransactionOperation() { + lookups += 1; + return createConfirmedOperation(); + }, + } as never, + }); + + const unrelated = await app.inject({ + headers: authHeader(reader), + method: 'POST', + payload: { + operationIndex: 0, + transactionId: 'tx-valid', + }, + url: '/worlds/world-1/proposals/proposal-1/canon-transaction/confirm', + }); + state.memberships.find((membership) => membership.userId === author.id)!.role = + WorldRole.READER; + const insufficientRole = await app.inject({ + headers: authHeader(author), + method: 'POST', + payload: { + operationIndex: 0, + transactionId: 'tx-valid', + }, + url: '/worlds/world-1/proposals/proposal-1/canon-transaction/confirm', + }); + + assert.equal(unrelated.statusCode, 403); + assert.deepEqual(unrelated.json(), { + code: 'INSUFFICIENT_WORLD_PERMISSIONS', + error: 'Insufficient world permissions.', + }); + assert.equal(insufficientRole.statusCode, 403); + assert.deepEqual(insufficientRole.json(), { + code: 'INSUFFICIENT_WORLD_PERMISSIONS', + error: 'Insufficient world permissions.', + }); + assert.equal(lookups, 0); + assert.equal(state.decision.transactionId, null); + assert.equal(state.events.length, 0); + assert.equal(state.auditLogs.length, 0); + await app.close(); + }); + + test('rejects spoofed actor identity from request data', async () => { + const state = createDatabase(); + attachConfirmedDecision(state); + let lookups = 0; + const app = await createApp(state.database, { + hiveBroadcaster: { + async confirmTransactionOperation() { + lookups += 1; + return createConfirmedOperation(); + }, + } as never, + }); + + const response = await app.inject({ + headers: authHeader(reader), + method: 'POST', + payload: { + actorId: author.id, + operationIndex: 0, + transactionId: 'tx-valid', + }, + url: '/worlds/world-1/proposals/proposal-1/canon-transaction/confirm', + }); + + assert.equal(response.statusCode, 400); + assert.equal(response.json().code, 'INVALID_CONFIRMATION_PAYLOAD'); + assert.equal(lookups, 0); + assert.equal(state.decision.transactionId, null); + assert.equal(state.events.length, 0); + assert.equal(state.auditLogs.length, 0); + await app.close(); + }); + + test('authorized proposal author can confirm a matching canon transaction', async () => { + const state = createDatabase(); + attachConfirmedDecision(state); + const app = await createApp(state.database, { + hiveBroadcaster: { + async confirmTransactionOperation() { + return createConfirmedOperation('tx-valid'); + }, + } as never, + }); + + const response = await app.inject({ + headers: authHeader(author), + method: 'POST', + payload: { + operationIndex: 0, + transactionId: 'tx-valid', + }, + url: '/worlds/world-1/proposals/proposal-1/canon-transaction/confirm', + }); + + assert.equal(response.statusCode, 200, response.body); + assert.equal(response.json().decision.transactionId, 'tx-valid'); + assert.equal(response.json().idempotent, false); + assert.equal(state.decision.transactionId, 'tx-valid'); + assert.equal(state.events.length, 1); + assert.equal(state.auditLogs.length, 1); + assert.equal( + (state.auditLogs[0] as { action: WorldAuditAction }).action, + WorldAuditAction.CANON_DECISION_CONFIRMED, + ); + await app.close(); + }); +}); diff --git a/apps/api/src/routes/proposals.ts b/apps/api/src/routes/proposals.ts new file mode 100644 index 0000000..fdacb82 --- /dev/null +++ b/apps/api/src/routes/proposals.ts @@ -0,0 +1,588 @@ +import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; +import { z } from 'zod'; + +import { env } from '../config/env.js'; +import { authenticateRequest, requireSession } from '../lib/auth-middleware.js'; +import { + acknowledgeProposalAiWarning, + CanonVotingError, + castCanonVote, + confirmCanonTransaction, + createCanonTransactionOperation, + finalizeCanonDecision, + getProposalDetail, + getVoteSummary, +} from '../lib/canon-voting.js'; +import { HafClient } from '../lib/hive/haf-client.js'; +import { prisma } from '../lib/prisma.js'; +import { + createProposalComment, + listProposalComments, + ProposalCommentError, + PROPOSAL_COMMENT_MAX_LENGTH, +} from '../lib/proposal-comments.js'; +import { + ProposalConsistencyError, + runProposalConsistencyCheck, +} from '../lib/proposal-consistency.js'; +import { authorizeWorldPermission } from '../lib/world-authorization.js'; +import type { WorldMembershipLookup } from '../lib/world-authorization.js'; +import { roleHasWorldPermission, WORLD_PERMISSIONS } from '../lib/world-permissions.js'; +import { createHiveReliableBroadcaster } from '../lib/hive/client.js'; +import { + HiveBroadcastError, + type HiveReliableBroadcaster, +} from '../lib/hive/broadcast-reliability.js'; + +const paramsSchema = z.object({ + proposalId: z.string().min(1), + worldId: z.string().min(1), +}); + +const voteBodySchema = z + .object({ + choice: z.enum(['APPROVE', 'REJECT', 'NEEDS_REVISION', 'ALTERNATE_TIMELINE']), + }) + .strict(); + +const commentsQuerySchema = z.object({ + cursor: z.string().min(1).optional(), + pageSize: z.coerce.number().int().positive().optional(), +}); + +const commentBodySchema = z + .object({ + body: z.string().max(PROPOSAL_COMMENT_MAX_LENGTH + 1), + }) + .strict(); + +const confirmBodySchema = z + .object({ + blockNumber: z.coerce.number().int().positive().optional(), + operationIndex: z.coerce.number().int().nonnegative().optional(), + transactionId: z.string().trim().min(1).max(128), + }) + .strict(); + +type RegisterProposalRoutesOptions = { + database?: typeof prisma & WorldMembershipLookup; + hafClient?: HafClient; + hiveBroadcaster?: HiveReliableBroadcaster; +}; + +function authOptions(database: typeof prisma) { + return { + audience: env.AUTH_JWT_AUDIENCE, + database, + issuer: env.AUTH_JWT_ISSUER, + jwtSecret: env.AUTH_JWT_SECRET, + }; +} + +function handleCanonVotingError(error: unknown, reply: FastifyReply) { + if (error instanceof CanonVotingError) { + return reply.code(error.statusCode).send({ + code: error.code, + error: error.message, + }); + } + + if (error instanceof HiveBroadcastError) { + const statusCode = hiveBroadcastStatusCode(error); + + return reply.code(statusCode).send({ + code: error.code, + error: error.message, + }); + } + + throw error; +} + +function hiveBroadcastStatusCode(error: HiveBroadcastError) { + if (error.code === 'BROADCAST_REJECTED' || error.code === 'PERMANENT_TRANSACTION_ERROR') { + return 400; + } + + if (error.code === 'TRANSACTION_EXPIRED') { + return 409; + } + + if (error.code === 'NETWORK_CONFIGURATION_ERROR' || error.code === 'NETWORK_MISMATCH') { + return 503; + } + + return 408; +} + +function handleProposalCommentError(error: unknown, reply: FastifyReply) { + if (error instanceof ProposalCommentError) { + return reply.code(error.statusCode).send({ + code: error.code, + error: error.message, + }); + } + + throw error; +} + +function handleProposalConsistencyError(error: unknown, reply: FastifyReply) { + if (error instanceof ProposalConsistencyError) { + return reply.code(error.statusCode).send({ + code: error.code, + error: error.message, + }); + } + + throw error; +} + +function proposalCommentRateLimitOptions(database: typeof prisma) { + return { + cache: env.PROPOSAL_COMMENT_WRITE_RATE_LIMIT_CACHE, + errorResponseBuilder: () => ({ + code: 'COMMENT_RATE_LIMITED', + error: 'Too many proposal comments. Try again later.', + statusCode: 429, + }), + keyGenerator: async (request: FastifyRequest) => { + const user = await authenticateRequest(request, authOptions(database)); + + return user ? `proposal-comments:user:${user.id}` : `proposal-comments:ip:${request.ip}`; + }, + max: env.PROPOSAL_COMMENT_WRITE_RATE_LIMIT_MAX, + timeWindow: `${env.PROPOSAL_COMMENT_WRITE_RATE_LIMIT_WINDOW_SECONDS} seconds`, + }; +} + +function canonTransactionConfirmRateLimitOptions(database: typeof prisma) { + return { + cache: env.PROPOSAL_COMMENT_WRITE_RATE_LIMIT_CACHE, + errorResponseBuilder: () => ({ + code: 'CANON_TRANSACTION_CONFIRM_RATE_LIMITED', + error: 'Too many canon transaction confirmations. Try again later.', + statusCode: 429, + }), + keyGenerator: async (request: FastifyRequest) => { + const user = await authenticateRequest(request, authOptions(database)); + + return user ? `canon-confirm:user:${user.id}` : `canon-confirm:ip:${request.ip}`; + }, + max: 3, + timeWindow: '60 seconds', + }; +} + +async function authorizeCanonTransactionPermission( + request: FastifyRequest, + reply: FastifyReply, + database: WorldMembershipLookup, + worldId: string, +) { + if (!request.user) { + return false; + } + + const membership = await database.worldMembership.findUnique({ + select: { + id: true, + revokedAt: true, + role: true, + userId: true, + worldId: true, + }, + where: { + revokedAt: null, + worldId_userId: { + userId: request.user.id, + worldId, + }, + }, + }); + + if (!membership || !roleHasWorldPermission(membership.role, WORLD_PERMISSIONS.SUBMIT_PROPOSAL)) { + await reply.code(403).send({ + code: 'INSUFFICIENT_WORLD_PERMISSIONS', + error: 'Insufficient world permissions.', + }); + + return false; + } + + request.worldMembership = membership; + + return true; +} + +export async function registerProposalRoutes( + app: FastifyInstance, + options: RegisterProposalRoutesOptions = {}, +) { + const database = options.database ?? prisma; + const hafClient = options.hafClient ?? new HafClient({ baseUrl: env.HAF_API_URL }); + const hiveBroadcaster = options.hiveBroadcaster ?? createHiveReliableBroadcaster(); + + app.get('/worlds/:worldId/proposals/:proposalId', async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + code: 'INVALID_PROPOSAL_ROUTE', + error: 'Invalid proposal route.', + }); + } + + const currentUser = await authenticateRequest(request, authOptions(database)); + + try { + const proposal = await getProposalDetail(database, { + ...(currentUser ? { currentUserId: currentUser.id } : {}), + proposalId: params.data.proposalId, + worldId: params.data.worldId, + }); + + return { + proposal, + }; + } catch (error) { + return handleCanonVotingError(error, reply); + } + }); + + app.get('/worlds/:worldId/proposals/:proposalId/votes/summary', async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + code: 'INVALID_PROPOSAL_ROUTE', + error: 'Invalid proposal route.', + }); + } + + try { + return await getVoteSummary(database, params.data); + } catch (error) { + return handleCanonVotingError(error, reply); + } + }); + + app.post( + '/worlds/:worldId/proposals/:proposalId/ai-consistency', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + code: 'INVALID_PROPOSAL_ROUTE', + error: 'Invalid proposal route.', + }); + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + database, + ); + + if (!authorized) { + return; + } + + try { + return await runProposalConsistencyCheck(database, params.data); + } catch (error) { + return handleProposalConsistencyError(error, reply); + } + }, + ); + + app.get('/worlds/:worldId/proposals/:proposalId/comments', async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + const query = commentsQuerySchema.safeParse(request.query); + + if (!params.success || !query.success) { + return reply.code(400).send({ + code: 'INVALID_COMMENT_QUERY', + error: 'Invalid comment query.', + }); + } + + try { + return await listProposalComments(database, { + cursor: query.data.cursor, + pageSize: query.data.pageSize, + proposalId: params.data.proposalId, + worldId: params.data.worldId, + }); + } catch (error) { + return handleProposalCommentError(error, reply); + } + }); + + app.post( + '/worlds/:worldId/proposals/:proposalId/comments', + { + preHandler: [ + app.rateLimit(proposalCommentRateLimitOptions(database)), + requireSession(authOptions(database)), + ], + }, + async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + const body = commentBodySchema.safeParse(request.body); + + if (!params.success || !body.success) { + return reply.code(400).send({ + code: 'INVALID_COMMENT_PAYLOAD', + error: 'Invalid comment payload.', + }); + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + database, + ); + + if (!authorized || !request.user) { + return; + } + + try { + const result = await createProposalComment(database, { + authorId: request.user.id, + body: body.data.body, + proposalId: params.data.proposalId, + worldId: params.data.worldId, + }); + + return reply.code(201).send(result); + } catch (error) { + return handleProposalCommentError(error, reply); + } + }, + ); + + app.post( + '/worlds/:worldId/proposals/:proposalId/votes', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + const body = voteBodySchema.safeParse(request.body); + + if (!params.success || !body.success) { + return reply.code(400).send({ + code: 'INVALID_VOTE_PAYLOAD', + error: 'Invalid vote payload.', + }); + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.VOTE_ON_PROPOSAL, + database, + ); + + if (!authorized || !request.user) { + return; + } + + try { + return await castCanonVote(database, { + choice: body.data.choice, + proposalId: params.data.proposalId, + voterId: request.user.id, + worldId: params.data.worldId, + }); + } catch (error) { + return handleCanonVotingError(error, reply); + } + }, + ); + + app.post( + '/worlds/:worldId/proposals/:proposalId/ai-warning/acknowledge', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + code: 'INVALID_PROPOSAL_ROUTE', + error: 'Invalid proposal route.', + }); + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.COMMENT_ON_AI_WARNING, + database, + ); + + if (!authorized || !request.user) { + return; + } + + try { + return await acknowledgeProposalAiWarning(database, { + actorId: request.user.id, + proposalId: params.data.proposalId, + worldId: params.data.worldId, + }); + } catch (error) { + return handleCanonVotingError(error, reply); + } + }, + ); + + app.post( + '/worlds/:worldId/proposals/:proposalId/finalize', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + code: 'INVALID_PROPOSAL_ROUTE', + error: 'Invalid proposal route.', + }); + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.EXECUTE_CANON_STATUS_AFTER_THRESHOLD, + database, + ); + + if (!authorized || !request.user) { + return; + } + + try { + return await finalizeCanonDecision(database, { + actorId: request.user.id, + proposalId: params.data.proposalId, + worldId: params.data.worldId, + }); + } catch (error) { + return handleCanonVotingError(error, reply); + } + }, + ); + + app.post( + '/worlds/:worldId/proposals/:proposalId/canon-transaction', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + code: 'INVALID_PROPOSAL_ROUTE', + error: 'Invalid proposal route.', + }); + } + + if (!request.user) { + return reply.code(401).send({ + code: 'AUTHENTICATION_REQUIRED', + error: 'Authentication required.', + }); + } + + const authorized = await authorizeCanonTransactionPermission( + request, + reply, + database, + params.data.worldId, + ); + + if (!authorized) { + return; + } + + try { + return await createCanonTransactionOperation(database, { + proposalId: params.data.proposalId, + signerId: request.user.id, + worldId: params.data.worldId, + }); + } catch (error) { + return handleCanonVotingError(error, reply); + } + }, + ); + + app.post( + '/worlds/:worldId/proposals/:proposalId/canon-transaction/confirm', + { + preHandler: [ + app.rateLimit(canonTransactionConfirmRateLimitOptions(database)), + requireSession(authOptions(database)), + ], + }, + async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + const body = confirmBodySchema.safeParse(request.body); + + if (!params.success || !body.success) { + return reply.code(400).send({ + code: 'INVALID_CONFIRMATION_PAYLOAD', + error: 'Invalid canon transaction confirmation payload.', + }); + } + + if (!request.user) { + return reply.code(401).send({ + code: 'AUTHENTICATION_REQUIRED', + error: 'Authentication required.', + }); + } + + const authorized = await authorizeCanonTransactionPermission( + request, + reply, + database, + params.data.worldId, + ); + + if (!authorized) { + return; + } + + try { + return await confirmCanonTransaction(database, { + ...body.data, + actorId: request.user.id, + hafClient, + hiveBroadcaster, + proposalId: params.data.proposalId, + worldId: params.data.worldId, + }); + } catch (error) { + return handleCanonVotingError(error, reply); + } + }, + ); +} diff --git a/apps/api/src/routes/search.ts b/apps/api/src/routes/search.ts new file mode 100644 index 0000000..6196174 --- /dev/null +++ b/apps/api/src/routes/search.ts @@ -0,0 +1,45 @@ +import type { FastifyInstance } from 'fastify'; +import { z } from 'zod'; + +import { SearchEntityType } from '../generated/prisma/enums.js'; +import { prisma } from '../lib/prisma.js'; +import { searchWorldLore } from '../lib/search-index.js'; + +const searchQuerySchema = z.object({ + page: z.coerce.number().int().positive().optional(), + pageSize: z.coerce.number().int().positive().max(50).optional(), + q: z.string().trim().min(1).max(120), + type: z.enum([SearchEntityType.WORLD, SearchEntityType.LORE_ENTRY]).optional(), + worldId: z.string().trim().min(1).optional(), +}); + +type RegisterSearchRoutesOptions = { + database?: typeof prisma; +}; + +export async function registerSearchRoutes( + app: FastifyInstance, + options: RegisterSearchRoutesOptions = {}, +) { + const database = options.database ?? prisma; + + app.get('/search', async (request, reply) => { + const query = searchQuerySchema.safeParse(request.query); + + if (!query.success) { + return reply.code(400).send({ + code: 'INVALID_SEARCH_QUERY', + error: 'Invalid search query.', + }); + } + + try { + return await searchWorldLore(database, query.data); + } catch (error) { + return reply.code(400).send({ + code: 'INVALID_SEARCH_QUERY', + error: error instanceof Error ? error.message : 'Invalid search query.', + }); + } + }); +} diff --git a/apps/api/src/routes/worlds.test.ts b/apps/api/src/routes/worlds.test.ts new file mode 100644 index 0000000..e28f5f6 --- /dev/null +++ b/apps/api/src/routes/worlds.test.ts @@ -0,0 +1,1075 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import Fastify from 'fastify'; + +import { env } from '../config/env.js'; +import { + LoreStatus, + PlatformRole, + ProposalStatus, + WorldAuditAction, + WorldRole, +} from '../generated/prisma/enums.js'; +import { signAccessToken } from '../lib/auth-crypto.js'; +import { createWorld, updateWorld } from '../lib/worlds.js'; +import { registerWorldRoutes } from './worlds.js'; + +const founder = { + avatarUrl: null, + displayName: 'Ember Quill', + hiveUsername: 'emberquill.dev', + id: 'user-1', + normalizedHiveUsername: 'emberquill.dev', +}; + +const contributor = { + avatarUrl: null, + displayName: 'Mira Vale', + hiveUsername: 'mira-vale.dev', + id: 'user-2', + normalizedHiveUsername: 'mira-vale.dev', +}; + +function authHeader(userId = founder.id) { + const token = signAccessToken( + { + hiveUsername: founder.hiveUsername, + normalizedHiveUsername: founder.normalizedHiveUsername, + platformRole: PlatformRole.USER, + sid: `session-${userId}`, + sub: userId, + }, + { + audience: env.AUTH_JWT_AUDIENCE, + issuer: env.AUTH_JWT_ISSUER, + secret: env.AUTH_JWT_SECRET, + ttlSeconds: 900, + }, + ); + + return { + authorization: `Bearer ${token}`, + }; +} + +type StoredWorld = { + id: string; + slug: string; + title: string; + description: string; + founderId: string; + founder: typeof founder; + createdAt: Date; + updatedAt: Date; +}; + +type StoredWorldSeed = { + id: string; + worldId: string; + premise: string; + genre: string; + tone: string; + mainConflict: string; + startingLocation: string | null; + firstCharacters: unknown; + firstFactions: unknown; + firstHistoricalEvent: string | null; + createdAt: Date; + updatedAt: Date; +}; + +type StoredBibleVersion = { + id: string; + worldId: string; + versionNumber: number; + creatorId: string; + content: unknown; + changeSummary: string | null; + publishedAt: Date | null; + hiveReferenceId: string | null; + createdAt: Date; + updatedAt: Date; +}; + +function createWorldRecord(input: { + id: string; + slug: string; + title: string; + description: string; + founderId?: string; +}): StoredWorld { + return { + createdAt: new Date('2026-08-05T00:00:00.000Z'), + description: input.description, + founder: input.founderId === contributor.id ? contributor : founder, + founderId: input.founderId ?? founder.id, + id: input.id, + slug: input.slug, + title: input.title, + updatedAt: new Date('2026-08-05T00:00:00.000Z'), + }; +} + +function createDatabase() { + const worlds: StoredWorld[] = []; + const seeds: StoredWorldSeed[] = []; + const bibleVersions: StoredBibleVersion[] = []; + const searchIndexes: unknown[] = []; + const memberships: Array<{ + id: string; + worldId: string; + userId: string; + role: WorldRole; + revokedAt: Date | null; + }> = []; + const auditLogs: unknown[] = []; + const loreEntries: Array<{ + id: string; + worldId: string; + title: string; + slug: string; + loreType: string; + status: LoreStatus; + updatedAt: Date; + }> = []; + const proposals: Array<{ + id: string; + worldId: string; + status: ProposalStatus; + }> = []; + let failNextAuditCreate = false; + let failNextSeedCreate = false; + let failNextWorldCreateWithSlugConflict = false; + + function cloneState() { + return { + auditLogs: [...auditLogs], + bibleVersions: bibleVersions.map((version) => ({ ...version })), + memberships: memberships.map((membership) => ({ ...membership })), + seeds: seeds.map((seed) => ({ ...seed })), + worlds: worlds.map((world) => ({ ...world })), + }; + } + + function restoreState(snapshot: ReturnType) { + auditLogs.splice(0, auditLogs.length, ...snapshot.auditLogs); + bibleVersions.splice(0, bibleVersions.length, ...snapshot.bibleVersions); + memberships.splice(0, memberships.length, ...snapshot.memberships); + seeds.splice(0, seeds.length, ...snapshot.seeds); + worlds.splice(0, worlds.length, ...snapshot.worlds); + } + + function matchesTextFilter(value: string, filter?: { contains?: string; equals?: string }) { + if (!filter) { + return true; + } + + if (filter.contains) { + return value.toLowerCase().includes(filter.contains.toLowerCase()); + } + + if (filter.equals) { + return value.toLowerCase() === filter.equals.toLowerCase(); + } + + return true; + } + + function matchesWorldWhere( + world: StoredWorld, + where?: { + OR?: Array<{ title?: { contains: string }; description?: { contains: string } }>; + seed?: { genre?: { equals: string }; tone?: { equals: string } }; + }, + ) { + if (!where) { + return true; + } + + if ( + where.OR && + !where.OR.some( + (filter) => + (filter.title ? matchesTextFilter(world.title, filter.title) : false) || + (filter.description ? matchesTextFilter(world.description, filter.description) : false), + ) + ) { + return false; + } + + const seed = seeds.find((candidate) => candidate.worldId === world.id); + + if (where.seed?.genre && !seed) { + return false; + } + + if (seed && !matchesTextFilter(seed.genre, where.seed?.genre)) { + return false; + } + + if (seed && !matchesTextFilter(seed.tone, where.seed?.tone)) { + return false; + } + + return true; + } + + function includeWorld(world: StoredWorld, includeContent = true) { + const versions = bibleVersions + .filter((version) => version.worldId === world.id) + .sort((left, right) => right.versionNumber - left.versionNumber) + .slice(0, 1) + .map((version) => { + if (includeContent) { + return version; + } + + const summary: Partial = { ...version }; + delete summary.content; + return summary; + }); + + return { + ...world, + bibleVersions: versions, + founder: world.founder, + seed: seeds.find((seed) => seed.worldId === world.id) ?? null, + }; + } + + const database = { + async $transaction(this: unknown, callback: (transaction: never) => Promise) { + const snapshot = cloneState(); + + try { + return await callback(this as never); + } catch (error) { + restoreState(snapshot); + throw error; + } + }, + loreEntry: { + async count(args: { where: { worldId: string; status?: LoreStatus } }) { + return loreEntries.filter( + (entry) => + entry.worldId === args.where.worldId && + (!args.where.status || entry.status === args.where.status), + ).length; + }, + async findMany(args: { where: { worldId: string; status?: LoreStatus }; take: number }) { + return loreEntries + .filter( + (entry) => + entry.worldId === args.where.worldId && + (!('status' in args.where) || entry.status === args.where.status), + ) + .slice(0, args.take); + }, + }, + proposal: { + async count(args: { where: { worldId: string; status: { in: ProposalStatus[] } } }) { + return proposals.filter( + (proposal) => + proposal.worldId === args.where.worldId && + args.where.status.in.includes(proposal.status), + ).length; + }, + }, + refreshSession: { + async findUnique(args: { where: { id: string } }) { + const userId = args.where.id.replace(/^session-/, ''); + + return { + expiresAt: new Date(Date.now() + 60 * 60 * 1000), + revokedAt: null, + userId, + }; + }, + }, + searchIndex: { + async deleteMany(args: { where?: { entityId?: string; entityType?: string } } = {}) { + const before = searchIndexes.length; + + for (let index = searchIndexes.length - 1; index >= 0; index -= 1) { + const row = searchIndexes[index] as { entityId?: string; entityType?: string }; + const matchesEntity = !args.where?.entityId || row.entityId === args.where.entityId; + const matchesType = !args.where?.entityType || row.entityType === args.where.entityType; + + if (matchesEntity && matchesType) { + searchIndexes.splice(index, 1); + } + } + + return { count: before - searchIndexes.length }; + }, + async upsert(args: { + create: { entityId: string; entityType: string }; + update: Record; + where: { entityType_entityId: { entityId: string; entityType: string } }; + }) { + const existing = searchIndexes.find( + (row) => + (row as { entityId: string; entityType: string }).entityId === + args.where.entityType_entityId.entityId && + (row as { entityId: string; entityType: string }).entityType === + args.where.entityType_entityId.entityType, + ); + + if (existing) { + Object.assign(existing as Record, args.update); + return existing; + } + + searchIndexes.push(args.create); + return args.create; + }, + }, + world: { + async count(args?: { where?: Parameters[1] }) { + return worlds.filter((world) => matchesWorldWhere(world, args?.where)).length; + }, + async create(args: { + data: { + description: string; + founderId: string; + slug: string; + title: string; + }; + }) { + if (failNextWorldCreateWithSlugConflict) { + failNextWorldCreateWithSlugConflict = false; + throw { + code: 'P2002', + meta: { + target: ['slug'], + }, + }; + } + + if (worlds.some((world) => world.slug === args.data.slug)) { + throw { + code: 'P2002', + meta: { + target: ['slug'], + }, + }; + } + + const world = createWorldRecord({ + description: args.data.description, + founderId: args.data.founderId, + id: `world-${worlds.length + 1}`, + slug: args.data.slug, + title: args.data.title, + }); + worlds.push(world); + return world; + }, + async findMany(args: { + include?: { bibleVersions?: { select?: Record } }; + take: number; + skip: number; + where?: Parameters[1]; + }) { + const includeContent = Boolean(args.include?.bibleVersions?.select?.content); + + return worlds + .filter((world) => matchesWorldWhere(world, args.where)) + .sort((left, right) => { + const createdAtOrder = right.createdAt.getTime() - left.createdAt.getTime(); + + if (createdAtOrder !== 0) { + return createdAtOrder; + } + + return right.id.localeCompare(left.id); + }) + .slice(args.skip, args.skip + args.take) + .map((world) => includeWorld(world, includeContent)); + }, + async findUnique(args: { where: { id?: string; slug?: string } }) { + const world = worlds.find((candidate) => { + if (args.where.id) { + return candidate.id === args.where.id; + } + + return candidate.slug === args.where.slug; + }); + + return world ? includeWorld(world) : null; + }, + async findUniqueOrThrow(args: { where: { id: string } }) { + const world = worlds.find((candidate) => candidate.id === args.where.id); + + if (!world) { + throw new Error('Missing world.'); + } + + return includeWorld(world); + }, + async update(args: { + data: Partial>; + where: { id: string }; + }) { + const world = worlds.find((candidate) => candidate.id === args.where.id); + + if (!world) { + throw new Error('Missing world.'); + } + + Object.assign(world, args.data, { + updatedAt: new Date('2026-08-05T00:01:00.000Z'), + }); + + return world; + }, + }, + worldAuditLog: { + async create(args: { data: unknown }) { + if (failNextAuditCreate) { + failNextAuditCreate = false; + throw new Error('Injected audit failure.'); + } + + auditLogs.push(args.data); + return args.data; + }, + }, + worldBibleVersion: { + async create(args: { + data: { + changeSummary: string; + content: unknown; + creatorId: string; + versionNumber: number; + worldId: string; + }; + }) { + const version = { + ...args.data, + createdAt: new Date('2026-08-05T00:00:00.000Z'), + hiveReferenceId: null, + id: `bible-${bibleVersions.length + 1}`, + publishedAt: null, + updatedAt: new Date('2026-08-05T00:00:00.000Z'), + }; + bibleVersions.push(version); + return version; + }, + async update(args: { + data: Partial>; + where: { id: string }; + }) { + const version = bibleVersions.find((candidate) => candidate.id === args.where.id); + + if (!version) { + throw new Error('Missing bible version.'); + } + + Object.assign(version, args.data, { + updatedAt: new Date('2026-08-05T00:01:00.000Z'), + }); + + return version; + }, + }, + worldMembership: { + async create(args: { + data: { + grantedById: string; + role: WorldRole; + userId: string; + worldId: string; + }; + }) { + const membership = { + id: `membership-${memberships.length + 1}`, + revokedAt: null, + ...args.data, + }; + memberships.push(membership); + return membership; + }, + async findUnique(args: { + where: { worldId_userId: { worldId: string; userId: string }; revokedAt?: null }; + }) { + return ( + memberships.find( + (membership) => + membership.worldId === args.where.worldId_userId.worldId && + membership.userId === args.where.worldId_userId.userId && + !membership.revokedAt, + ) ?? null + ); + }, + }, + worldSeed: { + async create(args: { + data: { + firstCharacters: string[]; + firstFactions: string[]; + firstHistoricalEvent: string | null; + genre: string; + mainConflict: string; + premise: string; + startingLocation: string | null; + tone: string; + worldId: string; + }; + }) { + if (failNextSeedCreate) { + failNextSeedCreate = false; + throw new Error('Injected seed failure.'); + } + + const seed = { + ...args.data, + createdAt: new Date('2026-08-05T00:00:00.000Z'), + id: `seed-${seeds.length + 1}`, + updatedAt: new Date('2026-08-05T00:00:00.000Z'), + }; + seeds.push(seed); + return seed; + }, + async update(args: { data: Partial; where: { worldId: string } }) { + const seed = seeds.find((candidate) => candidate.worldId === args.where.worldId); + + if (!seed) { + throw new Error('Missing seed.'); + } + + Object.assign(seed, args.data, { + updatedAt: new Date('2026-08-05T00:01:00.000Z'), + }); + + return seed; + }, + }, + }; + + return { + auditLogs, + bibleVersions, + database, + loreEntries, + memberships, + proposals, + seeds, + failNextAuditCreate() { + failNextAuditCreate = true; + }, + failNextSeedCreate() { + failNextSeedCreate = true; + }, + failNextWorldCreateWithSlugConflict() { + failNextWorldCreateWithSlugConflict = true; + }, + worlds, + }; +} + +async function createApp(database: ReturnType['database']) { + const app = Fastify(); + await registerWorldRoutes(app, { + database: database as never, + }); + return app; +} + +const worldPayload = { + bible: { + changeSummary: 'Initial bible.', + content: { + rules: ['No false canon.'], + style: 'Mythic', + }, + }, + description: 'A realm of moonlit archives.', + seed: { + firstCharacters: ['Archivist Lume'], + firstFactions: ['Moon Scribes'], + firstHistoricalEvent: 'The first archive opens.', + genre: 'Fantasy', + mainConflict: 'Memory fades whenever the moons align.', + premise: 'A world where moonlight writes history before people can.', + startingLocation: 'The Glass Archive', + tone: 'Mystic wonder', + }, + title: 'Moon Archive', +}; + +describe('world routes', () => { + test('creates a world atomically with seed, initial bible, founder membership, and audit log', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + const response = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: worldPayload, + url: '/worlds', + }); + + assert.equal(response.statusCode, 201); + assert.equal(response.json().world.title, 'Moon Archive'); + assert.equal(response.json().world.seed.genre, 'Fantasy'); + assert.equal(response.json().world.currentBibleVersion.versionNumber, 1); + assert.equal(response.json().world.currentBibleVersion.publishedAt, null); + assert.equal(state.worlds.length, 1); + assert.equal(state.seeds.length, 1); + assert.equal(state.bibleVersions.length, 1); + assert.equal(state.memberships[0]?.role, WorldRole.FOUNDER); + assert.deepEqual(state.auditLogs[0], { + action: WorldAuditAction.ROLE_ASSIGNED, + actorId: founder.id, + metadata: { + role: WorldRole.FOUNDER, + }, + targetId: 'membership-1', + targetType: 'WORLD_MEMBERSHIP', + worldId: 'world-1', + }); + await app.close(); + }); + + test('requires authentication to create a world and ignores client founder role data', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + const response = await app.inject({ + method: 'POST', + payload: { + ...worldPayload, + founderId: contributor.id, + role: WorldRole.CURATOR, + }, + url: '/worlds', + }); + + assert.equal(response.statusCode, 401); + assert.equal(state.worlds.length, 0); + await app.close(); + }); + + test('authenticated creation succeeds and ignores client identity and role fields', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + const response = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + ...worldPayload, + founderId: contributor.id, + role: WorldRole.CURATOR, + }, + url: '/worlds', + }); + + assert.equal(response.statusCode, 201); + assert.equal(response.json().world.founderId, founder.id); + assert.equal(state.memberships[0]?.userId, founder.id); + assert.equal(state.memberships[0]?.role, WorldRole.FOUNDER); + await app.close(); + }); + + test('rejects invalid, null, oversized, and deeply nested world bible content', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + const missingContent = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + ...worldPayload, + bible: { + changeSummary: 'Missing content should not pass as undefined.', + }, + }, + url: '/worlds', + }); + const nullContent = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + ...worldPayload, + bible: { + content: null, + }, + }, + url: '/worlds', + }); + const oversized = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + ...worldPayload, + bible: { + content: { + text: 'x'.repeat(101 * 1024), + }, + }, + }, + url: '/worlds', + }); + let deeplyNested: unknown = 'bottom'; + + for (let depth = 0; depth < 42; depth += 1) { + deeplyNested = { child: deeplyNested }; + } + + const nested = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + ...worldPayload, + bible: { + content: deeplyNested, + }, + }, + url: '/worlds', + }); + + assert.equal(missingContent.statusCode, 400); + assert.equal(nullContent.statusCode, 400); + assert.equal(oversized.statusCode, 400); + assert.equal(nested.statusCode, 400); + assert.equal(state.worlds.length, 0); + await app.close(); + }); + + test('browses, retrieves, and opens a world hub response', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + await app.inject({ + headers: authHeader(), + method: 'POST', + payload: worldPayload, + url: '/worlds', + }); + state.loreEntries.push({ + id: 'lore-1', + loreType: 'CHARACTER', + slug: 'archivist-lume', + status: LoreStatus.PUBLISHED_CANON, + title: 'Archivist Lume', + updatedAt: new Date('2026-08-05T00:02:00.000Z'), + worldId: 'world-1', + }); + state.loreEntries.push({ + id: 'draft-lore', + loreType: 'FACTION', + slug: 'hidden-draft', + status: LoreStatus.DRAFT, + title: 'Hidden Draft', + updatedAt: new Date('2026-08-05T00:03:00.000Z'), + worldId: 'world-1', + }); + state.proposals.push({ + id: 'proposal-1', + status: ProposalStatus.SUBMITTED, + worldId: 'world-1', + }); + + const listResponse = await app.inject({ + method: 'GET', + url: '/worlds?q=moon&page=1&pageSize=10', + }); + const getResponse = await app.inject({ + method: 'GET', + url: '/worlds/world-1', + }); + const hubResponse = await app.inject({ + method: 'GET', + url: '/worlds/world-1/hub', + }); + + assert.equal(listResponse.statusCode, 200); + assert.equal(listResponse.json().pagination.total, 1); + assert.equal('content' in listResponse.json().worlds[0].currentBibleVersion, false); + assert.equal(getResponse.statusCode, 200); + assert.deepEqual( + getResponse.json().world.currentBibleVersion.content, + worldPayload.bible.content, + ); + assert.equal(getResponse.json().world.seed.mainConflict, worldPayload.seed.mainConflict); + assert.equal(hubResponse.statusCode, 200); + assert.equal(hubResponse.json().stats.canonLoreCount, 1); + assert.equal(hubResponse.json().stats.activeProposalCount, 1); + assert.equal('draftLoreCount' in hubResponse.json().stats, false); + assert.equal(hubResponse.json().latestLoreEntries[0].id, 'lore-1'); + assert.equal( + hubResponse + .json() + .latestLoreEntries.some((entry: { id: string }) => entry.id === 'draft-lore'), + false, + ); + await app.close(); + }); + + test('filters worlds by q, visibility fields, pagination, and consistent counts', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + await app.inject({ + headers: authHeader(), + method: 'POST', + payload: worldPayload, + url: '/worlds', + }); + await app.inject({ + headers: authHeader(), + method: 'POST', + payload: { + ...worldPayload, + description: 'Sunlit city state.', + seed: { + ...worldPayload.seed, + genre: 'Science Fantasy', + tone: 'Bright', + }, + title: 'Solar Foundry', + }, + url: '/worlds', + }); + + const search = await app.inject({ method: 'GET', url: '/worlds?q=moon&page=1&pageSize=10' }); + const filtered = await app.inject({ + method: 'GET', + url: '/worlds?genre=fantasy&tone=mystic%20wonder&page=1&pageSize=1', + }); + + assert.deepEqual( + search.json().worlds.map((world: { title: string }) => world.title), + ['Moon Archive'], + ); + assert.deepEqual(filtered.json().pagination, { page: 1, pageSize: 1, total: 1 }); + assert.equal(filtered.json().worlds.length, 1); + await app.close(); + }); + + test('allows a founder to update mutable off-chain world seed and bible data', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + await app.inject({ + headers: authHeader(), + method: 'POST', + payload: worldPayload, + url: '/worlds', + }); + + const response = await app.inject({ + headers: authHeader(), + method: 'PATCH', + payload: { + bible: { + changeSummary: 'Refined initial bible.', + content: { + rules: ['Keep the moon archive coherent.'], + }, + }, + seed: { + tone: 'Quiet awe', + }, + title: 'Moon Archive Revised', + }, + url: '/worlds/world-1', + }); + + assert.equal(response.statusCode, 200); + assert.equal(response.json().world.title, 'Moon Archive Revised'); + assert.equal(response.json().world.seed.tone, 'Quiet awe'); + assert.deepEqual(response.json().world.currentBibleVersion.content, { + rules: ['Keep the moon archive coherent.'], + }); + assert.equal(response.json().world.currentBibleVersion.publishedAt, null); + assert.equal( + state.auditLogs.some( + (entry) => + (entry as { action?: WorldAuditAction }).action === WorldAuditAction.WORLD_BIBLE_UPDATED, + ), + true, + ); + await app.close(); + }); + + test('rejects published and Hive-anchored bible updates without audit records', async () => { + const publishedState = createDatabase(); + const publishedApp = await createApp(publishedState.database); + await publishedApp.inject({ + headers: authHeader(), + method: 'POST', + payload: worldPayload, + url: '/worlds', + }); + publishedState.bibleVersions[0]!.publishedAt = new Date('2026-08-05T00:05:00.000Z'); + + const publishedResponse = await publishedApp.inject({ + headers: authHeader(), + method: 'PATCH', + payload: { bible: { content: { rules: ['No'] } } }, + url: '/worlds/world-1', + }); + + const anchoredState = createDatabase(); + const anchoredApp = await createApp(anchoredState.database); + await anchoredApp.inject({ + headers: authHeader(), + method: 'POST', + payload: worldPayload, + url: '/worlds', + }); + anchoredState.bibleVersions[0]!.hiveReferenceId = 'hive-1'; + + const anchoredResponse = await anchoredApp.inject({ + headers: authHeader(), + method: 'PATCH', + payload: { bible: { content: { rules: ['No'] } } }, + url: '/worlds/world-1', + }); + + assert.equal(publishedResponse.statusCode, 409); + assert.equal(anchoredResponse.statusCode, 409); + assert.deepEqual(publishedState.bibleVersions[0]!.content, worldPayload.bible.content); + assert.deepEqual(anchoredState.bibleVersions[0]!.content, worldPayload.bible.content); + assert.equal( + publishedState.auditLogs.some( + (entry) => + (entry as { action?: WorldAuditAction }).action === WorldAuditAction.WORLD_BIBLE_UPDATED, + ), + false, + ); + await publishedApp.close(); + await anchoredApp.close(); + }); + + test('rejects world updates without founder permissions', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + await app.inject({ + headers: authHeader(), + method: 'POST', + payload: worldPayload, + url: '/worlds', + }); + + const response = await app.inject({ + headers: authHeader(contributor.id), + method: 'PATCH', + payload: { + title: 'Unauthorized', + }, + url: '/worlds/world-1', + }); + + assert.equal(response.statusCode, 403); + await app.close(); + }); + + test('maps slug conflicts to 409 and rolls back failed creation steps', async () => { + const conflictState = createDatabase(); + const app = await createApp(conflictState.database); + const [first, second] = await Promise.all([ + app.inject({ headers: authHeader(), method: 'POST', payload: worldPayload, url: '/worlds' }), + app.inject({ headers: authHeader(), method: 'POST', payload: worldPayload, url: '/worlds' }), + ]); + + assert.equal(first.statusCode, 201); + assert.equal(second.statusCode, 201); + assert.deepEqual( + conflictState.worlds.map((world) => world.slug), + ['moon-archive', 'moon-archive-2'], + ); + + const rollbackState = createDatabase(); + rollbackState.failNextSeedCreate(); + + await assert.rejects( + createWorld(rollbackState.database as never, { + ...worldPayload, + creatorId: founder.id, + }), + ); + + assert.equal(rollbackState.worlds.length, 0); + assert.equal(rollbackState.seeds.length, 0); + assert.equal(rollbackState.bibleVersions.length, 0); + await app.close(); + }); + + test('translates database world slug uniqueness conflicts to 409', async () => { + const state = createDatabase(); + const app = await createApp(state.database); + state.failNextWorldCreateWithSlugConflict(); + + const response = await app.inject({ + headers: authHeader(), + method: 'POST', + payload: worldPayload, + url: '/worlds', + }); + + assert.equal(response.statusCode, 409); + assert.equal(response.json().error, 'World slug is already in use.'); + assert.equal(state.worlds.length, 0); + await app.close(); + }); + + test('rolls back bible updates when audit creation fails', async () => { + const state = createDatabase(); + await createWorld(state.database as never, { ...worldPayload, creatorId: founder.id }); + state.failNextAuditCreate(); + + await assert.rejects( + updateWorld(state.database as never, { + actorId: founder.id, + bible: { + content: { + rules: ['Rollback me.'], + }, + }, + worldId: 'world-1', + }), + ); + + assert.deepEqual(state.bibleVersions[0]!.content, worldPayload.bible.content); + assert.equal( + state.auditLogs.some( + (entry) => + (entry as { action?: WorldAuditAction }).action === WorldAuditAction.WORLD_BIBLE_UPDATED, + ), + false, + ); + }); + + test('returns typed errors for worlds missing seed or bible rows', async () => { + const seedState = createDatabase(); + await createWorld(seedState.database as never, { ...worldPayload, creatorId: founder.id }); + seedState.seeds.length = 0; + + await assert.rejects( + updateWorld(seedState.database as never, { + actorId: founder.id, + seed: { + tone: 'No seed', + }, + worldId: 'world-1', + }), + (error: unknown) => error instanceof Error && error.message === 'World seed is missing.', + ); + + const bibleState = createDatabase(); + await createWorld(bibleState.database as never, { ...worldPayload, creatorId: founder.id }); + bibleState.bibleVersions.length = 0; + + await assert.rejects( + updateWorld(bibleState.database as never, { + actorId: founder.id, + bible: { + content: { + rules: [], + }, + }, + worldId: 'world-1', + }), + (error: unknown) => + error instanceof Error && error.message === 'World bible version is missing.', + ); + }); +}); diff --git a/apps/api/src/routes/worlds.ts b/apps/api/src/routes/worlds.ts new file mode 100644 index 0000000..74d6afc --- /dev/null +++ b/apps/api/src/routes/worlds.ts @@ -0,0 +1,383 @@ +import type { FastifyInstance } from 'fastify'; +import { z } from 'zod'; + +import { env } from '../config/env.js'; +import type { Prisma } from '../generated/prisma/client.js'; +import { authenticateRequest, requireSession } from '../lib/auth-middleware.js'; +import type { SessionVerificationDatabase } from '../lib/auth-sessions.js'; +import { prisma } from '../lib/prisma.js'; +import { + createWorld, + getWorld, + getWorldHub, + listWorlds, + updateWorld, + WorldError, + type WorldDatabase, + type WorldSeedInput, +} from '../lib/worlds.js'; +import { WORLD_PERMISSIONS } from '../lib/world-permissions.js'; +import { authorizeWorldPermission } from '../lib/world-authorization.js'; +import type { WorldMembershipLookup } from '../lib/world-authorization.js'; + +const paramsSchema = z.object({ + worldId: z.string().min(1), +}); + +const stringListSchema = z.array(z.string().trim().min(1).max(120)).max(20); +const WORLD_BIBLE_MAX_BYTES = 100 * 1024; +const WORLD_BIBLE_MAX_DEPTH = 40; + +type JsonValidationResult = + | { + ok: true; + value: Prisma.InputJsonValue; + } + | { + ok: false; + message: string; + }; + +function validateJsonValue(value: unknown): JsonValidationResult { + if (value === null) { + return { + message: 'World bible content cannot be null.', + ok: false, + }; + } + + const pending: Array<{ value: unknown; depth: number }> = [{ depth: 0, value }]; + + while (pending.length > 0) { + const item = pending.pop()!; + + if (item.depth > WORLD_BIBLE_MAX_DEPTH) { + return { + message: 'World bible content exceeds the maximum nesting depth.', + ok: false, + }; + } + + if (item.value === null) { + continue; + } + + if (typeof item.value === 'string' || typeof item.value === 'boolean') { + continue; + } + + if (typeof item.value === 'number') { + if (!Number.isFinite(item.value)) { + return { + message: 'World bible content must be valid JSON.', + ok: false, + }; + } + + continue; + } + + if (Array.isArray(item.value)) { + for (const child of item.value) { + pending.push({ depth: item.depth + 1, value: child }); + } + + continue; + } + + if (typeof item.value === 'object') { + const prototype = Object.getPrototypeOf(item.value); + + if (prototype !== Object.prototype && prototype !== null) { + return { + message: 'World bible content must be valid JSON.', + ok: false, + }; + } + + for (const child of Object.values(item.value)) { + if (child === undefined) { + return { + message: 'World bible content must be valid JSON.', + ok: false, + }; + } + + pending.push({ depth: item.depth + 1, value: child }); + } + + continue; + } + + return { + message: 'World bible content must be valid JSON.', + ok: false, + }; + } + + let serialized: string; + + try { + serialized = JSON.stringify(value); + } catch { + return { + message: 'World bible content must be valid JSON.', + ok: false, + }; + } + + if (!serialized || Buffer.byteLength(serialized, 'utf8') > WORLD_BIBLE_MAX_BYTES) { + return { + message: 'World bible content exceeds the 100 KB limit.', + ok: false, + }; + } + + return { + ok: true, + value: value as Prisma.InputJsonValue, + }; +} + +const jsonValueSchema = z + .unknown() + .superRefine((value, context) => { + const validation = validateJsonValue(value); + + if (!validation.ok) { + context.addIssue({ + code: 'custom', + message: validation.message, + }); + } + }) + .transform((value) => value as Prisma.InputJsonValue); + +const worldSeedSchema = z.object({ + firstCharacters: stringListSchema.optional(), + firstFactions: stringListSchema.optional(), + firstHistoricalEvent: z.string().trim().min(1).max(1_000).optional(), + genre: z.string().trim().min(1).max(80), + mainConflict: z.string().trim().min(1).max(2_000), + premise: z.string().trim().min(1).max(3_000), + startingLocation: z.string().trim().min(1).max(500).optional(), + tone: z.string().trim().min(1).max(80), +}); + +const worldBibleSchema = z.object({ + changeSummary: z.string().trim().min(1).max(500).optional(), + content: jsonValueSchema, +}); + +const createWorldSchema = z.object({ + bible: worldBibleSchema, + description: z.string().trim().min(1).max(1_000), + seed: worldSeedSchema, + title: z.string().trim().min(1).max(160), +}); + +const updateWorldSchema = z + .object({ + bible: worldBibleSchema.optional(), + description: z.string().trim().min(1).max(1_000).optional(), + seed: worldSeedSchema.partial().optional(), + title: z.string().trim().min(1).max(160).optional(), + }) + .refine((value) => Object.keys(value).length > 0, { + message: 'At least one editable world field is required.', + }); + +const listWorldsSchema = z.object({ + genre: z.string().trim().min(1).max(80).optional(), + page: z.coerce.number().int().positive().default(1), + pageSize: z.coerce.number().int().positive().max(100).default(20), + q: z.string().trim().min(1).max(120).optional(), + tone: z.string().trim().min(1).max(80).optional(), +}); + +type RegisterWorldRoutesOptions = { + database?: WorldDatabase & WorldMembershipLookup & SessionVerificationDatabase; +}; + +function authOptions(database: SessionVerificationDatabase) { + return { + audience: env.AUTH_JWT_AUDIENCE, + database, + issuer: env.AUTH_JWT_ISSUER, + jwtSecret: env.AUTH_JWT_SECRET, + }; +} + +function handleWorldError( + error: unknown, + reply: { code(statusCode: number): { send(body: unknown): unknown } }, +) { + if (error instanceof WorldError) { + return reply.code(error.statusCode).send({ + error: error.message, + }); + } + + throw error; +} + +export async function registerWorldRoutes( + app: FastifyInstance, + options: RegisterWorldRoutesOptions = {}, +) { + const database = options.database ?? prisma; + + app.post( + '/worlds', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const body = createWorldSchema.safeParse(request.body); + + if (!body.success) { + return reply.code(400).send({ + error: 'Invalid world payload.', + }); + } + + const authenticatedUser = await authenticateRequest(request, authOptions(database)); + + if (!authenticatedUser) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + try { + const world = await createWorld(database, { + ...body.data, + bible: { + ...body.data.bible, + content: body.data.bible.content, + }, + creatorId: authenticatedUser.id, + }); + + return reply.code(201).send({ + world, + }); + } catch (error) { + return handleWorldError(error, reply); + } + }, + ); + + app.get('/worlds', async (request, reply) => { + const query = listWorldsSchema.safeParse(request.query); + + if (!query.success) { + return reply.code(400).send({ + error: 'Invalid worlds query.', + }); + } + + return listWorlds(database, query.data); + }); + + app.get('/worlds/:worldId', async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + error: 'Invalid world route.', + }); + } + + const world = await getWorld(database, params.data.worldId); + + if (!world) { + return reply.code(404).send({ + error: 'World not found.', + }); + } + + return { + world, + }; + }); + + app.get('/worlds/:worldId/hub', async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + + if (!params.success) { + return reply.code(400).send({ + error: 'Invalid world route.', + }); + } + + const hub = await getWorldHub(database, params.data.worldId); + + if (!hub) { + return reply.code(404).send({ + error: 'World not found.', + }); + } + + return hub; + }); + + app.patch( + '/worlds/:worldId', + { + preHandler: requireSession(authOptions(database)), + }, + async (request, reply) => { + const params = paramsSchema.safeParse(request.params); + const body = updateWorldSchema.safeParse(request.body); + + if (!params.success || !body.success) { + return reply.code(400).send({ + error: 'Invalid world payload.', + }); + } + + const authorized = await authorizeWorldPermission( + request, + reply, + params.data.worldId, + WORLD_PERMISSIONS.EDIT_INITIAL_CANON, + database, + ); + + if (!authorized) { + return; + } + + if (!request.user) { + return reply.code(401).send({ + error: 'Authentication required.', + }); + } + + try { + const world = await updateWorld(database, { + actorId: request.user.id, + ...(body.data.description ? { description: body.data.description } : {}), + ...(body.data.seed ? { seed: body.data.seed as Partial } : {}), + ...(body.data.title ? { title: body.data.title } : {}), + ...(body.data.bible + ? { + bible: { + ...body.data.bible, + content: body.data.bible.content, + }, + } + : {}), + worldId: params.data.worldId, + }); + + return { + world, + }; + } catch (error) { + return handleWorldError(error, reply); + } + }, + ); +} diff --git a/apps/api/src/scripts/hive-mainnet-smoke.ts b/apps/api/src/scripts/hive-mainnet-smoke.ts new file mode 100644 index 0000000..13b8441 --- /dev/null +++ b/apps/api/src/scripts/hive-mainnet-smoke.ts @@ -0,0 +1,56 @@ +import { createInterface } from 'node:readline/promises'; +import process from 'node:process'; +import { stdin as input, stdout as output } from 'node:process'; +import { config as loadDotenv } from 'dotenv'; + +import { formatHiveMainnetSmokeResult, runHiveMainnetSmoke } from '../lib/hive/mainnet-smoke.js'; +import { buildMainnetSmokeNetworkFromEnv } from '../lib/hive/smoke-operation.js'; + +loadDotenv(); +loadDotenv({ override: false, path: 'apps/api/.env' }); + +const CONFIRMATION_PHRASE = 'BROADCAST HIVELORE SMOKE'; + +async function main() { + const account = process.env.HIVE_SMOKE_ACCOUNT?.trim(); + const postingKey = process.env.HIVE_SMOKE_POSTING_KEY?.trim(); + + if (!account) { + throw new Error('HIVE_SMOKE_ACCOUNT must be set in the local process environment.'); + } + + if (!postingKey) { + throw new Error('HIVE_SMOKE_POSTING_KEY must be set in the local process environment.'); + } + + const network = buildMainnetSmokeNetworkFromEnv(process.env); + const readline = createInterface({ input, output }); + + try { + output.write('WARNING: The next command broadcasts an irreversible Hive mainnet custom_json. '); + const answer = await readline.question(`Type ${CONFIRMATION_PHRASE} to continue: `); + + if (answer.trim() !== CONFIRMATION_PHRASE) { + output.write('verification summary: FAIL\n'); + process.exitCode = 1; + return; + } + } finally { + readline.close(); + } + + const result = await runHiveMainnetSmoke({ + account, + network, + postingKey, + }); + + output.write(`${formatHiveMainnetSmokeResult(result)}\n`); +} + +await main().catch((error: unknown) => { + const message = error instanceof Error ? error.message : String(error); + + process.stderr.write(`verification summary: FAIL (${message})\n`); + process.exitCode = 1; +}); diff --git a/apps/api/src/scripts/reindex-search.ts b/apps/api/src/scripts/reindex-search.ts new file mode 100644 index 0000000..7c4a09d --- /dev/null +++ b/apps/api/src/scripts/reindex-search.ts @@ -0,0 +1,10 @@ +import { prisma } from '../lib/prisma.js'; +import { rebuildSearchIndex } from '../lib/search-index.js'; + +const result = await rebuildSearchIndex(prisma); + +console.log( + `Rebuilt search index for ${result.worlds} worlds and ${result.loreEntries} canon lore entries.`, +); + +await prisma.$disconnect(); diff --git a/apps/api/src/test/integration-db.ts b/apps/api/src/test/integration-db.ts new file mode 100644 index 0000000..7fe3e35 --- /dev/null +++ b/apps/api/src/test/integration-db.ts @@ -0,0 +1,108 @@ +import { spawnSync } from 'node:child_process'; +import { randomUUID } from 'node:crypto'; +import process from 'node:process'; + +import { PrismaPg } from '@prisma/adapter-pg'; +import pg from 'pg'; + +import { PrismaClient } from '../generated/prisma/client.js'; + +const { Client } = pg; + +export const testDatabaseAdminUrl = process.env.TEST_DATABASE_ADMIN_URL; + +function disposableDatabaseName(prefix: string) { + return `${prefix}_${Date.now()}_${process.pid}_${randomUUID().replaceAll('-', '').slice(0, 8)}`; +} + +function databaseUrlFor(adminConnectionUrl: string, databaseName: string) { + const databaseUrl = new URL(adminConnectionUrl); + databaseUrl.pathname = `/${databaseName}`; + + return databaseUrl.toString(); +} + +async function withPgClient( + connectionString: string, + callback: (client: pg.Client) => Promise, +) { + const client = new Client({ connectionString }); + await client.connect(); + + try { + return await callback(client); + } finally { + await client.end(); + } +} + +function runPrismaMigrateDeploy(databaseUrl: string) { + const executable = process.platform === 'win32' ? 'npx.cmd' : 'npx'; + const result = spawnSync(executable, ['prisma', 'migrate', 'deploy'], { + cwd: new URL('../..', import.meta.url), + env: { + ...process.env, + DATABASE_URL: databaseUrl, + DIRECT_URL: databaseUrl, + NODE_ENV: 'test', + }, + shell: false, + stdio: 'inherit', + }); + + if (result.status !== 0) { + throw new Error(`prisma migrate deploy failed with exit code ${result.status}`); + } +} + +export function createPrismaClient(connectionString: string) { + return new PrismaClient({ + adapter: new PrismaPg({ connectionString }), + }); +} + +export async function withDisposablePrismaDatabase( + prefix: string, + callback: (database: PrismaClient, databaseUrl: string) => Promise, +) { + if (!testDatabaseAdminUrl) { + throw new Error('TEST_DATABASE_ADMIN_URL is not configured.'); + } + + const databaseName = disposableDatabaseName(prefix); + + if (!databaseName.startsWith(`${prefix}_`)) { + throw new Error(`Refusing to use non-disposable database name: ${databaseName}`); + } + + const directUrl = databaseUrlFor(testDatabaseAdminUrl, databaseName); + + await withPgClient(testDatabaseAdminUrl, (client) => + client.query(`CREATE DATABASE "${databaseName}"`), + ); + + try { + runPrismaMigrateDeploy(directUrl); + + const database = createPrismaClient(directUrl); + + try { + return await callback(database, directUrl); + } finally { + await database.$disconnect(); + } + } finally { + await withPgClient(testDatabaseAdminUrl, async (client) => { + await client.query( + ` + SELECT pg_terminate_backend(pid) + FROM pg_stat_activity + WHERE datname = $1 + AND pid <> pg_backend_pid() + `, + [databaseName], + ); + await client.query(`DROP DATABASE IF EXISTS "${databaseName}"`); + }); + } +} diff --git a/apps/web/.env.example b/apps/web/.env.example index b5cb2cb..28eff82 100644 --- a/apps/web/.env.example +++ b/apps/web/.env.example @@ -5,5 +5,6 @@ # Hive private keys must never be collected, stored, transmitted, or logged. NEXT_PUBLIC_API_URL=http://localhost:3001 +NEXT_PUBLIC_GOOGLE_AUTH_ENABLED=false NEXT_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your-supabase-publishable-key diff --git a/apps/web/README.md b/apps/web/README.md index 18c15b4..fc1de16 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -32,11 +32,13 @@ Quality commands: ```bash npm run lint --workspace=@hivelore/web +npm test --workspace=@hivelore/web npm run typecheck --workspace=@hivelore/web npm run build --workspace=@hivelore/web ``` -There is currently no configured `test` script. +The repository root `npm test` command runs every workspace test script with +`--workspaces --if-present`, including this web suite. ## Environment Variables diff --git a/apps/web/package.json b/apps/web/package.json index eb3c143..14d327f 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -6,6 +6,7 @@ "scripts": { "dev": "next dev --port 3000", "lint": "eslint .", + "test": "vitest run", "typecheck": "tsc --noEmit", "build": "next build", "clean": "node -e \"fs.rmSync('.next', { recursive: true, force: true }); fs.rmSync('dist', { recursive: true, force: true })\"" @@ -23,13 +24,19 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4", + "@testing-library/jest-dom": "^7.0.1", + "@testing-library/react": "^16.3.3", + "@testing-library/user-event": "^14.6.6", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "@vitejs/plugin-react": "^6.1.1", "eslint": "^9", "eslint-config-next": "^15.4.2", + "jsdom": "^29.1.1", "tailwindcss": "^4", - "typescript": "^5" + "typescript": "^5", + "vitest": "^4.1.11" }, "optionalDependencies": { "@tailwindcss/oxide-linux-x64-gnu": "^4.3.2", diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index 5d71e19..75c71c3 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -166,27 +166,81 @@ textarea { line-height: var(--leading-prose); } -.theme-switcher { - display: flex; +.theme-toggle { + display: inline-flex; + min-height: 2.5rem; + width: 2.5rem; align-items: center; - gap: 0.5rem; + justify-content: center; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--surface); + color: var(--foreground); + box-shadow: var(--shadow-soft); + transition: + background-color 160ms ease, + border-color 160ms ease, + color 160ms ease; } -.theme-switcher__label { - color: var(--muted-foreground); - font-size: 0.75rem; - font-weight: 700; - letter-spacing: var(--tracking-label); - text-transform: uppercase; +.theme-toggle:hover { + background: var(--muted); } -.theme-switcher__select { - min-height: 2.25rem; - border: 1px solid var(--input-border); - border-radius: var(--radius-control); - background: var(--surface); - color: var(--foreground); - padding: 0 2rem 0 0.75rem; +.theme-toggle__icon { + width: 1.25rem; + height: 1.25rem; +} + +.mobile-navigation-backdrop { + position: fixed; + inset: 4rem 0 0; + z-index: 70; + border: 0; + background: + linear-gradient(rgb(0 0 0 / 0.92), rgb(0 0 0 / 0.92)), + color-mix(in srgb, var(--background) 35%, black); + backdrop-filter: blur(8px); + cursor: default; + padding: 0; +} + +.mobile-navigation-panel { + position: fixed; + top: 4.75rem; + right: 1rem; + z-index: 80; + display: flex; + width: calc(100vw - 2rem); + max-width: 24rem; + transform-origin: top right; + flex-direction: column; + gap: 1.25rem; + border: 1px solid var(--border); + border-radius: var(--radius-panel); + background: color-mix(in srgb, var(--surface) 98%, transparent); + box-shadow: var(--shadow-elevated); + padding: 1rem; +} + +@keyframes mobile-overlay-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes mobile-menu-in { + from { + opacity: 0; + transform: translateY(-0.5rem) scale(0.98); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } } .hive-brand { @@ -221,3 +275,407 @@ textarea { padding: 0.4rem 0.7rem; text-transform: uppercase; } + +.auth-atlas-page { + position: relative; + width: 100vw; + height: calc(100svh - 8rem); + max-height: calc(100svh - 8rem); + margin-inline: calc(50% - 50vw); + overflow: hidden; + isolation: isolate; +} + +.auth-atlas-page__content { + position: relative; + z-index: 1; + height: 100%; + max-width: 72rem; + margin-inline: auto; + padding-inline: 1rem; + padding-block: clamp(1rem, 3vh, 2.25rem); +} + +@media (min-width: 640px) { + .auth-atlas-page__content { + padding-inline: 1.5rem; + } +} + +@media (min-width: 1024px) { + .auth-atlas-page__content { + padding-inline: 2rem; + } +} + +.auth-atlas-page__hero { + position: relative; + text-shadow: 0 1px 28px color-mix(in srgb, var(--background) 86%, transparent); +} + +.auth-atlas-page__form { + position: relative; + width: 100%; + max-width: 22rem; + justify-self: end; + background: linear-gradient( + 135deg, + color-mix(in srgb, var(--surface) 96%, transparent), + color-mix(in srgb, var(--surface-elevated) 88%, transparent) + ); + box-shadow: + 0 16px 38px rgb(0 0 0 / 0.18), + 0 0 0 1px color-mix(in srgb, var(--hive-red) 5%, transparent); +} + +.lore-atlas-background { + --atlas-parallax-x: 0; + --atlas-parallax-y: 0; + position: absolute; + inset: 0; + z-index: 0; + overflow: hidden; + pointer-events: none; + background: + radial-gradient( + ellipse at 27% 43%, + color-mix(in srgb, var(--hive-red) 12%, transparent) 0%, + transparent 31% + ), + radial-gradient(ellipse at 49% 34%, rgb(61 71 117 / 0.11) 0%, transparent 34%), + radial-gradient(ellipse at 78% 58%, rgb(24 42 78 / 0.12) 0%, transparent 35%), + linear-gradient( + 90deg, + color-mix(in srgb, var(--background) 90%, #07060a) 0%, + color-mix(in srgb, var(--background) 96%, #0b0d18) 54%, + var(--background) 100% + ); +} + +.lore-atlas-background::before, +.lore-atlas-background::after { + position: absolute; + inset: 0; + content: ''; +} + +.lore-atlas-background::before { + background: + linear-gradient( + 90deg, + transparent 0%, + transparent 50%, + color-mix(in srgb, var(--background) 58%, transparent) 73%, + color-mix(in srgb, var(--background) 88%, transparent) 100% + ), + radial-gradient(ellipse at center, transparent 44%, rgb(0 0 0 / 0.34) 100%); +} + +.lore-atlas-background::after { + background-image: + linear-gradient(color-mix(in srgb, var(--foreground) 5%, transparent) 1px, transparent 1px), + linear-gradient( + 90deg, + color-mix(in srgb, var(--foreground) 5%, transparent) 1px, + transparent 1px + ); + background-position: + calc(var(--atlas-parallax-x) * -10px) calc(var(--atlas-parallax-y) * -10px), + calc(var(--atlas-parallax-x) * -10px) calc(var(--atlas-parallax-y) * -10px); + background-size: 64px 64px; + mask-image: radial-gradient(circle at 32% 48%, black 0%, transparent 58%); + opacity: 0.16; +} + +:root[data-theme='dark'] .lore-atlas-background { + background: + radial-gradient(ellipse at 27% 43%, rgb(133 22 45 / 0.2) 0%, transparent 32%), + radial-gradient(ellipse at 49% 34%, rgb(46 55 103 / 0.16) 0%, transparent 34%), + radial-gradient(ellipse at 78% 58%, rgb(15 30 61 / 0.18) 0%, transparent 35%), + linear-gradient(90deg, #0a090d 0%, #111014 52%, #08080c 100%); +} + +.lore-atlas-background__hub { + position: absolute; + left: clamp(-3rem, 4vw, 4rem); + top: 16%; + width: clamp(17rem, 33vw, 31rem); + aspect-ratio: 1; + border: 1px solid color-mix(in srgb, var(--hive-red) 20%, transparent); + border-radius: 999px; + background: + radial-gradient( + circle, + color-mix(in srgb, var(--hive-red) 7%, transparent) 0%, + transparent 50% + ), + repeating-radial-gradient( + circle, + color-mix(in srgb, var(--foreground) 5%, transparent) 0 1px, + transparent 1px 2.4rem + ); + filter: blur(0.2px); + opacity: 0.44; + transform: translate( + calc(var(--atlas-parallax-x) * -18px), + calc(var(--atlas-parallax-y) * -12px) + ); +} + +.lore-atlas-background__map { + position: absolute; + inset: -15% auto auto -4rem; + width: min(82rem, 104vw); + height: 130%; + opacity: 0.62; + transform: translate(calc(var(--atlas-parallax-x) * 16px), calc(var(--atlas-parallax-y) * 10px)); +} + +.lore-atlas-background__contours path { + fill: none; + stroke: color-mix(in srgb, var(--foreground) 9%, transparent); + stroke-dasharray: 0.45 1.85; + stroke-linecap: round; + stroke-width: 0.18; +} + +.lore-atlas-background__coastlines path { + fill: color-mix(in srgb, #192132 12%, transparent); + stroke: color-mix(in srgb, var(--foreground) 13%, transparent); + stroke-linejoin: round; + stroke-width: 0.2; +} + +.lore-atlas-background__connections path { + fill: none; + stroke: color-mix(in srgb, var(--foreground) 15%, transparent); + stroke-linecap: round; + stroke-width: 0.18; +} + +.lore-atlas-background__signals path { + animation: lore-signal 13s linear infinite; + fill: none; + stroke: color-mix(in srgb, var(--hive-red) 36%, var(--foreground) 20%); + stroke-dasharray: 0.01 13; + stroke-linecap: round; + stroke-width: 0.28; +} + +.lore-atlas-background__node-glow { + fill: url('#atlas-node-glow'); + opacity: 0.18; +} + +.lore-atlas-background__node-core { + animation: lore-node-pulse 9s ease-in-out infinite; + fill: color-mix(in srgb, var(--hive-red) 58%, var(--foreground) 18%); + stroke: color-mix(in srgb, var(--surface) 72%, transparent); + stroke-width: 0.14; +} + +.lore-atlas-background__node.is-region .lore-atlas-background__node-glow { + fill: url('#atlas-cool-glow'); + opacity: 0.16; +} + +.lore-atlas-background__node.is-region .lore-atlas-background__node-core { + fill: color-mix(in srgb, #8ab4ff 52%, var(--foreground) 12%); +} + +.lore-atlas-background__node.is-lore .lore-atlas-background__node-core { + fill: color-mix(in srgb, var(--foreground) 62%, var(--hive-red) 13%); + opacity: 0.7; +} + +.lore-atlas-background__particles { + position: absolute; + inset: 0; + transform: translate(calc(var(--atlas-parallax-x) * -8px), calc(var(--atlas-parallax-y) * -6px)); +} + +.lore-atlas-background__particles span { + position: absolute; + width: 2px; + height: 2px; + animation: lore-particle-drift 18s ease-in-out infinite; + border-radius: 999px; + background: color-mix(in srgb, var(--foreground) 46%, transparent); + box-shadow: 0 0 8px color-mix(in srgb, #8ab4ff 16%, transparent); +} + +.lore-atlas-background__veil { + position: absolute; + inset: 0; + background: + linear-gradient( + 90deg, + transparent 0%, + transparent 50%, + color-mix(in srgb, var(--background) 88%, transparent) 74%, + var(--background) 100% + ), + linear-gradient( + 180deg, + var(--background) 0%, + transparent 12%, + transparent 78%, + var(--background) 100% + ); +} + +@keyframes lore-node-pulse { + 0%, + 100% { + opacity: 0.62; + transform: scale(1); + } + + 45% { + opacity: 0.9; + transform: scale(1.08); + } +} + +@keyframes lore-signal { + from { + stroke-dashoffset: 11; + opacity: 0; + } + + 20%, + 74% { + opacity: 0.72; + } + + to { + stroke-dashoffset: 0; + opacity: 0; + } +} + +@keyframes lore-particle-drift { + 0%, + 100% { + opacity: 0.18; + transform: translate3d(0, 0, 0); + } + + 50% { + opacity: 0.55; + transform: translate3d(var(--particle-distance), -18px, 0); + } +} + +@media (max-width: 1024px) { + .lore-atlas-background__map { + width: 74rem; + opacity: 0.48; + } + + .lore-atlas-background__particles span:nth-child(n + 6), + .lore-atlas-background__signals path:nth-child(n + 5) { + display: none; + } +} + +@media (max-height: 720px) and (min-width: 768px) { + .auth-atlas-page__content { + padding-block: 0.75rem; + } + + .auth-atlas-page__hero h1 { + font-size: clamp(2.35rem, 4.4vw, 3.25rem); + } + + .auth-atlas-page__hero .prose-text { + margin-top: 1rem; + } + + .auth-atlas-page__hero p:last-child { + margin-top: 1rem; + } + + .auth-atlas-page__form { + padding: 1rem; + } +} + +@media (max-width: 767px) { + .auth-atlas-page { + height: calc(100svh - 7rem); + max-height: calc(100svh - 7rem); + overflow: hidden; + } + + .auth-atlas-page__form { + max-width: none; + justify-self: stretch; + } + + .auth-atlas-page__content { + padding-block: 1.5rem; + } + + .lore-atlas-background { + inset: 0; + } + + .lore-atlas-background::before { + background: + linear-gradient(180deg, transparent 0%, rgb(0 0 0 / 0.38) 48%, rgb(0 0 0 / 0.66) 100%), + radial-gradient(ellipse at center, transparent 36%, rgb(0 0 0 / 0.45) 100%); + } + + .lore-atlas-background__hub { + left: -7rem; + top: 4%; + width: 22rem; + opacity: 0.26; + } + + .lore-atlas-background__map { + left: -17rem; + top: -1rem; + width: 58rem; + height: 115%; + opacity: 0.34; + } + + .lore-atlas-background__particles span:nth-child(n + 4), + .lore-atlas-background__signals path:nth-child(n + 3), + .lore-atlas-background__contours path:nth-child(n + 4) { + display: none; + } + + .lore-atlas-background__veil { + background: + linear-gradient( + 180deg, + transparent 0%, + color-mix(in srgb, var(--background) 76%, transparent) 44%, + var(--background) 100% + ), + radial-gradient(circle at 28% 24%, transparent 0%, var(--background) 72%); + } +} + +@media (prefers-reduced-motion: reduce) { + .lore-atlas-background, + .lore-atlas-background__hub, + .lore-atlas-background__map, + .lore-atlas-background__particles { + transform: none; + } + + .lore-atlas-background__node-core, + .lore-atlas-background__signals path, + .lore-atlas-background__particles span { + animation: none; + } + + .lore-atlas-background__signals path { + opacity: 0.16; + stroke-dasharray: 1 9; + } +} diff --git a/apps/web/src/app/login/page.tsx b/apps/web/src/app/login/page.tsx index 530bb3f..9064205 100644 --- a/apps/web/src/app/login/page.tsx +++ b/apps/web/src/app/login/page.tsx @@ -1,5 +1,5 @@ -import { PlaceholderPage } from '@/components/layout/placeholder-page'; +import Home from '@/app/page'; export default function LoginPage() { - return ; + return ; } diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index aaa6022..3cd3462 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -1,5 +1,352 @@ -import { PlaceholderPage } from '@/components/layout/placeholder-page'; +'use client'; + +import { useMemo, useState } from 'react'; + +import { LoreAtlasBackground } from '@/components/auth/lore-atlas-background'; +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { + createAuthChallenge, + getMe, + verifyAuthChallenge, + type AuthChallengeResponse, + type AuthProvider, +} from '@/lib/api/auth'; +import { ApiError } from '@/lib/api/errors'; +import { env } from '@/lib/env'; +import { useAuthSession } from '@/providers/auth-session-provider'; + +type HiveKeychainResponse = { + success: boolean; + error?: string; + message?: string; + result?: string; + publicKey?: string; +}; + +declare global { + interface Window { + hive_keychain?: { + requestSignBuffer( + username: string, + message: string, + keyType: 'Posting', + callback: (response: HiveKeychainResponse) => void, + ): void; + }; + } +} + +function getErrorMessage(error: unknown) { + if (error instanceof ApiError) { + return error.body?.error ?? 'Authentication failed.'; + } + + if (error instanceof Error) { + return error.message; + } + + return 'Authentication failed.'; +} + +function signWithKeychain(username: string, message: string) { + return new Promise((resolve, reject) => { + if (!window.hive_keychain) { + reject(new Error('Hive Keychain is not available in this browser.')); + return; + } + + window.hive_keychain.requestSignBuffer(username, message, 'Posting', (response) => { + if (!response.success) { + reject(new Error(response.error ?? response.message ?? 'Signature request was rejected.')); + return; + } + + resolve(response); + }); + }); +} + +async function sha256Hex(value: string) { + const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value)); + + return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join(''); +} + +function GoogleIcon() { + return ( + + ); +} export default function Home() { - return ; + const [challenge, setChallenge] = useState(null); + const [error, setError] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [manualSignature, setManualSignature] = useState(''); + const [manualPublicKey, setManualPublicKey] = useState(''); + const [provider, setProvider] = useState('keychain'); + const [username, setUsername] = useState(''); + const { clearSession, isSessionLoading, refreshSession, setSession, user } = useAuthSession(); + + const canSubmit = useMemo( + () => username.trim().length > 0 && !isLoading && !isSessionLoading, + [isLoading, isSessionLoading, username], + ); + + async function completeLogin( + nextChallenge: AuthChallengeResponse, + signature: string, + publicKey?: string, + ) { + const session = await verifyAuthChallenge({ + challengeId: nextChallenge.challengeId, + message: nextChallenge.message, + provider: nextChallenge.provider, + signature, + username: nextChallenge.hiveUsername, + ...(publicKey ? { publicKey } : {}), + }); + + setSession(session); + setChallenge(null); + setManualSignature(''); + setManualPublicKey(''); + } + + async function handleKeychainLogin() { + setError(null); + setIsLoading(true); + setProvider('keychain'); + + try { + const nextChallenge = await createAuthChallenge(username, 'keychain'); + const signaturePayload = await sha256Hex(nextChallenge.message); + const signature = await signWithKeychain(nextChallenge.hiveUsername, signaturePayload); + + await completeLogin(nextChallenge, signature.result ?? '', signature.publicKey); + } catch (nextError) { + setError(getErrorMessage(nextError)); + } finally { + setIsLoading(false); + } + } + + async function handleHiveSignerStart() { + setError(null); + setIsLoading(true); + setProvider('hivesigner'); + + try { + setChallenge(await createAuthChallenge(username, 'hivesigner')); + } catch (nextError) { + setError(getErrorMessage(nextError)); + } finally { + setIsLoading(false); + } + } + + async function handleManualVerify() { + if (!challenge) { + return; + } + + setError(null); + setIsLoading(true); + + try { + await completeLogin(challenge, manualSignature, manualPublicKey || undefined); + } catch (nextError) { + setError(getErrorMessage(nextError)); + } finally { + setIsLoading(false); + } + } + + async function handleRefresh() { + setError(null); + setIsLoading(true); + + try { + const session = await refreshSession(); + await getMe(session.accessToken); + } catch (nextError) { + setError(getErrorMessage(nextError)); + } finally { + setIsLoading(false); + } + } + + async function handleLogout() { + setError(null); + setIsLoading(true); + + try { + await clearSession(); + } catch (nextError) { + setError(getErrorMessage(nextError)); + } finally { + setIsLoading(false); + } + } + + return ( +
+ +
+
+

+ Welcome back to HiveLore. +

+

+ Sign in to contribute, vote, and build trusted Hive knowledge. +

+

+ Hive accounts are the canonical identity. Signing a challenge proves account control and + never gives HiveLore permission to publish, transfer, or hold private keys. +

+
+ +
+ {user ? ( +
+
+

Signed in as

+

@{user.hiveUsername}

+
+
+ + +
+
+ ) : ( +
+ + + + +
+ + or + +
+ + + + + +

+ Google creates or connects a Hive account behind the scenes. +

+ +

+ No password is stored by HiveLore. +

+
+ )} + + {challenge ? ( +
+