Merge pull request #1 from Yiling-J/feature-backend-infra-6262829423610331401
Backend Infrastructure Setup
This commit is contained in:
47 files changed
+15107
-39
No files matched your search
@@ -1,8 +1,2 @@
|
||||
# Environment variables declared in this file are NOT automatically loaded by Prisma.
|
||||
# Please add `import "dotenv/config";` to your `prisma.config.ts` file, or use the Prisma CLI with Bun
|
||||
# to load environment variables from .env files: https://pris.ly/prisma-config-env-vars.
|
||||
|
||||
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
|
||||
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||
|
||||
DATABASE_URL="file:./dev.db"
|
||||
# Environment variables
|
||||
DATABASE_URL="file:./dev.db"
|
||||
@@ -0,0 +1,36 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Generate Prisma Client
|
||||
run: bun --bun run prisma generate
|
||||
env:
|
||||
DATABASE_URL: 'file:./test.db'
|
||||
|
||||
- name: Lint
|
||||
run: bun run lint
|
||||
|
||||
- name: Typecheck
|
||||
run: bun run typecheck
|
||||
|
||||
- name: Run Tests
|
||||
run: bun run test
|
||||
env:
|
||||
DATABASE_URL: 'file:./test.db'
|
||||
+12
-2
@@ -1,2 +1,12 @@
|
||||
# deps
|
||||
node_modules/
|
||||
node_modules
|
||||
.bun
|
||||
dist
|
||||
out
|
||||
.DS_Store
|
||||
*.log
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
data/files/*
|
||||
!data/files/.gitkeep
|
||||
*.db
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
.bun
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
# Developer Guide
|
||||
|
||||
## Backend Architecture
|
||||
|
||||
The backend is built with:
|
||||
|
||||
- **Runtime**: Bun
|
||||
- **Framework**: Hono
|
||||
- **ORM**: Prisma (with SQLite)
|
||||
- **Database**: SQLite (local file)
|
||||
|
||||
### Layered Architecture
|
||||
|
||||
We follow a strict layered architecture:
|
||||
|
||||
1. **API Layer (`src/api`)**: Handles HTTP requests, validation, and calls Service layer. **Do not access DB directly.**
|
||||
2. **Service Layer (`src/service`)**: Contains business logic and interacts with the Database via Prisma.
|
||||
3. **Data Layer (`src/db.ts`)**: Exports the Prisma Client instance.
|
||||
|
||||
## Testing
|
||||
|
||||
We use `bun:test` for testing.
|
||||
|
||||
### Service Tests
|
||||
|
||||
- Located in `src/service/*.test.ts`.
|
||||
- Mock `prisma` client using `mock.module('../db', ...)`.
|
||||
- **Important**: Due to `bun test` module caching in parallel execution, service tests must import the service under test dynamically with a cache-busting query parameter to ensure a fresh module instance (and thus fresh mocks).
|
||||
```typescript
|
||||
// @ts-ignore
|
||||
const { MyService } = await import(`./myService?v=${Date.now()}`)
|
||||
```
|
||||
|
||||
### API Tests
|
||||
|
||||
- Located in `src/api/*.test.ts`.
|
||||
- Mock the Service layer using `mock.module('../service/myService', ...)`.
|
||||
- Verify that the API calls the Service methods correctly.
|
||||
|
||||
## Submission Rules
|
||||
|
||||
- **Strict Requirement**: You must ensure `lint`, `format`, `typecheck`, and `test` all pass before submitting any changes.
|
||||
|
||||
## Prisma Configuration
|
||||
|
||||
- Schema: `prisma/schema.prisma`
|
||||
- Generated Client: `src/generated/prisma`
|
||||
- Config: `prisma.config.ts` (Required for Prisma 7+)
|
||||
- Adapter: We use `@prisma/adapter-libsql` for SQLite compatibility with Bun.
|
||||
|
||||
### Commands
|
||||
|
||||
- Generate Client: `bun --bun run prisma generate`
|
||||
- Push Schema to DB: `bun --bun run prisma db push`
|
||||
|
||||
## Environment Variables
|
||||
|
||||
- `.env`: Development environment variables (`DATABASE_URL="file:./dev.db"`).
|
||||
- `.env.test`: Test environment variables (`DATABASE_URL="file:./test.db"`).
|
||||
|
||||
## Known Issues
|
||||
|
||||
- `bun test` module mocking can be sticky across test files running in the same process/worker. Use the dynamic import workaround in Service tests.
|
||||
@@ -1,9 +1,11 @@
|
||||
To install dependencies:
|
||||
|
||||
```sh
|
||||
bun install
|
||||
```
|
||||
|
||||
To run:
|
||||
|
||||
```sh
|
||||
bun run dev
|
||||
```
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "forgery",
|
||||
"dependencies": {
|
||||
"@libsql/client": "^0.17.0",
|
||||
"@prisma/adapter-libsql": "^7.3.0",
|
||||
"@prisma/client": "^7.3.0",
|
||||
"hono": "^4.11.8",
|
||||
"ulidx": "^2.4.1",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@types/bun": "^1.3.8",
|
||||
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
||||
"@typescript-eslint/parser": "^8.54.0",
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"prettier": "^3.8.1",
|
||||
"prisma": "^7.3.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.54.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -30,31 +39,63 @@
|
||||
|
||||
"@electric-sql/pglite-tools": ["@electric-sql/pglite-tools@0.2.20", "", { "peerDependencies": { "@electric-sql/pglite": "0.3.15" } }, "sha512-BK50ZnYa3IG7ztXhtgYf0Q7zijV32Iw1cYS8C+ThdQlwx12V5VZ9KRJ42y82Hyb4PkTxZQklVQA9JHyUlex33A=="],
|
||||
|
||||
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
|
||||
|
||||
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
|
||||
|
||||
"@eslint/config-array": ["@eslint/config-array@0.23.1", "", { "dependencies": { "@eslint/object-schema": "^3.0.1", "debug": "^4.3.1", "minimatch": "^10.1.1" } }, "sha512-uVSdg/V4dfQmTjJzR0szNczjOH/J+FyUMMjYtr07xFRXR7EDf9i1qdxrD0VusZH9knj1/ecxzCQQxyic5NzAiA=="],
|
||||
|
||||
"@eslint/config-helpers": ["@eslint/config-helpers@0.5.2", "", { "dependencies": { "@eslint/core": "^1.1.0" } }, "sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ=="],
|
||||
|
||||
"@eslint/core": ["@eslint/core@1.1.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw=="],
|
||||
|
||||
"@eslint/js": ["@eslint/js@10.0.1", "", { "peerDependencies": { "eslint": "^10.0.0" }, "optionalPeers": ["eslint"] }, "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA=="],
|
||||
|
||||
"@eslint/object-schema": ["@eslint/object-schema@3.0.1", "", {}, "sha512-P9cq2dpr+LU8j3qbLygLcSZrl2/ds/pUpfnHNNuk5HW7mnngHs+6WSq5C9mO3rqRX8A1poxqLTC9cu0KOyJlBg=="],
|
||||
|
||||
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.6.0", "", { "dependencies": { "@eslint/core": "^1.1.0", "levn": "^0.4.1" } }, "sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ=="],
|
||||
|
||||
"@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="],
|
||||
|
||||
"@libsql/client": ["@libsql/client@0.8.1", "", { "dependencies": { "@libsql/core": "^0.8.1", "@libsql/hrana-client": "^0.6.2", "js-base64": "^3.7.5", "libsql": "^0.3.10", "promise-limit": "^2.7.0" } }, "sha512-xGg0F4iTDFpeBZ0r4pA6icGsYa5rG6RAG+i/iLDnpCAnSuTqEWMDdPlVseiq4Z/91lWI9jvvKKiKpovqJ1kZWA=="],
|
||||
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
||||
|
||||
"@libsql/core": ["@libsql/core@0.8.1", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-u6nrj6HZMTPsgJ9EBhLzO2uhqhlHQJQmVHV+0yFLvfGf3oSP8w7TjZCNUgu1G8jHISx6KFi7bmcrdXW9lRt++A=="],
|
||||
"@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="],
|
||||
|
||||
"@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.3.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rmOqsLcDI65zzxlUOoEiPJLhqmbFsZF6p4UJQ2kMqB+Kc0Rt5/A1OAdOZ/Wo8fQfJWjR1IbkbpEINFioyKf+nQ=="],
|
||||
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
|
||||
|
||||
"@libsql/darwin-x64": ["@libsql/darwin-x64@0.3.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-q9O55B646zU+644SMmOQL3FIfpmEvdWpRpzubwFc2trsa+zoBlSkHuzU9v/C+UNoPHQVRMP7KQctJ455I/h/xw=="],
|
||||
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
|
||||
|
||||
"@libsql/hrana-client": ["@libsql/hrana-client@0.6.2", "", { "dependencies": { "@libsql/isomorphic-fetch": "^0.2.1", "@libsql/isomorphic-ws": "^0.1.5", "js-base64": "^3.7.5", "node-fetch": "^3.3.2" } }, "sha512-MWxgD7mXLNf9FXXiM0bc90wCjZSpErWKr5mGza7ERy2FJNNMXd7JIOv+DepBA1FQTIfI8TFO4/QDYgaQC0goNw=="],
|
||||
"@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="],
|
||||
|
||||
"@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.1", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ=="],
|
||||
|
||||
"@libsql/client": ["@libsql/client@0.17.0", "", { "dependencies": { "@libsql/core": "^0.17.0", "@libsql/hrana-client": "^0.9.0", "js-base64": "^3.7.5", "libsql": "^0.5.22", "promise-limit": "^2.7.0" } }, "sha512-TLjSU9Otdpq0SpKHl1tD1Nc9MKhrsZbCFGot3EbCxRa8m1E5R1mMwoOjKMMM31IyF7fr+hPNHLpYfwbMKNusmg=="],
|
||||
|
||||
"@libsql/core": ["@libsql/core@0.17.0", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-hnZRnJHiS+nrhHKLGYPoJbc78FE903MSDrFJTbftxo+e52X+E0Y0fHOCVYsKWcg6XgB7BbJYUrz/xEkVTSaipw=="],
|
||||
|
||||
"@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.5.22", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4B8ZlX3nIDPndfct7GNe0nI3Yw6ibocEicWdC4fvQbSs/jdq/RC2oCsoJxJ4NzXkvktX70C1J4FcmmoBy069UA=="],
|
||||
|
||||
"@libsql/darwin-x64": ["@libsql/darwin-x64@0.5.22", "", { "os": "darwin", "cpu": "x64" }, "sha512-ny2HYWt6lFSIdNFzUFIJ04uiW6finXfMNJ7wypkAD8Pqdm6nAByO+Fdqu8t7sD0sqJGeUCiOg480icjyQ2/8VA=="],
|
||||
|
||||
"@libsql/hrana-client": ["@libsql/hrana-client@0.9.0", "", { "dependencies": { "@libsql/isomorphic-ws": "^0.1.5", "cross-fetch": "^4.0.0", "js-base64": "^3.7.5", "node-fetch": "^3.3.2" } }, "sha512-pxQ1986AuWfPX4oXzBvLwBnfgKDE5OMhAdR/5cZmRaB4Ygz5MecQybvwZupnRz341r2CtFmbk/BhSu7k2Lm+Jw=="],
|
||||
|
||||
"@libsql/isomorphic-fetch": ["@libsql/isomorphic-fetch@0.2.5", "", {}, "sha512-8s/B2TClEHms2yb+JGpsVRTPBfy1ih/Pq6h6gvyaNcYnMVJvgQRY7wAa8U2nD0dppbCuDU5evTNMEhrQ17ZKKg=="],
|
||||
|
||||
"@libsql/isomorphic-ws": ["@libsql/isomorphic-ws@0.1.5", "", { "dependencies": { "@types/ws": "^8.5.4", "ws": "^8.13.0" } }, "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg=="],
|
||||
|
||||
"@libsql/linux-arm64-gnu": ["@libsql/linux-arm64-gnu@0.3.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-mgeAUU1oqqh57k7I3cQyU6Trpdsdt607eFyEmH5QO7dv303ti+LjUvh1pp21QWV6WX7wZyjeJV1/VzEImB+jRg=="],
|
||||
"@libsql/linux-arm-gnueabihf": ["@libsql/linux-arm-gnueabihf@0.5.22", "", { "os": "linux", "cpu": "arm" }, "sha512-3Uo3SoDPJe/zBnyZKosziRGtszXaEtv57raWrZIahtQDsjxBVjuzYQinCm9LRCJCUT5t2r5Z5nLDPJi2CwZVoA=="],
|
||||
|
||||
"@libsql/linux-arm64-musl": ["@libsql/linux-arm64-musl@0.3.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-VEZtxghyK6zwGzU9PHohvNxthruSxBEnRrX7BSL5jQ62tN4n2JNepJ6SdzXp70pdzTfwroOj/eMwiPt94gkVRg=="],
|
||||
"@libsql/linux-arm-musleabihf": ["@libsql/linux-arm-musleabihf@0.5.22", "", { "os": "linux", "cpu": "arm" }, "sha512-LCsXh07jvSojTNJptT9CowOzwITznD+YFGGW+1XxUr7fS+7/ydUrpDfsMX7UqTqjm7xG17eq86VkWJgHJfvpNg=="],
|
||||
|
||||
"@libsql/linux-x64-gnu": ["@libsql/linux-x64-gnu@0.3.19", "", { "os": "linux", "cpu": "x64" }, "sha512-2t/J7LD5w2f63wGihEO+0GxfTyYIyLGEvTFEsMO16XI5o7IS9vcSHrxsvAJs4w2Pf907uDjmc7fUfMg6L82BrQ=="],
|
||||
"@libsql/linux-arm64-gnu": ["@libsql/linux-arm64-gnu@0.5.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-KSdnOMy88c9mpOFKUEzPskSaF3VLflfSUCBwas/pn1/sV3pEhtMF6H8VUCd2rsedwoukeeCSEONqX7LLnQwRMA=="],
|
||||
|
||||
"@libsql/linux-x64-musl": ["@libsql/linux-x64-musl@0.3.19", "", { "os": "linux", "cpu": "x64" }, "sha512-BLsXyJaL8gZD8+3W2LU08lDEd9MIgGds0yPy5iNPp8tfhXx3pV/Fge2GErN0FC+nzt4DYQtjL+A9GUMglQefXQ=="],
|
||||
"@libsql/linux-arm64-musl": ["@libsql/linux-arm64-musl@0.5.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-mCHSMAsDTLK5YH//lcV3eFEgiR23Ym0U9oEvgZA0667gqRZg/2px+7LshDvErEKv2XZ8ixzw3p1IrBzLQHGSsw=="],
|
||||
|
||||
"@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.3.19", "", { "os": "win32", "cpu": "x64" }, "sha512-ay1X9AobE4BpzG0XPw1gplyLZPGHIgJOovvW23gUrukRegiUP62uzhpRbKNogLlUOynyXeq//prHgPXiebUfWg=="],
|
||||
"@libsql/linux-x64-gnu": ["@libsql/linux-x64-gnu@0.5.22", "", { "os": "linux", "cpu": "x64" }, "sha512-kNBHaIkSg78Y4BqAdgjcR2mBilZXs4HYkAmi58J+4GRwDQZh5fIUWbnQvB9f95DkWUIGVeenqLRFY2pcTmlsew=="],
|
||||
|
||||
"@libsql/linux-x64-musl": ["@libsql/linux-x64-musl@0.5.22", "", { "os": "linux", "cpu": "x64" }, "sha512-UZ4Xdxm4pu3pQXjvfJiyCzZop/9j/eA2JjmhMaAhe3EVLH2g11Fy4fwyUp9sT1QJYR1kpc2JLuybPM0kuXv/Tg=="],
|
||||
|
||||
"@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.5.22", "", { "os": "win32", "cpu": "x64" }, "sha512-Fj0j8RnBpo43tVZUVoNK6BV/9AtDUM5S7DF3LB4qTYg1LMSZqi3yeCneUTLJD6XomQJlZzbI4mst89yspVSAnA=="],
|
||||
|
||||
"@mrleebo/prisma-ast": ["@mrleebo/prisma-ast@0.13.1", "", { "dependencies": { "chevrotain": "^10.5.0", "lilconfig": "^2.1.0" } }, "sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw=="],
|
||||
|
||||
@@ -90,16 +131,52 @@
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="],
|
||||
|
||||
"@types/esrecurse": ["@types/esrecurse@4.3.1", "", {}, "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||
|
||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||
|
||||
"@types/node": ["@types/node@25.2.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg=="],
|
||||
|
||||
"@types/react": ["@types/react@19.2.13", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ=="],
|
||||
|
||||
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
|
||||
|
||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.54.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/type-utils": "8.54.0", "@typescript-eslint/utils": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ=="],
|
||||
|
||||
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.54.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA=="],
|
||||
|
||||
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.54.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.54.0", "@typescript-eslint/types": "^8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g=="],
|
||||
|
||||
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0" } }, "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg=="],
|
||||
|
||||
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.54.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw=="],
|
||||
|
||||
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA=="],
|
||||
|
||||
"@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.54.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.54.0", "@typescript-eslint/tsconfig-utils": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA=="],
|
||||
|
||||
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.54.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA=="],
|
||||
|
||||
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="],
|
||||
|
||||
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||
|
||||
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
|
||||
|
||||
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||
|
||||
"async-mutex": ["async-mutex@0.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA=="],
|
||||
|
||||
"aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="],
|
||||
|
||||
"c12": ["c12@3.1.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^16.6.1", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.4.2", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw=="],
|
||||
@@ -114,12 +191,18 @@
|
||||
|
||||
"consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
|
||||
|
||||
"cross-fetch": ["cross-fetch@4.1.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
||||
|
||||
"data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="],
|
||||
|
||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
||||
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
|
||||
|
||||
"deepmerge-ts": ["deepmerge-ts@7.1.5", "", {}, "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw=="],
|
||||
|
||||
"defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
|
||||
@@ -136,12 +219,48 @@
|
||||
|
||||
"empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||
|
||||
"eslint": ["eslint@10.0.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.0", "@eslint/config-helpers": "^0.5.2", "@eslint/core": "^1.1.0", "@eslint/plugin-kit": "^0.6.0", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.0", "eslint-visitor-keys": "^5.0.0", "espree": "^11.1.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.1.1", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-O0piBKY36YSJhlFSG8p9VUdPV/SxxS4FYDWVpr/9GJuMaepzwlf4J8I4ov1b+ySQfDTPhc3DtLaxcT1fN0yqCg=="],
|
||||
|
||||
"eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="],
|
||||
|
||||
"eslint-scope": ["eslint-scope@9.1.0", "", { "dependencies": { "@types/esrecurse": "^4.3.1", "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-CkWE42hOJsNj9FJRaoMX9waUFYhqY4jmyLFdAdzZr6VaCg3ynLYx4WnOdkaIifGfH4gsUcBTn4OZbHXkpLD0FQ=="],
|
||||
|
||||
"eslint-visitor-keys": ["eslint-visitor-keys@5.0.0", "", {}, "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q=="],
|
||||
|
||||
"espree": ["espree@11.1.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^5.0.0" } }, "sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw=="],
|
||||
|
||||
"esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="],
|
||||
|
||||
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
|
||||
|
||||
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
|
||||
|
||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||
|
||||
"exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="],
|
||||
|
||||
"fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
||||
|
||||
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
|
||||
|
||||
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||
|
||||
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
||||
|
||||
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
|
||||
|
||||
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
||||
|
||||
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
|
||||
|
||||
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
|
||||
|
||||
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
||||
|
||||
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
|
||||
@@ -152,6 +271,8 @@
|
||||
|
||||
"giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="],
|
||||
|
||||
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
|
||||
"grammex": ["grammex@3.1.12", "", {}, "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ=="],
|
||||
@@ -164,6 +285,14 @@
|
||||
|
||||
"iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
|
||||
|
||||
"ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
||||
|
||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-property": ["is-property@1.0.2", "", {}, "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
@@ -172,20 +301,40 @@
|
||||
|
||||
"js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="],
|
||||
|
||||
"libsql": ["libsql@0.3.19", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2", "libsql": "^0.3.15" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.3.19", "@libsql/darwin-x64": "0.3.19", "@libsql/linux-arm64-gnu": "0.3.19", "@libsql/linux-arm64-musl": "0.3.19", "@libsql/linux-x64-gnu": "0.3.19", "@libsql/linux-x64-musl": "0.3.19", "@libsql/win32-x64-msvc": "0.3.19" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ] }, "sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA=="],
|
||||
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
|
||||
|
||||
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
||||
|
||||
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
|
||||
|
||||
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
||||
|
||||
"layerr": ["layerr@3.0.0", "", {}, "sha512-tv754Ki2dXpPVApOrjTyRo4/QegVb9eVFq4mjqp4+NM5NaX7syQvN5BBNfV/ZpAHCEHV24XdUVrBAoka4jt3pA=="],
|
||||
|
||||
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
||||
|
||||
"libsql": ["libsql@0.5.22", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.5.22", "@libsql/darwin-x64": "0.5.22", "@libsql/linux-arm-gnueabihf": "0.5.22", "@libsql/linux-arm-musleabihf": "0.5.22", "@libsql/linux-arm64-gnu": "0.5.22", "@libsql/linux-arm64-musl": "0.5.22", "@libsql/linux-x64-gnu": "0.5.22", "@libsql/linux-x64-musl": "0.5.22", "@libsql/win32-x64-msvc": "0.5.22" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "arm", "x64", "arm64", ] }, "sha512-NscWthMQt7fpU8lqd7LXMvT9pi+KhhmTHAJWUB/Lj6MWa0MKFv0F2V4C6WKKpjCVZl0VwcDz4nOI3CyaT1DDiA=="],
|
||||
|
||||
"lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
|
||||
|
||||
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
||||
|
||||
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||
|
||||
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
||||
|
||||
"lru.min": ["lru.min@1.1.4", "", {}, "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA=="],
|
||||
|
||||
"minimatch": ["minimatch@10.1.2", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.1" } }, "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"mysql2": ["mysql2@3.15.3", "", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.7.0", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg=="],
|
||||
|
||||
"named-placeholders": ["named-placeholders@1.1.6", "", { "dependencies": { "lru.min": "^1.1.0" } }, "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w=="],
|
||||
|
||||
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
|
||||
|
||||
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
||||
|
||||
"node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
|
||||
@@ -196,22 +345,38 @@
|
||||
|
||||
"ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
|
||||
|
||||
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||
|
||||
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
||||
|
||||
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
||||
|
||||
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||
|
||||
"perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="],
|
||||
|
||||
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||
|
||||
"pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
|
||||
|
||||
"postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="],
|
||||
|
||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||
|
||||
"prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="],
|
||||
|
||||
"prisma": ["prisma@7.3.0", "", { "dependencies": { "@prisma/config": "7.3.0", "@prisma/dev": "0.20.0", "@prisma/engines": "7.3.0", "@prisma/studio-core": "0.13.1", "mysql2": "3.15.3", "postgres": "3.4.7" }, "peerDependencies": { "better-sqlite3": ">=9.0.0", "typescript": ">=5.4.0" }, "optionalPeers": ["better-sqlite3", "typescript"], "bin": { "prisma": "build/index.js" } }, "sha512-ApYSOLHfMN8WftJA+vL6XwAPOh/aZ0BgUyyKPwUFgjARmG6EBI9LzDPf6SWULQMSAxydV9qn5gLj037nPNlg2w=="],
|
||||
|
||||
"promise-limit": ["promise-limit@2.7.0", "", {}, "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw=="],
|
||||
|
||||
"proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="],
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
"pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="],
|
||||
|
||||
"rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="],
|
||||
@@ -232,6 +397,8 @@
|
||||
|
||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
|
||||
"semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||
|
||||
"seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
@@ -246,20 +413,48 @@
|
||||
|
||||
"tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
|
||||
|
||||
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||
|
||||
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
|
||||
|
||||
"ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"typescript-eslint": ["typescript-eslint@8.54.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.54.0", "@typescript-eslint/parser": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ=="],
|
||||
|
||||
"ulidx": ["ulidx@2.4.1", "", { "dependencies": { "layerr": "^3.0.0" } }, "sha512-xY7c8LPyzvhvew0Fn+Ek3wBC9STZAuDI/Y5andCKi9AX6/jvfaX45PhsDX8oxgPL0YFp0Jhr8qWMbS/p9375Xg=="],
|
||||
|
||||
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||
|
||||
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
||||
|
||||
"valibot": ["valibot@1.2.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg=="],
|
||||
|
||||
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
|
||||
|
||||
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
||||
|
||||
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
|
||||
|
||||
"ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
|
||||
|
||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||
|
||||
"zeptomatch": ["zeptomatch@2.1.0", "", { "dependencies": { "grammex": "^3.1.11", "graphmatch": "^1.1.0" } }, "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA=="],
|
||||
|
||||
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client": ["@libsql/client@0.8.1", "", { "dependencies": { "@libsql/core": "^0.8.1", "@libsql/hrana-client": "^0.6.2", "js-base64": "^3.7.5", "libsql": "^0.3.10", "promise-limit": "^2.7.0" } }, "sha512-xGg0F4iTDFpeBZ0r4pA6icGsYa5rG6RAG+i/iLDnpCAnSuTqEWMDdPlVseiq4Z/91lWI9jvvKKiKpovqJ1kZWA=="],
|
||||
|
||||
"@prisma/dev/hono": ["hono@4.11.4", "", {}, "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA=="],
|
||||
|
||||
"@prisma/engines/@prisma/get-platform": ["@prisma/get-platform@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0" } }, "sha512-N7c6m4/I0Q6JYmWKP2RCD/sM9eWiyCPY98g5c0uEktObNSZnugW2U/PO+pwL0UaqzxqTXt7gTsYsb0FnMnJNbg=="],
|
||||
@@ -268,8 +463,36 @@
|
||||
|
||||
"@prisma/get-platform/@prisma/debug": ["@prisma/debug@7.2.0", "", {}, "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||
|
||||
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
|
||||
|
||||
"cross-fetch/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
||||
|
||||
"eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||
|
||||
"nypm/citty": ["citty@0.2.0", "", {}, "sha512-8csy5IBFI2ex2hTVpaHN2j+LNE199AgiI7y4dMintrr8i0lQiFn+0AWMZrWdHKIgMOer65f8IThysYhoReqjWA=="],
|
||||
|
||||
"proper-lockfile/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client/@libsql/core": ["@libsql/core@0.8.1", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-u6nrj6HZMTPsgJ9EBhLzO2uhqhlHQJQmVHV+0yFLvfGf3oSP8w7TjZCNUgu1G8jHISx6KFi7bmcrdXW9lRt++A=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client/@libsql/hrana-client": ["@libsql/hrana-client@0.6.2", "", { "dependencies": { "@libsql/isomorphic-fetch": "^0.2.1", "@libsql/isomorphic-ws": "^0.1.5", "js-base64": "^3.7.5", "node-fetch": "^3.3.2" } }, "sha512-MWxgD7mXLNf9FXXiM0bc90wCjZSpErWKr5mGza7ERy2FJNNMXd7JIOv+DepBA1FQTIfI8TFO4/QDYgaQC0goNw=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client/libsql": ["libsql@0.3.19", "", { "dependencies": { "@neon-rs/load": "^0.0.4", "detect-libc": "2.0.2", "libsql": "^0.3.15" }, "optionalDependencies": { "@libsql/darwin-arm64": "0.3.19", "@libsql/darwin-x64": "0.3.19", "@libsql/linux-arm64-gnu": "0.3.19", "@libsql/linux-arm64-musl": "0.3.19", "@libsql/linux-x64-gnu": "0.3.19", "@libsql/linux-x64-musl": "0.3.19", "@libsql/win32-x64-msvc": "0.3.19" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ] }, "sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client/libsql/@libsql/darwin-arm64": ["@libsql/darwin-arm64@0.3.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rmOqsLcDI65zzxlUOoEiPJLhqmbFsZF6p4UJQ2kMqB+Kc0Rt5/A1OAdOZ/Wo8fQfJWjR1IbkbpEINFioyKf+nQ=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client/libsql/@libsql/darwin-x64": ["@libsql/darwin-x64@0.3.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-q9O55B646zU+644SMmOQL3FIfpmEvdWpRpzubwFc2trsa+zoBlSkHuzU9v/C+UNoPHQVRMP7KQctJ455I/h/xw=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client/libsql/@libsql/linux-arm64-gnu": ["@libsql/linux-arm64-gnu@0.3.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-mgeAUU1oqqh57k7I3cQyU6Trpdsdt607eFyEmH5QO7dv303ti+LjUvh1pp21QWV6WX7wZyjeJV1/VzEImB+jRg=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client/libsql/@libsql/linux-arm64-musl": ["@libsql/linux-arm64-musl@0.3.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-VEZtxghyK6zwGzU9PHohvNxthruSxBEnRrX7BSL5jQ62tN4n2JNepJ6SdzXp70pdzTfwroOj/eMwiPt94gkVRg=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client/libsql/@libsql/linux-x64-gnu": ["@libsql/linux-x64-gnu@0.3.19", "", { "os": "linux", "cpu": "x64" }, "sha512-2t/J7LD5w2f63wGihEO+0GxfTyYIyLGEvTFEsMO16XI5o7IS9vcSHrxsvAJs4w2Pf907uDjmc7fUfMg6L82BrQ=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client/libsql/@libsql/linux-x64-musl": ["@libsql/linux-x64-musl@0.3.19", "", { "os": "linux", "cpu": "x64" }, "sha512-BLsXyJaL8gZD8+3W2LU08lDEd9MIgGds0yPy5iNPp8tfhXx3pV/Fge2GErN0FC+nzt4DYQtjL+A9GUMglQefXQ=="],
|
||||
|
||||
"@prisma/adapter-libsql/@libsql/client/libsql/@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.3.19", "", { "os": "win32", "cpu": "x64" }, "sha512-ay1X9AobE4BpzG0XPw1gplyLZPGHIgJOovvW23gUrukRegiUP62uzhpRbKNogLlUOynyXeq//prHgPXiebUfWg=="],
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,12 @@
|
||||
import js from '@eslint/js'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import prettier from 'eslint-config-prettier'
|
||||
|
||||
export default tseslint.config(js.configs.recommended, ...tseslint.configs.recommended, prettier, {
|
||||
ignores: ['dist/**', 'node_modules/**'],
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
},
|
||||
})
|
||||
+21
-5
@@ -1,15 +1,31 @@
|
||||
{
|
||||
"name": "forgery",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "bun run --hot src/index.ts"
|
||||
"dev": "bun run --hot src/index.ts",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"test": "bun test",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@libsql/client": "^0.17.0",
|
||||
"@prisma/adapter-libsql": "^7.3.0",
|
||||
"@prisma/client": "^7.3.0",
|
||||
"hono": "^4.11.8"
|
||||
"hono": "^4.11.8",
|
||||
"ulidx": "^2.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"prisma": "^7.3.0"
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@types/bun": "^1.3.8",
|
||||
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
||||
"@typescript-eslint/parser": "^8.54.0",
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"prettier": "^3.8.1",
|
||||
"prisma": "^7.3.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.54.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-6
@@ -1,12 +1,11 @@
|
||||
// This file was generated by Prisma, and assumes you run Prisma commands using `bun --bun run prisma [command]`.
|
||||
import { defineConfig, env } from "prisma/config";
|
||||
import { defineConfig } from 'prisma/config'
|
||||
|
||||
export default defineConfig({
|
||||
schema: "prisma/schema.prisma",
|
||||
schema: 'prisma/schema.prisma',
|
||||
migrations: {
|
||||
path: "prisma/migrations",
|
||||
path: 'prisma/migrations',
|
||||
},
|
||||
datasource: {
|
||||
url: env("DATABASE_URL"),
|
||||
url: process.env.DATABASE_URL || 'file:./dev.db',
|
||||
},
|
||||
});
|
||||
})
|
||||
+95
-2
@@ -2,10 +2,103 @@
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client"
|
||||
output = "../src/generated/prisma"
|
||||
provider = "prisma-client"
|
||||
output = "../src/generated/prisma"
|
||||
previewFeatures = ["driverAdapters"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
}
|
||||
|
||||
model Asset {
|
||||
id String @id
|
||||
name String
|
||||
type String
|
||||
path String
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
// Relations
|
||||
characters Character[]
|
||||
equipments Equipment[]
|
||||
generations Generation[]
|
||||
|
||||
@@map("assets")
|
||||
}
|
||||
|
||||
model Character {
|
||||
id String @id
|
||||
name String
|
||||
description String?
|
||||
imageId String @map("image_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
// Relations
|
||||
image Asset @relation(fields: [imageId], references: [id])
|
||||
generations Generation[]
|
||||
|
||||
@@map("characters")
|
||||
}
|
||||
|
||||
model Category {
|
||||
id String @id
|
||||
name String
|
||||
parentId String? @map("parent_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
// Relations
|
||||
parent Category? @relation("CategoryToSubCategory", fields: [parentId], references: [id])
|
||||
subCategories Category[] @relation("CategoryToSubCategory")
|
||||
equipmentsAsMain Equipment[] @relation("CategoryMain")
|
||||
equipmentsAsSub Equipment[] @relation("CategorySub")
|
||||
|
||||
@@map("categories")
|
||||
}
|
||||
|
||||
model Equipment {
|
||||
id String @id
|
||||
name String
|
||||
description String
|
||||
categoryId String @map("category_id")
|
||||
subCategoryId String? @map("sub_category_id")
|
||||
imageId String @map("image_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
// Relations
|
||||
category Category @relation("CategoryMain", fields: [categoryId], references: [id])
|
||||
subCategory Category? @relation("CategorySub", fields: [subCategoryId], references: [id])
|
||||
image Asset @relation(fields: [imageId], references: [id])
|
||||
generations GenerationEquipment[]
|
||||
|
||||
@@map("equipments")
|
||||
}
|
||||
|
||||
model Generation {
|
||||
id String @id
|
||||
characterId String @map("character_id")
|
||||
imageId String @map("image_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
// Relations
|
||||
character Character @relation(fields: [characterId], references: [id])
|
||||
image Asset @relation(fields: [imageId], references: [id])
|
||||
equipments GenerationEquipment[]
|
||||
|
||||
@@map("generations")
|
||||
}
|
||||
|
||||
model GenerationEquipment {
|
||||
generationId String @map("generation_id")
|
||||
equipmentId String @map("equipment_id")
|
||||
|
||||
generation Generation @relation(fields: [generationId], references: [id])
|
||||
equipment Equipment @relation(fields: [equipmentId], references: [id])
|
||||
|
||||
@@id([generationId, equipmentId])
|
||||
@@map("generation_equipments")
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { describe, it, expect, mock, afterEach } from 'bun:test'
|
||||
import asset from './asset'
|
||||
|
||||
const mockAssetService = {
|
||||
createAsset: mock(),
|
||||
}
|
||||
|
||||
mock.module('../service/asset', () => ({
|
||||
AssetService: mockAssetService,
|
||||
}))
|
||||
|
||||
describe('Asset API', () => {
|
||||
afterEach(() => {
|
||||
mockAssetService.createAsset.mockClear()
|
||||
})
|
||||
|
||||
it('POST /upload should create asset', async () => {
|
||||
mockAssetService.createAsset.mockResolvedValue({ id: '1', name: 'Test' })
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('file', new File(['test'], 'test.png', { type: 'image/png' }))
|
||||
formData.append('name', 'Test Asset')
|
||||
|
||||
const req = new Request('http://localhost/upload', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
})
|
||||
|
||||
const res = await asset.fetch(req)
|
||||
expect(res.status).toBe(201)
|
||||
expect(await res.json()).toEqual({ id: '1', name: 'Test' })
|
||||
expect(mockAssetService.createAsset).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Hono } from 'hono'
|
||||
import { AssetService } from '../service/asset'
|
||||
|
||||
const asset = new Hono()
|
||||
|
||||
asset.post('/upload', async (c) => {
|
||||
const body = await c.req.parseBody()
|
||||
const file = body['file']
|
||||
const name = body['name'] as string
|
||||
|
||||
if (!file || !(file instanceof File)) {
|
||||
return c.json({ error: 'File is required' }, 400)
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
return c.json({ error: 'Name is required' }, 400)
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await AssetService.createAsset(file, {
|
||||
name,
|
||||
type: file.type,
|
||||
})
|
||||
return c.json(result, 201)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return c.json({ error: 'Internal Server Error' }, 500)
|
||||
}
|
||||
})
|
||||
|
||||
export default asset
|
||||
@@ -0,0 +1,48 @@
|
||||
import { describe, it, expect, mock, afterEach } from 'bun:test'
|
||||
import character from './character'
|
||||
|
||||
const mockCharacterService = {
|
||||
createCharacter: mock(),
|
||||
listCharacters: mock(),
|
||||
updateCharacter: mock(),
|
||||
deleteCharacter: mock(),
|
||||
}
|
||||
|
||||
mock.module('../service/character', () => ({
|
||||
CharacterService: mockCharacterService,
|
||||
}))
|
||||
|
||||
describe('Character API', () => {
|
||||
afterEach(() => {
|
||||
mockCharacterService.createCharacter.mockClear()
|
||||
mockCharacterService.listCharacters.mockClear()
|
||||
mockCharacterService.updateCharacter.mockClear()
|
||||
mockCharacterService.deleteCharacter.mockClear()
|
||||
})
|
||||
|
||||
it('GET / should list characters', async () => {
|
||||
mockCharacterService.listCharacters.mockResolvedValue({ items: [], total: 0 })
|
||||
|
||||
const req = new Request('http://localhost/', {
|
||||
method: 'GET',
|
||||
})
|
||||
|
||||
const res = await character.fetch(req)
|
||||
expect(res.status).toBe(200)
|
||||
expect(mockCharacterService.listCharacters).toHaveBeenCalledWith({ page: 1, limit: 10 })
|
||||
})
|
||||
|
||||
it('POST / should create character', async () => {
|
||||
mockCharacterService.createCharacter.mockResolvedValue({ id: '1', name: 'Char' })
|
||||
|
||||
const req = new Request('http://localhost/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ name: 'Char', imageId: 'img1' }),
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
|
||||
const res = await character.fetch(req)
|
||||
expect(res.status).toBe(201)
|
||||
expect(await res.json()).toEqual({ id: '1', name: 'Char' })
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Hono } from 'hono'
|
||||
import { CharacterService } from '../service/character'
|
||||
|
||||
const character = new Hono()
|
||||
|
||||
character.get('/', async (c) => {
|
||||
const page = parseInt(c.req.query('page') || '1')
|
||||
const limit = parseInt(c.req.query('limit') || '10')
|
||||
const result = await CharacterService.listCharacters({ page, limit })
|
||||
return c.json(result)
|
||||
})
|
||||
|
||||
character.post('/', async (c) => {
|
||||
const body = await c.req.json()
|
||||
const { name, description, imageId } = body
|
||||
if (!name || !imageId) {
|
||||
return c.json({ error: 'Name and Image ID are required' }, 400)
|
||||
}
|
||||
const result = await CharacterService.createCharacter({ name, description, imageId })
|
||||
return c.json(result, 201)
|
||||
})
|
||||
|
||||
character.put('/:id', async (c) => {
|
||||
const id = c.req.param('id')
|
||||
const body = await c.req.json()
|
||||
const result = await CharacterService.updateCharacter(id, body)
|
||||
return c.json(result)
|
||||
})
|
||||
|
||||
character.delete('/:id', async (c) => {
|
||||
const id = c.req.param('id')
|
||||
await CharacterService.deleteCharacter(id)
|
||||
return c.json({ success: true }, 200)
|
||||
})
|
||||
|
||||
export default character
|
||||
@@ -0,0 +1,31 @@
|
||||
import { describe, it, expect, mock, afterEach } from 'bun:test'
|
||||
import equipment from './equipment'
|
||||
|
||||
const mockEquipmentService = {
|
||||
listEquipments: mock(),
|
||||
}
|
||||
|
||||
mock.module('../service/equipment', () => ({
|
||||
EquipmentService: mockEquipmentService,
|
||||
}))
|
||||
|
||||
describe('Equipment API', () => {
|
||||
afterEach(() => {
|
||||
mockEquipmentService.listEquipments.mockClear()
|
||||
})
|
||||
|
||||
it('GET / should list equipments with filters', async () => {
|
||||
mockEquipmentService.listEquipments.mockResolvedValue({ items: [], total: 0 })
|
||||
|
||||
const req = new Request('http://localhost/?categoryId=cat1', {
|
||||
method: 'GET',
|
||||
})
|
||||
|
||||
const res = await equipment.fetch(req)
|
||||
expect(res.status).toBe(200)
|
||||
expect(mockEquipmentService.listEquipments).toHaveBeenCalledWith(
|
||||
{ page: 1, limit: 10 },
|
||||
{ categoryId: 'cat1', subCategoryId: undefined },
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Hono } from 'hono'
|
||||
import { EquipmentService } from '../service/equipment'
|
||||
|
||||
const equipment = new Hono()
|
||||
|
||||
equipment.get('/', async (c) => {
|
||||
const page = parseInt(c.req.query('page') || '1')
|
||||
const limit = parseInt(c.req.query('limit') || '10')
|
||||
const categoryId = c.req.query('categoryId')
|
||||
const subCategoryId = c.req.query('subCategoryId')
|
||||
|
||||
const result = await EquipmentService.listEquipments(
|
||||
{ page, limit },
|
||||
{ categoryId, subCategoryId },
|
||||
)
|
||||
return c.json(result)
|
||||
})
|
||||
|
||||
export default equipment
|
||||
@@ -0,0 +1,31 @@
|
||||
import { describe, it, expect, mock, afterEach } from 'bun:test'
|
||||
import generation from './generation'
|
||||
|
||||
const mockGenerationService = {
|
||||
listGenerations: mock(),
|
||||
}
|
||||
|
||||
mock.module('../service/generation', () => ({
|
||||
GenerationService: mockGenerationService,
|
||||
}))
|
||||
|
||||
describe('Generation API', () => {
|
||||
afterEach(() => {
|
||||
mockGenerationService.listGenerations.mockClear()
|
||||
})
|
||||
|
||||
it('GET / should list generations with filters', async () => {
|
||||
mockGenerationService.listGenerations.mockResolvedValue({ items: [], total: 0 })
|
||||
|
||||
const req = new Request('http://localhost/?equipmentId=eq1', {
|
||||
method: 'GET',
|
||||
})
|
||||
|
||||
const res = await generation.fetch(req)
|
||||
expect(res.status).toBe(200)
|
||||
expect(mockGenerationService.listGenerations).toHaveBeenCalledWith(
|
||||
{ page: 1, limit: 10 },
|
||||
{ characterId: undefined, equipmentId: 'eq1' },
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Hono } from 'hono'
|
||||
import { GenerationService } from '../service/generation'
|
||||
|
||||
const generation = new Hono()
|
||||
|
||||
generation.get('/', async (c) => {
|
||||
const page = parseInt(c.req.query('page') || '1')
|
||||
const limit = parseInt(c.req.query('limit') || '10')
|
||||
const characterId = c.req.query('characterId')
|
||||
const equipmentId = c.req.query('equipmentId')
|
||||
|
||||
const result = await GenerationService.listGenerations(
|
||||
{ page, limit },
|
||||
{ characterId, equipmentId },
|
||||
)
|
||||
return c.json(result)
|
||||
})
|
||||
|
||||
export default generation
|
||||
@@ -0,0 +1,11 @@
|
||||
import { PrismaClient } from './generated/prisma/client'
|
||||
import { PrismaLibSql } from '@prisma/adapter-libsql'
|
||||
import { createClient } from '@libsql/client'
|
||||
|
||||
const libsql = createClient({
|
||||
url: process.env.DATABASE_URL || 'file:./dev.db',
|
||||
})
|
||||
|
||||
const adapter = new PrismaLibSql(libsql as any)
|
||||
|
||||
export const prisma = new PrismaClient({ adapter })
|
||||
@@ -0,0 +1,48 @@
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
|
||||
// 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 Asset
|
||||
*
|
||||
*/
|
||||
export type Asset = Prisma.AssetModel
|
||||
/**
|
||||
* Model Character
|
||||
*
|
||||
*/
|
||||
export type Character = Prisma.CharacterModel
|
||||
/**
|
||||
* Model Category
|
||||
*
|
||||
*/
|
||||
export type Category = Prisma.CategoryModel
|
||||
/**
|
||||
* Model Equipment
|
||||
*
|
||||
*/
|
||||
export type Equipment = Prisma.EquipmentModel
|
||||
/**
|
||||
* Model Generation
|
||||
*
|
||||
*/
|
||||
export type Generation = Prisma.GenerationModel
|
||||
/**
|
||||
* Model GenerationEquipment
|
||||
*
|
||||
*/
|
||||
export type GenerationEquipment = Prisma.GenerationEquipmentModel
|
||||
@@ -0,0 +1,74 @@
|
||||
/* !!! 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()
|
||||
* // Fetch zero or more Assets
|
||||
* const assets = await prisma.asset.findMany()
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://pris.ly/d/client).
|
||||
*/
|
||||
export const PrismaClient = $Class.getPrismaClientClass()
|
||||
export type PrismaClient<
|
||||
LogOpts extends Prisma.LogLevel = never,
|
||||
OmitOpts extends Prisma.PrismaClientOptions['omit'] = Prisma.PrismaClientOptions['omit'],
|
||||
ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs,
|
||||
> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>
|
||||
export { Prisma }
|
||||
|
||||
/**
|
||||
* Model Asset
|
||||
*
|
||||
*/
|
||||
export type Asset = Prisma.AssetModel
|
||||
/**
|
||||
* Model Character
|
||||
*
|
||||
*/
|
||||
export type Character = Prisma.CharacterModel
|
||||
/**
|
||||
* Model Category
|
||||
*
|
||||
*/
|
||||
export type Category = Prisma.CategoryModel
|
||||
/**
|
||||
* Model Equipment
|
||||
*
|
||||
*/
|
||||
export type Equipment = Prisma.EquipmentModel
|
||||
/**
|
||||
* Model Generation
|
||||
*
|
||||
*/
|
||||
export type Generation = Prisma.GenerationModel
|
||||
/**
|
||||
* Model GenerationEquipment
|
||||
*
|
||||
*/
|
||||
export type GenerationEquipment = Prisma.GenerationEquipmentModel
|
||||
@@ -0,0 +1,214 @@
|
||||
/* !!! 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[]
|
||||
notIn?: string[]
|
||||
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 DateTimeFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[]
|
||||
notIn?: Date[] | string[]
|
||||
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 StringWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
in?: string[]
|
||||
notIn?: string[]
|
||||
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 DateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[]
|
||||
notIn?: Date[] | string[]
|
||||
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 StringNullableFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||
in?: string[] | null
|
||||
notIn?: string[] | 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 SortOrderInput = {
|
||||
sort: Prisma.SortOrder
|
||||
nulls?: Prisma.NullsOrder
|
||||
}
|
||||
|
||||
export type StringNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||
in?: string[] | null
|
||||
notIn?: string[] | 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 NestedStringFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
in?: string[]
|
||||
notIn?: string[]
|
||||
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 NestedDateTimeFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[]
|
||||
notIn?: Date[] | string[]
|
||||
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[]
|
||||
notIn?: string[]
|
||||
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[]
|
||||
notIn?: number[]
|
||||
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 NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
|
||||
in?: Date[] | string[]
|
||||
notIn?: Date[] | string[]
|
||||
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 NestedStringNullableFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||
in?: string[] | null
|
||||
notIn?: string[] | 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 NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
|
||||
in?: string[] | null
|
||||
notIn?: string[] | 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[] | null
|
||||
notIn?: number[] | 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
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
|
||||
// biome-ignore-all lint: generated file
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* This file exports all enum related types from the schema.
|
||||
*
|
||||
* 🟢 You can import this file directly.
|
||||
*/
|
||||
|
||||
// This file is empty because there are no enums in the schema.
|
||||
export {}
|
||||
@@ -0,0 +1,277 @@
|
||||
/* !!! 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: ['driverAdapters'],
|
||||
clientVersion: '7.3.0',
|
||||
engineVersion: '9d6ad21cbbceab97458517b147a6a09ff43aa735',
|
||||
activeProvider: 'sqlite',
|
||||
inlineSchema:
|
||||
'// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\ngenerator client {\n provider = "prisma-client"\n output = "../src/generated/prisma"\n previewFeatures = ["driverAdapters"]\n}\n\ndatasource db {\n provider = "sqlite"\n}\n\nmodel Asset {\n id String @id\n name String\n type String\n path String\n createdAt DateTime @default(now()) @map("created_at")\n updatedAt DateTime @updatedAt @map("updated_at")\n\n // Relations\n characters Character[]\n equipments Equipment[]\n generations Generation[]\n\n @@map("assets")\n}\n\nmodel Character {\n id String @id\n name String\n description String?\n imageId String @map("image_id")\n createdAt DateTime @default(now()) @map("created_at")\n updatedAt DateTime @updatedAt @map("updated_at")\n\n // Relations\n image Asset @relation(fields: [imageId], references: [id])\n generations Generation[]\n\n @@map("characters")\n}\n\nmodel Category {\n id String @id\n name String\n parentId String? @map("parent_id")\n createdAt DateTime @default(now()) @map("created_at")\n updatedAt DateTime @updatedAt @map("updated_at")\n\n // Relations\n parent Category? @relation("CategoryToSubCategory", fields: [parentId], references: [id])\n subCategories Category[] @relation("CategoryToSubCategory")\n equipmentsAsMain Equipment[] @relation("CategoryMain")\n equipmentsAsSub Equipment[] @relation("CategorySub")\n\n @@map("categories")\n}\n\nmodel Equipment {\n id String @id\n name String\n description String\n categoryId String @map("category_id")\n subCategoryId String? @map("sub_category_id")\n imageId String @map("image_id")\n createdAt DateTime @default(now()) @map("created_at")\n updatedAt DateTime @updatedAt @map("updated_at")\n\n // Relations\n category Category @relation("CategoryMain", fields: [categoryId], references: [id])\n subCategory Category? @relation("CategorySub", fields: [subCategoryId], references: [id])\n image Asset @relation(fields: [imageId], references: [id])\n generations GenerationEquipment[]\n\n @@map("equipments")\n}\n\nmodel Generation {\n id String @id\n characterId String @map("character_id")\n imageId String @map("image_id")\n createdAt DateTime @default(now()) @map("created_at")\n updatedAt DateTime @updatedAt @map("updated_at")\n\n // Relations\n character Character @relation(fields: [characterId], references: [id])\n image Asset @relation(fields: [imageId], references: [id])\n equipments GenerationEquipment[]\n\n @@map("generations")\n}\n\nmodel GenerationEquipment {\n generationId String @map("generation_id")\n equipmentId String @map("equipment_id")\n\n generation Generation @relation(fields: [generationId], references: [id])\n equipment Equipment @relation(fields: [equipmentId], references: [id])\n\n @@id([generationId, equipmentId])\n @@map("generation_equipments")\n}\n',
|
||||
runtimeDataModel: {
|
||||
models: {},
|
||||
enums: {},
|
||||
types: {},
|
||||
},
|
||||
}
|
||||
|
||||
config.runtimeDataModel = JSON.parse(
|
||||
'{"models":{"Asset":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"name","kind":"scalar","type":"String"},{"name":"type","kind":"scalar","type":"String"},{"name":"path","kind":"scalar","type":"String"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"updatedAt","kind":"scalar","type":"DateTime","dbName":"updated_at"},{"name":"characters","kind":"object","type":"Character","relationName":"AssetToCharacter"},{"name":"equipments","kind":"object","type":"Equipment","relationName":"AssetToEquipment"},{"name":"generations","kind":"object","type":"Generation","relationName":"AssetToGeneration"}],"dbName":"assets"},"Character":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"name","kind":"scalar","type":"String"},{"name":"description","kind":"scalar","type":"String"},{"name":"imageId","kind":"scalar","type":"String","dbName":"image_id"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"updatedAt","kind":"scalar","type":"DateTime","dbName":"updated_at"},{"name":"image","kind":"object","type":"Asset","relationName":"AssetToCharacter"},{"name":"generations","kind":"object","type":"Generation","relationName":"CharacterToGeneration"}],"dbName":"characters"},"Category":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"name","kind":"scalar","type":"String"},{"name":"parentId","kind":"scalar","type":"String","dbName":"parent_id"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"updatedAt","kind":"scalar","type":"DateTime","dbName":"updated_at"},{"name":"parent","kind":"object","type":"Category","relationName":"CategoryToSubCategory"},{"name":"subCategories","kind":"object","type":"Category","relationName":"CategoryToSubCategory"},{"name":"equipmentsAsMain","kind":"object","type":"Equipment","relationName":"CategoryMain"},{"name":"equipmentsAsSub","kind":"object","type":"Equipment","relationName":"CategorySub"}],"dbName":"categories"},"Equipment":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"name","kind":"scalar","type":"String"},{"name":"description","kind":"scalar","type":"String"},{"name":"categoryId","kind":"scalar","type":"String","dbName":"category_id"},{"name":"subCategoryId","kind":"scalar","type":"String","dbName":"sub_category_id"},{"name":"imageId","kind":"scalar","type":"String","dbName":"image_id"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"updatedAt","kind":"scalar","type":"DateTime","dbName":"updated_at"},{"name":"category","kind":"object","type":"Category","relationName":"CategoryMain"},{"name":"subCategory","kind":"object","type":"Category","relationName":"CategorySub"},{"name":"image","kind":"object","type":"Asset","relationName":"AssetToEquipment"},{"name":"generations","kind":"object","type":"GenerationEquipment","relationName":"EquipmentToGenerationEquipment"}],"dbName":"equipments"},"Generation":{"fields":[{"name":"id","kind":"scalar","type":"String"},{"name":"characterId","kind":"scalar","type":"String","dbName":"character_id"},{"name":"imageId","kind":"scalar","type":"String","dbName":"image_id"},{"name":"createdAt","kind":"scalar","type":"DateTime","dbName":"created_at"},{"name":"updatedAt","kind":"scalar","type":"DateTime","dbName":"updated_at"},{"name":"character","kind":"object","type":"Character","relationName":"CharacterToGeneration"},{"name":"image","kind":"object","type":"Asset","relationName":"AssetToGeneration"},{"name":"equipments","kind":"object","type":"GenerationEquipment","relationName":"GenerationToGenerationEquipment"}],"dbName":"generations"},"GenerationEquipment":{"fields":[{"name":"generationId","kind":"scalar","type":"String","dbName":"generation_id"},{"name":"equipmentId","kind":"scalar","type":"String","dbName":"equipment_id"},{"name":"generation","kind":"object","type":"Generation","relationName":"GenerationToGenerationEquipment"},{"name":"equipment","kind":"object","type":"Equipment","relationName":"EquipmentToGenerationEquipment"}],"dbName":"generation_equipments"}},"enums":{},"types":{}}',
|
||||
)
|
||||
|
||||
async function decodeBase64AsWasm(wasmBase64: string): Promise<WebAssembly.Module> {
|
||||
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.sqlite.mjs'),
|
||||
|
||||
getQueryCompilerWasmModule: async () => {
|
||||
const { wasm } =
|
||||
await import('@prisma/client/runtime/query_compiler_fast_bg.sqlite.wasm-base64.mjs')
|
||||
return await decodeBase64AsWasm(wasm)
|
||||
},
|
||||
|
||||
importName: './query_compiler_fast_bg.js',
|
||||
}
|
||||
|
||||
export type LogOptions<ClientOptions extends Prisma.PrismaClientOptions> =
|
||||
'log' extends keyof ClientOptions
|
||||
? ClientOptions['log'] extends Array<Prisma.LogLevel | Prisma.LogDefinition>
|
||||
? Prisma.GetEvents<ClientOptions['log']>
|
||||
: never
|
||||
: never
|
||||
|
||||
export interface PrismaClientConstructor {
|
||||
/**
|
||||
* ## Prisma Client
|
||||
*
|
||||
* Type-safe database client for TypeScript
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient()
|
||||
* // Fetch zero or more Assets
|
||||
* const assets = await prisma.asset.findMany()
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://pris.ly/d/client).
|
||||
*/
|
||||
|
||||
new <
|
||||
Options extends Prisma.PrismaClientOptions = Prisma.PrismaClientOptions,
|
||||
LogOpts extends LogOptions<Options> = LogOptions<Options>,
|
||||
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<Options, Prisma.PrismaClientOptions>,
|
||||
): PrismaClient<LogOpts, OmitOpts, ExtArgs>
|
||||
}
|
||||
|
||||
/**
|
||||
* ## Prisma Client
|
||||
*
|
||||
* Type-safe database client for TypeScript
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient()
|
||||
* // Fetch zero or more Assets
|
||||
* const assets = await prisma.asset.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<ExtArgs>['other'] }
|
||||
|
||||
$on<V extends LogOpts>(
|
||||
eventType: V,
|
||||
callback: (event: V extends 'query' ? Prisma.QueryEvent : Prisma.LogEvent) => void,
|
||||
): PrismaClient
|
||||
|
||||
/**
|
||||
* Connect with the database
|
||||
*/
|
||||
$connect(): runtime.Types.Utils.JsPromise<void>
|
||||
|
||||
/**
|
||||
* Disconnect from the database
|
||||
*/
|
||||
$disconnect(): runtime.Types.Utils.JsPromise<void>
|
||||
|
||||
/**
|
||||
* 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<T = unknown>(
|
||||
query: TemplateStringsArray | Prisma.Sql,
|
||||
...values: any[]
|
||||
): Prisma.PrismaPromise<number>
|
||||
|
||||
/**
|
||||
* 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<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<number>
|
||||
|
||||
/**
|
||||
* 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<T = unknown>(
|
||||
query: TemplateStringsArray | Prisma.Sql,
|
||||
...values: any[]
|
||||
): Prisma.PrismaPromise<T>
|
||||
|
||||
/**
|
||||
* 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<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<T>
|
||||
|
||||
/**
|
||||
* 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/concepts/components/prisma-client/transactions).
|
||||
*/
|
||||
$transaction<P extends Prisma.PrismaPromise<any>[]>(
|
||||
arg: [...P],
|
||||
options?: { isolationLevel?: Prisma.TransactionIsolationLevel },
|
||||
): runtime.Types.Utils.JsPromise<runtime.Types.Utils.UnwrapTuple<P>>
|
||||
|
||||
$transaction<R>(
|
||||
fn: (prisma: Omit<PrismaClient, runtime.ITXClientDenyList>) => runtime.Types.Utils.JsPromise<R>,
|
||||
options?: {
|
||||
maxWait?: number
|
||||
timeout?: number
|
||||
isolationLevel?: Prisma.TransactionIsolationLevel
|
||||
},
|
||||
): runtime.Types.Utils.JsPromise<R>
|
||||
|
||||
$extends: runtime.Types.Extensions.ExtendsHook<
|
||||
'extends',
|
||||
Prisma.TypeMapCb<OmitOpts>,
|
||||
ExtArgs,
|
||||
runtime.Types.Utils.Call<
|
||||
Prisma.TypeMapCb<OmitOpts>,
|
||||
{
|
||||
extArgs: ExtArgs
|
||||
}
|
||||
>
|
||||
>
|
||||
|
||||
/**
|
||||
* `prisma.asset`: Exposes CRUD operations for the **Asset** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more Assets
|
||||
* const assets = await prisma.asset.findMany()
|
||||
* ```
|
||||
*/
|
||||
get asset(): Prisma.AssetDelegate<ExtArgs, { omit: OmitOpts }>
|
||||
|
||||
/**
|
||||
* `prisma.character`: Exposes CRUD operations for the **Character** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more Characters
|
||||
* const characters = await prisma.character.findMany()
|
||||
* ```
|
||||
*/
|
||||
get character(): Prisma.CharacterDelegate<ExtArgs, { omit: OmitOpts }>
|
||||
|
||||
/**
|
||||
* `prisma.category`: Exposes CRUD operations for the **Category** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more Categories
|
||||
* const categories = await prisma.category.findMany()
|
||||
* ```
|
||||
*/
|
||||
get category(): Prisma.CategoryDelegate<ExtArgs, { omit: OmitOpts }>
|
||||
|
||||
/**
|
||||
* `prisma.equipment`: Exposes CRUD operations for the **Equipment** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more Equipment
|
||||
* const equipment = await prisma.equipment.findMany()
|
||||
* ```
|
||||
*/
|
||||
get equipment(): Prisma.EquipmentDelegate<ExtArgs, { omit: OmitOpts }>
|
||||
|
||||
/**
|
||||
* `prisma.generation`: Exposes CRUD operations for the **Generation** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more Generations
|
||||
* const generations = await prisma.generation.findMany()
|
||||
* ```
|
||||
*/
|
||||
get generation(): Prisma.GenerationDelegate<ExtArgs, { omit: OmitOpts }>
|
||||
|
||||
/**
|
||||
* `prisma.generationEquipment`: Exposes CRUD operations for the **GenerationEquipment** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more GenerationEquipments
|
||||
* const generationEquipments = await prisma.generationEquipment.findMany()
|
||||
* ```
|
||||
*/
|
||||
get generationEquipment(): Prisma.GenerationEquipmentDelegate<ExtArgs, { omit: OmitOpts }>
|
||||
}
|
||||
|
||||
export function getPrismaClientClass(): PrismaClientConstructor {
|
||||
return runtime.getPrismaClient(config) as unknown as PrismaClientConstructor
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,151 @@
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
|
||||
// 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 = {
|
||||
Asset: 'Asset',
|
||||
Character: 'Character',
|
||||
Category: 'Category',
|
||||
Equipment: 'Equipment',
|
||||
Generation: 'Generation',
|
||||
GenerationEquipment: 'GenerationEquipment',
|
||||
} as const
|
||||
|
||||
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
||||
|
||||
/*
|
||||
* Enums
|
||||
*/
|
||||
|
||||
export const TransactionIsolationLevel = runtime.makeStrictEnum({
|
||||
Serializable: 'Serializable',
|
||||
} as const)
|
||||
|
||||
export type TransactionIsolationLevel =
|
||||
(typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel]
|
||||
|
||||
export const AssetScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
type: 'type',
|
||||
path: 'path',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
} as const
|
||||
|
||||
export type AssetScalarFieldEnum = (typeof AssetScalarFieldEnum)[keyof typeof AssetScalarFieldEnum]
|
||||
|
||||
export const CharacterScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
imageId: 'imageId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
} as const
|
||||
|
||||
export type CharacterScalarFieldEnum =
|
||||
(typeof CharacterScalarFieldEnum)[keyof typeof CharacterScalarFieldEnum]
|
||||
|
||||
export const CategoryScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
parentId: 'parentId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
} as const
|
||||
|
||||
export type CategoryScalarFieldEnum =
|
||||
(typeof CategoryScalarFieldEnum)[keyof typeof CategoryScalarFieldEnum]
|
||||
|
||||
export const EquipmentScalarFieldEnum = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
categoryId: 'categoryId',
|
||||
subCategoryId: 'subCategoryId',
|
||||
imageId: 'imageId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
} as const
|
||||
|
||||
export type EquipmentScalarFieldEnum =
|
||||
(typeof EquipmentScalarFieldEnum)[keyof typeof EquipmentScalarFieldEnum]
|
||||
|
||||
export const GenerationScalarFieldEnum = {
|
||||
id: 'id',
|
||||
characterId: 'characterId',
|
||||
imageId: 'imageId',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt',
|
||||
} as const
|
||||
|
||||
export type GenerationScalarFieldEnum =
|
||||
(typeof GenerationScalarFieldEnum)[keyof typeof GenerationScalarFieldEnum]
|
||||
|
||||
export const GenerationEquipmentScalarFieldEnum = {
|
||||
generationId: 'generationId',
|
||||
equipmentId: 'equipmentId',
|
||||
} as const
|
||||
|
||||
export type GenerationEquipmentScalarFieldEnum =
|
||||
(typeof GenerationEquipmentScalarFieldEnum)[keyof typeof GenerationEquipmentScalarFieldEnum]
|
||||
|
||||
export const SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc',
|
||||
} as const
|
||||
|
||||
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder]
|
||||
|
||||
export const NullsOrder = {
|
||||
first: 'first',
|
||||
last: 'last',
|
||||
} as const
|
||||
|
||||
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]
|
||||
@@ -0,0 +1,16 @@
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
|
||||
// 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/Asset.js'
|
||||
export type * from './models/Character.js'
|
||||
export type * from './models/Category.js'
|
||||
export type * from './models/Equipment.js'
|
||||
export type * from './models/Generation.js'
|
||||
export type * from './models/GenerationEquipment.js'
|
||||
export type * from './commonInputTypes.js'
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,4 +1,9 @@
|
||||
import { Hono } from 'hono'
|
||||
import { serveStatic } from 'hono/bun'
|
||||
import asset from './api/asset'
|
||||
import character from './api/character'
|
||||
import equipment from './api/equipment'
|
||||
import generation from './api/generation'
|
||||
|
||||
const app = new Hono()
|
||||
|
||||
@@ -6,4 +11,12 @@ app.get('/', (c) => {
|
||||
return c.text('Hello Hono!')
|
||||
})
|
||||
|
||||
// Serve static files from data/files
|
||||
app.use('/files/*', serveStatic({ root: './data' }))
|
||||
|
||||
app.route('/assets', asset)
|
||||
app.route('/characters', character)
|
||||
app.route('/equipments', equipment)
|
||||
app.route('/generations', generation)
|
||||
|
||||
export default app
|
||||
@@ -0,0 +1,7 @@
|
||||
export const writeFile = async (
|
||||
path: string,
|
||||
content: Blob | string | ArrayBuffer | ArrayBufferView,
|
||||
) => {
|
||||
// @ts-expect-error - Bun.write accepts string path
|
||||
return Bun.write(path, content)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { describe, it, expect, mock, afterEach } from 'bun:test'
|
||||
|
||||
const mockPrisma = {
|
||||
asset: {
|
||||
create: mock(),
|
||||
findUnique: mock(),
|
||||
},
|
||||
}
|
||||
|
||||
const mockFileSystem = {
|
||||
writeFile: mock(),
|
||||
}
|
||||
|
||||
mock.module('../db', () => ({
|
||||
prisma: mockPrisma,
|
||||
}))
|
||||
|
||||
mock.module('../lib/fileSystem', () => mockFileSystem)
|
||||
|
||||
describe('AssetService', () => {
|
||||
afterEach(() => {
|
||||
mockPrisma.asset.create.mockClear()
|
||||
mockPrisma.asset.findUnique.mockClear()
|
||||
mockFileSystem.writeFile.mockClear()
|
||||
})
|
||||
|
||||
it('createAsset should save file and create db record', async () => {
|
||||
// @ts-ignore
|
||||
const { AssetService } = await import(`./asset?v=${Date.now()}`)
|
||||
const file = new File(['content'], 'test.png', { type: 'image/png' })
|
||||
const meta = { name: 'Test Asset', type: 'image/png' }
|
||||
|
||||
mockPrisma.asset.create.mockResolvedValue({
|
||||
id: '01HRKV...',
|
||||
name: meta.name,
|
||||
type: meta.type,
|
||||
path: 'data/files/01HRKV....png',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
|
||||
const result = await AssetService.createAsset(file, meta)
|
||||
|
||||
expect(mockFileSystem.writeFile).toHaveBeenCalled()
|
||||
expect(mockPrisma.asset.create).toHaveBeenCalled()
|
||||
expect(result.name).toBe(meta.name)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,32 @@
|
||||
import { ulid } from 'ulidx'
|
||||
import { prisma } from '../db'
|
||||
import { join, extname } from 'path'
|
||||
import { writeFile } from '../lib/fileSystem'
|
||||
|
||||
export class AssetService {
|
||||
static async createAsset(file: File, meta: { name: string; type: string }) {
|
||||
const id = ulid()
|
||||
const ext = extname(file.name) || '.bin'
|
||||
const filename = `${id}${ext}`
|
||||
const path = join('data/files', filename)
|
||||
|
||||
await writeFile(path, file)
|
||||
|
||||
const asset = await prisma.asset.create({
|
||||
data: {
|
||||
id,
|
||||
name: meta.name,
|
||||
type: meta.type,
|
||||
path,
|
||||
},
|
||||
})
|
||||
|
||||
return asset
|
||||
}
|
||||
|
||||
static async getAsset(id: string) {
|
||||
return prisma.asset.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { describe, it, expect, mock, afterEach } from 'bun:test'
|
||||
|
||||
const mockPrisma = {
|
||||
character: {
|
||||
create: mock(),
|
||||
findMany: mock(),
|
||||
count: mock(),
|
||||
update: mock(),
|
||||
delete: mock(),
|
||||
},
|
||||
}
|
||||
|
||||
mock.module('../db', () => ({
|
||||
prisma: mockPrisma,
|
||||
}))
|
||||
|
||||
describe('CharacterService', () => {
|
||||
afterEach(() => {
|
||||
mockPrisma.character.create.mockClear()
|
||||
mockPrisma.character.findMany.mockClear()
|
||||
mockPrisma.character.count.mockClear()
|
||||
mockPrisma.character.update.mockClear()
|
||||
mockPrisma.character.delete.mockClear()
|
||||
})
|
||||
|
||||
it('createCharacter should create character with image relation', async () => {
|
||||
// @ts-ignore
|
||||
const { CharacterService } = await import(`./character?v=${Date.now()}`)
|
||||
const data = { name: 'Test Char', description: 'Desc', imageId: 'img1' }
|
||||
mockPrisma.character.create.mockResolvedValue({ id: 'char1', ...data })
|
||||
|
||||
const result = await CharacterService.createCharacter(data)
|
||||
|
||||
expect(mockPrisma.character.create).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
data: expect.objectContaining({
|
||||
name: data.name,
|
||||
imageId: data.imageId,
|
||||
}),
|
||||
include: { image: true },
|
||||
}),
|
||||
)
|
||||
expect(result.id).toBe('char1')
|
||||
})
|
||||
|
||||
it('listCharacters should return paginated list', async () => {
|
||||
// @ts-ignore
|
||||
const { CharacterService } = await import(`./character?v=${Date.now()}`)
|
||||
mockPrisma.character.count.mockResolvedValue(10)
|
||||
mockPrisma.character.findMany.mockResolvedValue([{ id: 'char1' }])
|
||||
|
||||
const result = await CharacterService.listCharacters({ page: 1, limit: 5 })
|
||||
|
||||
expect(mockPrisma.character.findMany).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
skip: 0,
|
||||
take: 5,
|
||||
}),
|
||||
)
|
||||
expect(result.total).toBe(10)
|
||||
expect(result.items).toHaveLength(1)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,55 @@
|
||||
import { prisma } from '../db'
|
||||
import { ulid } from 'ulidx'
|
||||
|
||||
export class CharacterService {
|
||||
static async createCharacter(data: { name: string; description?: string; imageId: string }) {
|
||||
return prisma.character.create({
|
||||
data: {
|
||||
id: ulid(),
|
||||
...data,
|
||||
},
|
||||
include: {
|
||||
image: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
static async listCharacters(pagination: { page: number; limit: number }) {
|
||||
const { page, limit } = pagination
|
||||
const skip = (page - 1) * limit
|
||||
const [total, items] = await Promise.all([
|
||||
prisma.character.count(),
|
||||
prisma.character.findMany({
|
||||
skip,
|
||||
take: limit,
|
||||
include: {
|
||||
image: true,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
}),
|
||||
])
|
||||
|
||||
return { total, items, page, limit, totalPages: Math.ceil(total / limit) }
|
||||
}
|
||||
|
||||
static async updateCharacter(
|
||||
id: string,
|
||||
data: { name?: string; description?: string; imageId?: string },
|
||||
) {
|
||||
return prisma.character.update({
|
||||
where: { id },
|
||||
data,
|
||||
include: {
|
||||
image: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
static async deleteCharacter(id: string) {
|
||||
return prisma.character.delete({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, it, expect, mock, afterEach } from 'bun:test'
|
||||
|
||||
const mockPrisma = {
|
||||
equipment: {
|
||||
findMany: mock(),
|
||||
count: mock(),
|
||||
},
|
||||
}
|
||||
|
||||
mock.module('../db', () => ({
|
||||
prisma: mockPrisma,
|
||||
}))
|
||||
|
||||
describe('EquipmentService', () => {
|
||||
afterEach(() => {
|
||||
mockPrisma.equipment.findMany.mockClear()
|
||||
mockPrisma.equipment.count.mockClear()
|
||||
})
|
||||
|
||||
it('listEquipments should filter by category', async () => {
|
||||
// @ts-ignore
|
||||
const { EquipmentService } = await import(`./equipment?v=${Date.now()}`)
|
||||
mockPrisma.equipment.count.mockResolvedValue(5)
|
||||
mockPrisma.equipment.findMany.mockResolvedValue([])
|
||||
|
||||
await EquipmentService.listEquipments({ page: 1, limit: 10 }, { categoryId: 'cat1' })
|
||||
|
||||
expect(mockPrisma.equipment.findMany).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
where: expect.objectContaining({
|
||||
categoryId: 'cat1',
|
||||
}),
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,39 @@
|
||||
import { prisma } from '../db'
|
||||
import { Prisma } from '../generated/prisma/client'
|
||||
|
||||
export class EquipmentService {
|
||||
static async listEquipments(
|
||||
pagination: { page: number; limit: number },
|
||||
filters?: { categoryId?: string; subCategoryId?: string },
|
||||
) {
|
||||
const { page, limit } = pagination
|
||||
const skip = (page - 1) * limit
|
||||
const where: Prisma.EquipmentWhereInput = {}
|
||||
|
||||
if (filters?.categoryId) {
|
||||
where.categoryId = filters.categoryId
|
||||
}
|
||||
if (filters?.subCategoryId) {
|
||||
where.subCategoryId = filters.subCategoryId
|
||||
}
|
||||
|
||||
const [total, items] = await Promise.all([
|
||||
prisma.equipment.count({ where }),
|
||||
prisma.equipment.findMany({
|
||||
where,
|
||||
skip,
|
||||
take: limit,
|
||||
include: {
|
||||
image: true,
|
||||
category: true,
|
||||
subCategory: true,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
}),
|
||||
])
|
||||
|
||||
return { total, items, page, limit, totalPages: Math.ceil(total / limit) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { describe, it, expect, mock, afterEach } from 'bun:test'
|
||||
|
||||
const mockPrisma = {
|
||||
generation: {
|
||||
findMany: mock(),
|
||||
count: mock(),
|
||||
},
|
||||
}
|
||||
|
||||
mock.module('../db', () => ({
|
||||
prisma: mockPrisma,
|
||||
}))
|
||||
|
||||
describe('GenerationService', () => {
|
||||
afterEach(() => {
|
||||
mockPrisma.generation.findMany.mockClear()
|
||||
mockPrisma.generation.count.mockClear()
|
||||
})
|
||||
|
||||
it('listGenerations should filter by equipment', async () => {
|
||||
// @ts-ignore
|
||||
const { GenerationService } = await import(`./generation?v=${Date.now()}`)
|
||||
mockPrisma.generation.count.mockResolvedValue(2)
|
||||
mockPrisma.generation.findMany.mockResolvedValue([])
|
||||
|
||||
await GenerationService.listGenerations({ page: 1, limit: 10 }, { equipmentId: 'eq1' })
|
||||
|
||||
expect(mockPrisma.generation.findMany).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
where: expect.objectContaining({
|
||||
equipments: {
|
||||
some: {
|
||||
equipmentId: 'eq1',
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,48 @@
|
||||
import { prisma } from '../db'
|
||||
import { Prisma } from '../generated/prisma/client'
|
||||
|
||||
export class GenerationService {
|
||||
static async listGenerations(
|
||||
pagination: { page: number; limit: number },
|
||||
filters?: { characterId?: string; equipmentId?: string },
|
||||
) {
|
||||
const { page, limit } = pagination
|
||||
const skip = (page - 1) * limit
|
||||
const where: Prisma.GenerationWhereInput = {}
|
||||
|
||||
if (filters?.characterId) {
|
||||
where.characterId = filters.characterId
|
||||
}
|
||||
|
||||
if (filters?.equipmentId) {
|
||||
where.equipments = {
|
||||
some: {
|
||||
equipmentId: filters.equipmentId,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const [total, items] = await Promise.all([
|
||||
prisma.generation.count({ where }),
|
||||
prisma.generation.findMany({
|
||||
where,
|
||||
skip,
|
||||
take: limit,
|
||||
include: {
|
||||
image: true,
|
||||
character: true,
|
||||
equipments: {
|
||||
include: {
|
||||
equipment: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
}),
|
||||
])
|
||||
|
||||
return { total, items, page, limit, totalPages: Math.ceil(total / limit) }
|
||||
}
|
||||
}
|
||||
+9
-3
@@ -2,6 +2,12 @@
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "hono/jsx"
|
||||
}
|
||||
}
|
||||
"jsxImportSource": "hono/jsx",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"target": "esnext",
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in new issue
Block a user