From 5e26c47174e79e80bdc1713008672abaa0639ad8 Mon Sep 17 00:00:00 2001 From: onmax Date: Tue, 30 Jun 2026 07:25:30 +0200 Subject: [PATCH] feat(db): ORM adapter pattern --- .gitignore | 4 +- package.json | 3 + playground/test/basic.test.ts | 3 +- pnpm-lock.yaml | 1061 ++++++++++++++++- src/db/adapters/drizzle.ts | 291 +++++ src/db/adapters/interface.ts | 71 ++ src/db/adapters/prisma.ts | 140 +++ src/db/lib/build.ts | 17 +- src/db/lib/migrations.ts | 89 +- src/db/runtime/plugins/migrations.dev.ts | 9 +- src/db/setup.ts | 378 +----- src/devtools.ts | 115 +- src/types/config.ts | 17 +- test/adapter.test.ts | 298 +++++ test/database.config.test.ts | 60 + test/db-drizzle.e2e.test.ts | 66 + test/db-prisma.e2e.test.ts | 68 ++ test/fixtures/db-drizzle/nuxt.config.ts | 9 + test/fixtures/db-drizzle/package.json | 1 + .../server/api/users/[id].delete.ts | 10 + .../db-drizzle/server/api/users/[id].get.ts | 10 + .../db-drizzle/server/api/users/[id].put.ts | 11 + .../db-drizzle/server/api/users/index.get.ts | 6 + .../db-drizzle/server/api/users/index.post.ts | 8 + .../migrations/sqlite/0000_create_users.sql | 6 + test/fixtures/db-drizzle/server/db/schema.ts | 7 + test/fixtures/db-drizzle/server/tsconfig.json | 1 + test/fixtures/db-prisma/nuxt.config.ts | 9 + test/fixtures/db-prisma/package.json | 12 + test/fixtures/db-prisma/prisma/schema.prisma | 15 + .../db-prisma/server/api/users/[id].delete.ts | 12 + .../db-prisma/server/api/users/[id].get.ts | 9 + .../db-prisma/server/api/users/[id].put.ts | 12 + .../db-prisma/server/api/users/index.get.ts | 6 + .../db-prisma/server/api/users/index.post.ts | 7 + .../db/migrations/sqlite/0000_create_user.sql | 6 + test/fixtures/db-prisma/server/tsconfig.json | 1 + test/fixtures/wrangler/server/db/schema.ts | 6 + test/wrangler.test.ts | 2 +- 39 files changed, 2382 insertions(+), 474 deletions(-) create mode 100644 src/db/adapters/drizzle.ts create mode 100644 src/db/adapters/interface.ts create mode 100644 src/db/adapters/prisma.ts create mode 100644 test/adapter.test.ts create mode 100644 test/db-drizzle.e2e.test.ts create mode 100644 test/db-prisma.e2e.test.ts create mode 100644 test/fixtures/db-drizzle/nuxt.config.ts create mode 100644 test/fixtures/db-drizzle/package.json create mode 100644 test/fixtures/db-drizzle/server/api/users/[id].delete.ts create mode 100644 test/fixtures/db-drizzle/server/api/users/[id].get.ts create mode 100644 test/fixtures/db-drizzle/server/api/users/[id].put.ts create mode 100644 test/fixtures/db-drizzle/server/api/users/index.get.ts create mode 100644 test/fixtures/db-drizzle/server/api/users/index.post.ts create mode 100644 test/fixtures/db-drizzle/server/db/migrations/sqlite/0000_create_users.sql create mode 100644 test/fixtures/db-drizzle/server/db/schema.ts create mode 100644 test/fixtures/db-drizzle/server/tsconfig.json create mode 100644 test/fixtures/db-prisma/nuxt.config.ts create mode 100644 test/fixtures/db-prisma/package.json create mode 100644 test/fixtures/db-prisma/prisma/schema.prisma create mode 100644 test/fixtures/db-prisma/server/api/users/[id].delete.ts create mode 100644 test/fixtures/db-prisma/server/api/users/[id].get.ts create mode 100644 test/fixtures/db-prisma/server/api/users/[id].put.ts create mode 100644 test/fixtures/db-prisma/server/api/users/index.get.ts create mode 100644 test/fixtures/db-prisma/server/api/users/index.post.ts create mode 100644 test/fixtures/db-prisma/server/db/migrations/sqlite/0000_create_user.sql create mode 100644 test/fixtures/db-prisma/server/tsconfig.json create mode 100644 test/fixtures/wrangler/server/db/schema.ts diff --git a/.gitignore b/.gitignore index 295840a78..a84848e91 100644 --- a/.gitignore +++ b/.gitignore @@ -61,4 +61,6 @@ test/fixtures/kv/.data test/fixtures/blob/.data test/fixtures/openapi/.data test/fixtures/cache/.data -test/fixtures/wrangler/.data \ No newline at end of file +test/fixtures/wrangler/.data +test/fixtures/db-prisma/.data +test/fixtures/db-drizzle/.data \ No newline at end of file diff --git a/package.json b/package.json index de9325255..d9cdd1feb 100644 --- a/package.json +++ b/package.json @@ -106,6 +106,8 @@ "@nuxt/schema": "^4.2.2", "@nuxt/test-utils": "3.21.0", "@nuxthub/core": "link:", + "@prisma/adapter-libsql": "^5.22.0", + "@prisma/client": "^5.22.0", "@types/node": "^25.0.3", "better-sqlite3": "^12.5.0", "changelogen": "^0.6.2", @@ -114,6 +116,7 @@ "jiti": "^2.6.1", "nitropack": "^2.12.9", "nuxt": "^4.2.2", + "prisma": "^5.22.0", "typescript": "^5.9.3", "vitest": "^4.0.16", "vue-tsc": "^3.1.8" diff --git a/playground/test/basic.test.ts b/playground/test/basic.test.ts index b49d7cd2b..ebed8f9c8 100644 --- a/playground/test/basic.test.ts +++ b/playground/test/basic.test.ts @@ -8,7 +8,8 @@ describe('ssr', async () => { await setup({ rootDir: fileURLToPath(new URL('..', import.meta.url)), - dev: true + dev: true, + setupTimeout: 180000 }) it('List todos', async () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 843841aae..d5f5e0f2b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -79,7 +79,7 @@ importers: version: 0.1.3 unstorage: specifier: ^1.17.3 - version: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2) + version: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3))(ioredis@5.8.2) zod: specifier: ^4.2.1 version: 4.2.1 @@ -102,6 +102,12 @@ importers: '@nuxthub/core': specifier: 'link:' version: 'link:' + '@prisma/adapter-libsql': + specifier: ^5.22.0 + version: 5.22.0(@libsql/client@0.15.15) + '@prisma/client': + specifier: ^5.22.0 + version: 5.22.0(prisma@5.22.0) '@types/node': specifier: ^25.0.3 version: 25.0.3 @@ -122,10 +128,13 @@ importers: version: 2.6.1 nitropack: specifier: ^2.12.9 - version: 2.12.9(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3)(rolldown@1.0.0-beta.55) + version: 2.12.9(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3)(rolldown@1.0.0-beta.55) nuxt: specifier: ^4.2.2 - version: 4.2.2(29cf92ef53281a2598cea37085a6dda0) + version: 4.2.2(3b13fce02b4e8ad8c6ca8131442d4dba) + prisma: + specifier: ^5.22.0 + version: 5.22.0 typescript: specifier: ^5.9.3 version: 5.9.3 @@ -158,19 +167,19 @@ importers: version: 1.2.37 '@nuxt/content': specifier: ^3.9.0 - version: 3.9.0(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(magicast@0.5.1)(mysql2@3.15.3)(valibot@1.2.0(typescript@5.9.3)) + version: 3.9.0(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(magicast@0.5.1)(mysql2@3.15.3)(valibot@1.2.0(typescript@5.9.3)) '@nuxt/fonts': specifier: ^0.12.1 - version: 0.12.1(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)) + version: 0.12.1(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)) '@nuxt/image': specifier: ^2.0.0 - version: 2.0.0(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1) + version: 2.0.0(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1) '@nuxt/scripts': specifier: ^0.13.1 - version: 0.13.1(@unhead/vue@2.0.19(vue@3.5.25(typescript@5.9.3)))(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) + version: 0.13.1(@unhead/vue@2.0.19(vue@3.5.25(typescript@5.9.3)))(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) '@nuxt/ui': specifier: ^4.2.1 - version: 4.2.1(ce5e0e5d7482f2919b2663ab5c647330) + version: 4.2.1(7f192c154934c434f0438b46cb03531b) '@nuxtjs/mcp-toolkit': specifier: 0.5.2 version: 0.5.2(magicast@0.5.1)(zod@4.2.1) @@ -185,19 +194,19 @@ importers: version: 14.1.0(vue@3.5.25(typescript@5.9.3)) '@vueuse/nuxt': specifier: ^14.1.0 - version: 14.1.0(magicast@0.5.1)(nuxt@4.2.2(29cf92ef53281a2598cea37085a6dda0))(vue@3.5.25(typescript@5.9.3)) + version: 14.1.0(magicast@0.5.1)(nuxt@4.2.2(fa4fa017741a39d7f93d443429824224))(vue@3.5.25(typescript@5.9.3)) feed: specifier: ^5.1.0 version: 5.1.0 nuxt: specifier: ^4.2.2 - version: 4.2.2(29cf92ef53281a2598cea37085a6dda0) + version: 4.2.2(fa4fa017741a39d7f93d443429824224) nuxt-llms: specifier: ^0.1.3 version: 0.1.3(magicast@0.5.1) nuxt-og-image: specifier: ^5.1.13 - version: 5.1.13(@unhead/vue@2.0.19(vue@3.5.25(typescript@5.9.3)))(h3@1.15.5)(magicast@0.5.1)(unstorage@1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2))(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) + version: 5.1.13(@unhead/vue@2.0.19(vue@3.5.25(typescript@5.9.3)))(h3@1.15.5)(magicast@0.5.1)(unstorage@1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2))(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) tailwindcss: specifier: ^4.1.18 version: 4.1.18 @@ -218,7 +227,7 @@ importers: version: 0.15.15 '@nuxt/ui': specifier: ^4.2.1 - version: 4.2.1(ce5e0e5d7482f2919b2663ab5c647330) + version: 4.2.1(7f192c154934c434f0438b46cb03531b) '@nuxthub/core': specifier: workspace:* version: link:.. @@ -233,7 +242,7 @@ importers: version: 14.1.0(vue@3.5.25(typescript@5.9.3)) '@vueuse/nuxt': specifier: ^14.1.0 - version: 14.1.0(magicast@0.5.1)(nuxt@4.2.2(29cf92ef53281a2598cea37085a6dda0))(vue@3.5.25(typescript@5.9.3)) + version: 14.1.0(magicast@0.5.1)(nuxt@4.2.2(fa4fa017741a39d7f93d443429824224))(vue@3.5.25(typescript@5.9.3)) aws4fetch: specifier: ^1.0.20 version: 1.0.20 @@ -242,7 +251,7 @@ importers: version: 0.31.8 drizzle-orm: specifier: ^0.45.1 - version: 0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7) + version: 0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)) ioredis: specifier: ^5.8.2 version: 5.8.2 @@ -251,7 +260,7 @@ importers: version: 3.15.3 nuxt: specifier: 4.2.2 - version: 4.2.2(29cf92ef53281a2598cea37085a6dda0) + version: 4.2.2(fa4fa017741a39d7f93d443429824224) nuxt-auth-utils: specifier: ^0.5.26 version: 0.5.26(magicast@0.5.1) @@ -434,6 +443,18 @@ packages: resolution: {integrity: sha512-8XqW8xGn++Eqqbz3e9wKuK7mxryeRjs4LOHLxbh2lwKeSbuNR4NFifDZT4KzvjU6HMOPbiNTsWpniK5EJfTWkg==} engines: {node: '>=18'} + '@chevrotain/cst-dts-gen@10.5.0': + resolution: {integrity: sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==} + + '@chevrotain/gast@10.5.0': + resolution: {integrity: sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==} + + '@chevrotain/types@10.5.0': + resolution: {integrity: sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==} + + '@chevrotain/utils@10.5.0': + resolution: {integrity: sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==} + '@clack/core@0.5.0': resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} @@ -462,9 +483,23 @@ packages: '@dxup/unimport@0.1.2': resolution: {integrity: sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==} + '@electric-sql/pglite-socket@0.0.6': + resolution: {integrity: sha512-6RjmgzphIHIBA4NrMGJsjNWK4pu+bCWJlEWlwcxFTVY3WT86dFpKwbZaGWZV6C5Rd7sCk1Z0CI76QEfukLAUXw==} + hasBin: true + peerDependencies: + '@electric-sql/pglite': 0.3.2 + + '@electric-sql/pglite-tools@0.2.7': + resolution: {integrity: sha512-9dAccClqxx4cZB+Ar9B+FZ5WgxDc/Xvl9DPrTWv+dYTf0YNubLzi4wHHRGRGhrJv15XwnyKcGOZAP1VXSneSUg==} + peerDependencies: + '@electric-sql/pglite': 0.3.2 + '@electric-sql/pglite@0.3.14': resolution: {integrity: sha512-3DB258dhqdsArOI1fIt7cb9RpUOgcDg5hXWVgVHAeqVQ/qxtFy605QKs4gx6mFq3jWsSPqDN8TgSEsqC3OfV9Q==} + '@electric-sql/pglite@0.3.2': + resolution: {integrity: sha512-zfWWa+V2ViDCY/cmUfRqeWY1yLto+EpxjXnZzenB1TyxsTiXaTWeZFIZw6mac52BsuQm0RjCnisjBtdBaXOI6w==} + '@emnapi/core@1.7.1': resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} @@ -1000,6 +1035,12 @@ packages: '@floating-ui/vue@1.1.9': resolution: {integrity: sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==} + '@hono/node-server@1.19.6': + resolution: {integrity: sha512-Shz/KjlIeAhfiuE93NDKVdZ7HdBVLQAfdbaXEaoAVO3ic9ibRSLGIQGkcBbFyuLr+7/1D5ZCINM8B+6IvXeMtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -1318,6 +1359,10 @@ packages: '@cfworker/json-schema': optional: true + '@mrleebo/prisma-ast@0.12.1': + resolution: {integrity: sha512-JwqeCQ1U3fvccttHZq7Tk0m/TMC6WcFAQZdukypW3AzlJYKYTGNVd1ANU2GuhKnv4UQuOFj3oAl0LLG/gxFN1w==} + engines: {node: '>=16'} + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -1955,6 +2000,90 @@ packages: resolution: {integrity: sha512-da+MMyeXhBaKtxQiWPfy7+056wk3lVIhioJnXHXkJ2/OHDaZfFcyKHNl1R06sdYO8lIRXcXdoZ6LO2ARmkAREA==} engines: {node: '>=18.16.0'} + '@prisma/adapter-libsql@5.22.0': + resolution: {integrity: sha512-6Lox7JqNfMdnpb6CblZ/DcuU5OmP2lRBGIPkdnMq0wGqC7fq7DQURZGpDSAZL/mI9sbR/aUKyeo31FLqg97dsw==} + peerDependencies: + '@libsql/client': ^0.3.5 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0 + + '@prisma/client-runtime-utils@7.2.0': + resolution: {integrity: sha512-dn7oB53v0tqkB0wBdMuTNFNPdEbfICEUe82Tn9FoKAhJCUkDH+fmyEp0ClciGh+9Hp2Tuu2K52kth2MTLstvmA==} + + '@prisma/client@5.22.0': + resolution: {integrity: sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==} + engines: {node: '>=16.13'} + peerDependencies: + prisma: '*' + peerDependenciesMeta: + prisma: + optional: true + + '@prisma/client@7.2.0': + resolution: {integrity: sha512-JdLF8lWZ+LjKGKpBqyAlenxd/kXjd1Abf/xK+6vUA7R7L2Suo6AFTHFRpPSdAKCan9wzdFApsUpSa/F6+t1AtA==} + engines: {node: ^20.19 || ^22.12 || >=24.0} + peerDependencies: + prisma: '*' + typescript: '>=5.4.0' + peerDependenciesMeta: + prisma: + optional: true + typescript: + optional: true + + '@prisma/config@7.2.0': + resolution: {integrity: sha512-qmvSnfQ6l/srBW1S7RZGfjTQhc44Yl3ldvU6y3pgmuLM+83SBDs6UQVgMtQuMRe9J3gGqB0RF8wER6RlXEr6jQ==} + + '@prisma/debug@5.22.0': + resolution: {integrity: sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==} + + '@prisma/debug@6.8.2': + resolution: {integrity: sha512-4muBSSUwJJ9BYth5N8tqts8JtiLT8QI/RSAzEogwEfpbYGFo9mYsInsVo8dqXdPO2+Rm5OG5q0qWDDE3nyUbVg==} + + '@prisma/debug@7.2.0': + resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==} + + '@prisma/dev@0.17.0': + resolution: {integrity: sha512-6sGebe5jxX+FEsQTpjHLzvOGPn6ypFQprcs3jcuIWv1Xp/5v6P/rjfdvAwTkP2iF6pDx2tCd8vGLNWcsWzImTA==} + + '@prisma/driver-adapter-utils@5.22.0': + resolution: {integrity: sha512-Y8msGZl9unmVflXoqdxTejv99UD02Gp4VoIvkyw+YxNUIj7nRz35O7yf5D87qNmTiPMGCS1WjUucG9ZuNq8+tw==} + + '@prisma/engines-version@5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2': + resolution: {integrity: sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==} + + '@prisma/engines-version@7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3': + resolution: {integrity: sha512-KezsjCZDsbjNR7SzIiVlUsn9PnLePI7r5uxABlwL+xoerurZTfgQVbIjvjF2sVr3Uc0ZcsnREw3F84HvbggGdA==} + + '@prisma/engines@5.22.0': + resolution: {integrity: sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==} + + '@prisma/engines@7.2.0': + resolution: {integrity: sha512-HUeOI/SvCDsHrR9QZn24cxxZcujOjcS3w1oW/XVhnSATAli5SRMOfp/WkG3TtT5rCxDA4xOnlJkW7xkho4nURA==} + + '@prisma/fetch-engine@5.22.0': + resolution: {integrity: sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==} + + '@prisma/fetch-engine@7.2.0': + resolution: {integrity: sha512-Z5XZztJ8Ap+wovpjPD2lQKnB8nWFGNouCrglaNFjxIWAGWz0oeHXwUJRiclIoSSXN/ptcs9/behptSk8d0Yy6w==} + + '@prisma/get-platform@5.22.0': + resolution: {integrity: sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==} + + '@prisma/get-platform@6.8.2': + resolution: {integrity: sha512-vXSxyUgX3vm1Q70QwzwkjeYfRryIvKno1SXbIqwSptKwqKzskINnDUcx85oX+ys6ooN2ATGSD0xN2UTfg6Zcow==} + + '@prisma/get-platform@7.2.0': + resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} + + '@prisma/query-plan-executor@6.18.0': + resolution: {integrity: sha512-jZ8cfzFgL0jReE1R10gT8JLHtQxjWYLiQ//wHmVYZ2rVkFHoh0DT8IXsxcKcFlfKN7ak7k6j0XMNn2xVNyr5cA==} + + '@prisma/studio-core@0.9.0': + resolution: {integrity: sha512-xA2zoR/ADu/NCSQuriBKTh6Ps4XjU0bErkEcgMfnSGh346K1VI7iWKnoq1l2DoxUqiddPHIEWwtxJ6xCHG6W7g==} + peerDependencies: + '@types/react': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} @@ -2635,6 +2764,9 @@ packages: '@types/pluralize@0.0.33': resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} + '@types/react@19.2.8': + resolution: {integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==} + '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -3189,6 +3321,9 @@ packages: resolution: {integrity: sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==} engines: {node: '>=20.19.0'} + async-mutex@0.5.0: + resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} + async-retry@1.3.3: resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} @@ -3315,6 +3450,14 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + c12@3.1.0: + resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + c12@3.3.3: resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==} peerDependencies: @@ -3386,6 +3529,9 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chevrotain@10.5.0: + resolution: {integrity: sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -3678,6 +3824,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge-ts@7.1.5: + resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} + engines: {node: '>=16.0.0'} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -3892,6 +4042,9 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + effect@3.18.4: + resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==} + electron-to-chromium@1.5.266: resolution: {integrity: sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==} @@ -4235,6 +4388,10 @@ packages: resolution: {integrity: sha512-CGnyrvbhPlWYMngksqrSSUT1BAVP49dZocrHuK0SvtR0D5TMs5wP0o3j7jexDJW01KSadjBp1M/71o/KR3nD1w==} engines: {node: '>=18'} + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -4409,6 +4566,9 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-port-please@3.1.2: + resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==} + get-port-please@3.2.0: resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} @@ -4478,6 +4638,9 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + grammex@3.1.12: + resolution: {integrity: sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==} + gzip-size@7.0.0: resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -4558,6 +4721,10 @@ packages: hey-listen@1.0.8: resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} + hono@4.10.6: + resolution: {integrity: sha512-BIdolzGpDO9MQ4nu3AUuDwHZZ+KViNm+EZ75Ae55eMXMqLVhDFqEMXxtUe9Qh8hjL+pIna/frs2j6Y2yD5Ua/g==} + engines: {node: '>=16.9.0'} + hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} @@ -4581,6 +4748,9 @@ packages: resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + http-status-codes@2.3.0: + resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==} + https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} @@ -4971,6 +5141,10 @@ packages: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -5665,6 +5839,9 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + perfect-debounce@2.0.0: resolution: {integrity: sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==} @@ -5903,6 +6080,24 @@ packages: resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} engines: {node: '>=18'} + prisma@5.22.0: + resolution: {integrity: sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==} + engines: {node: '>=16.13'} + hasBin: true + + prisma@7.2.0: + resolution: {integrity: sha512-jSdHWgWOgFF24+nRyyNRVBIgGDQEsMEF8KPHvhBBg3jWyR9fUAK0Nq9ThUmiGlNgq2FA7vSk/ZoCvefod+a8qg==} + engines: {node: ^20.19 || ^22.12 || >=24.0} + hasBin: true + peerDependencies: + better-sqlite3: '>=9.0.0' + typescript: '>=5.4.0' + peerDependenciesMeta: + better-sqlite3: + optional: true + typescript: + optional: true + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -5917,6 +6112,9 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} @@ -5934,6 +6132,9 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -5968,6 +6169,15 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true + react-dom@19.2.3: + resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} + peerDependencies: + react: ^19.2.3 + + react@19.2.3: + resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + engines: {node: '>=0.10.0'} + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -6015,6 +6225,9 @@ packages: resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + regexp-to-ast@0.5.0: + resolution: {integrity: sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==} + regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true @@ -6068,6 +6281,9 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + remeda@2.21.3: + resolution: {integrity: sha512-XXrZdLA10oEOQhLLzEJEiFFSKi21REGAkHdImIb4rt/XXy8ORGXh5HCcpUOsElfPNDb+X6TA/+wkh+p2KffYmg==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -6099,6 +6315,10 @@ packages: restructure@3.0.2: resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} @@ -6193,6 +6413,9 @@ packages: sax@1.4.3: resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + scslre@0.3.0: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} @@ -6274,6 +6497,9 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -6379,6 +6605,9 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + streamx@2.23.0: resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} @@ -6627,6 +6856,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + type-fest@5.3.0: resolution: {integrity: sha512-d9CwU93nN0IA1QL+GSNDdwLAu1Ew5ZjTwupvedwg3WdfoH6pIDvYQ2hV0Uc2nKBLPq7NB5apCx57MLS5qlmO5g==} engines: {node: '>=20'} @@ -7251,6 +7484,9 @@ packages: youch@4.1.0-beta.13: resolution: {integrity: sha512-3+AG1Xvt+R7M7PSDudhbfbwiyveW6B8PLBIwTyEC598biEYIjHhC89i6DBEvR0EZUjGY3uGSnC429HpIa2Z09g==} + zeptomatch@2.0.2: + resolution: {integrity: sha512-H33jtSKf8Ijtb5BW6wua3G5DhnFjbFML36eFu+VdOoVY4HD9e7ggjqdM6639B+L87rjnR6Y+XeRzBXZdy52B/g==} + zip-stream@6.0.1: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} @@ -7467,6 +7703,25 @@ snapshots: dependencies: fontkit: 2.0.4 + '@chevrotain/cst-dts-gen@10.5.0': + dependencies: + '@chevrotain/gast': 10.5.0 + '@chevrotain/types': 10.5.0 + lodash: 4.17.21 + optional: true + + '@chevrotain/gast@10.5.0': + dependencies: + '@chevrotain/types': 10.5.0 + lodash: 4.17.21 + optional: true + + '@chevrotain/types@10.5.0': + optional: true + + '@chevrotain/utils@10.5.0': + optional: true + '@clack/core@0.5.0': dependencies: picocolors: 1.1.1 @@ -7509,8 +7764,21 @@ snapshots: '@dxup/unimport@0.1.2': {} + '@electric-sql/pglite-socket@0.0.6(@electric-sql/pglite@0.3.2)': + dependencies: + '@electric-sql/pglite': 0.3.2 + optional: true + + '@electric-sql/pglite-tools@0.2.7(@electric-sql/pglite@0.3.2)': + dependencies: + '@electric-sql/pglite': 0.3.2 + optional: true + '@electric-sql/pglite@0.3.14': {} + '@electric-sql/pglite@0.3.2': + optional: true + '@emnapi/core@1.7.1': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -7846,6 +8114,11 @@ snapshots: - '@vue/composition-api' - vue + '@hono/node-server@1.19.6(hono@4.10.6)': + dependencies: + hono: 4.10.6 + optional: true + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -8154,6 +8427,12 @@ snapshots: transitivePeerDependencies: - supports-color + '@mrleebo/prisma-ast@0.12.1': + dependencies: + chevrotain: 10.5.0 + lilconfig: 2.1.0 + optional: true + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.7.1 @@ -8217,7 +8496,7 @@ snapshots: - magicast - supports-color - '@nuxt/content@3.9.0(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(magicast@0.5.1)(mysql2@3.15.3)(valibot@1.2.0(typescript@5.9.3))': + '@nuxt/content@3.9.0(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(magicast@0.5.1)(mysql2@3.15.3)(valibot@1.2.0(typescript@5.9.3))': dependencies: '@nuxt/kit': 4.2.2(magicast@0.5.1) '@nuxtjs/mdc': 0.19.1(magicast@0.5.1) @@ -8228,7 +8507,7 @@ snapshots: c12: 3.3.3(magicast@0.5.1) chokidar: 5.0.0 consola: 3.4.2 - db0: 0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3) + db0: 0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3) defu: 6.1.4 destr: 2.0.5 git-url-parse: 16.1.0 @@ -8390,7 +8669,7 @@ snapshots: - supports-color - typescript - '@nuxt/fonts@0.12.1(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))': + '@nuxt/fonts@0.12.1(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))': dependencies: '@nuxt/devtools-kit': 3.1.1(magicast@0.5.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)) '@nuxt/kit': 4.2.2(magicast@0.5.1) @@ -8399,7 +8678,7 @@ snapshots: defu: 6.1.4 esbuild: 0.25.12 fontaine: 0.7.0 - fontless: 0.1.0(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)) + fontless: 0.1.0(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)) h3: 1.15.5 jiti: 2.6.1 magic-regexp: 0.10.0 @@ -8412,7 +8691,7 @@ snapshots: ufo: 1.6.3 unifont: 0.6.0 unplugin: 2.3.11 - unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2) + unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -8457,7 +8736,7 @@ snapshots: - vite - vue - '@nuxt/image@2.0.0(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)': + '@nuxt/image@2.0.0(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)': dependencies: '@nuxt/kit': 4.2.2(magicast@0.5.1) consola: 3.4.2 @@ -8470,7 +8749,7 @@ snapshots: std-env: 3.10.0 ufo: 1.6.3 optionalDependencies: - ipx: 3.1.1(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2) + ipx: 3.1.1(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -8567,7 +8846,71 @@ snapshots: - vue - vue-tsc - '@nuxt/nitro-server@4.2.2(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(ioredis@5.8.2)(magicast@0.5.1)(mysql2@3.15.3)(nuxt@4.2.2(29cf92ef53281a2598cea37085a6dda0))(rolldown@1.0.0-beta.55)(typescript@5.9.3)': + '@nuxt/nitro-server@4.2.2(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3))(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(ioredis@5.8.2)(magicast@0.5.1)(mysql2@3.15.3)(nuxt@4.2.2(3b13fce02b4e8ad8c6ca8131442d4dba))(rolldown@1.0.0-beta.55)(typescript@5.9.3)': + dependencies: + '@nuxt/devalue': 2.0.2 + '@nuxt/kit': 4.2.2(magicast@0.5.1) + '@unhead/vue': 2.0.19(vue@3.5.25(typescript@5.9.3)) + '@vue/shared': 3.5.25 + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + devalue: 5.6.1 + errx: 0.1.0 + escape-string-regexp: 5.0.0 + exsolve: 1.0.8 + h3: 1.15.5 + impound: 1.0.0 + klona: 2.0.6 + mocked-exports: 0.1.1 + nitropack: 2.12.9(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3)(rolldown@1.0.0-beta.55) + nuxt: 4.2.2(3b13fce02b4e8ad8c6ca8131442d4dba) + pathe: 2.0.3 + pkg-types: 2.3.0 + radix3: 1.1.2 + std-env: 3.10.0 + ufo: 1.6.3 + unctx: 2.4.1 + unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3))(ioredis@5.8.2) + vue: 3.5.25(typescript@5.9.3) + vue-bundle-renderer: 2.2.0 + vue-devtools-stub: 0.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bare-abort-controller + - better-sqlite3 + - db0 + - drizzle-orm + - encoding + - idb-keyval + - ioredis + - magicast + - mysql2 + - react-native-b4a + - rolldown + - sqlite3 + - supports-color + - typescript + - uploadthing + - xml2js + + '@nuxt/nitro-server@4.2.2(fc969faf5d3879a1af702f7bf022d801)': dependencies: '@nuxt/devalue': 2.0.2 '@nuxt/kit': 4.2.2(magicast@0.5.1) @@ -8584,15 +8927,15 @@ snapshots: impound: 1.0.0 klona: 2.0.6 mocked-exports: 0.1.1 - nitropack: 2.12.9(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3)(rolldown@1.0.0-beta.55) - nuxt: 4.2.2(29cf92ef53281a2598cea37085a6dda0) + nitropack: 2.12.9(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3)(rolldown@1.0.0-beta.55) + nuxt: 4.2.2(fa4fa017741a39d7f93d443429824224) pathe: 2.0.3 pkg-types: 2.3.0 radix3: 1.1.2 std-env: 3.10.0 ufo: 1.6.3 unctx: 2.4.1 - unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2) + unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2) vue: 3.5.25(typescript@5.9.3) vue-bundle-renderer: 2.2.0 vue-devtools-stub: 0.1.0 @@ -8639,7 +8982,7 @@ snapshots: pkg-types: 2.3.0 std-env: 3.10.0 - '@nuxt/scripts@0.13.1(@unhead/vue@2.0.19(vue@3.5.25(typescript@5.9.3)))(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))': + '@nuxt/scripts@0.13.1(@unhead/vue@2.0.19(vue@3.5.25(typescript@5.9.3)))(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))': dependencies: '@nuxt/kit': 4.2.2(magicast@0.5.1) '@unhead/vue': 2.0.19(vue@3.5.25(typescript@5.9.3)) @@ -8656,7 +8999,7 @@ snapshots: std-env: 3.10.0 ufo: 1.6.3 unplugin: 2.3.11 - unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2) + unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2) valibot: 1.2.0(typescript@5.9.3) transitivePeerDependencies: - '@azure/app-configuration' @@ -8733,12 +9076,12 @@ snapshots: - magicast - typescript - '@nuxt/ui@4.2.1(ce5e0e5d7482f2919b2663ab5c647330)': + '@nuxt/ui@4.2.1(7f192c154934c434f0438b46cb03531b)': dependencies: '@iconify/vue': 5.0.0(vue@3.5.25(typescript@5.9.3)) '@internationalized/date': 3.10.0 '@internationalized/number': 3.6.5 - '@nuxt/fonts': 0.12.1(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)) + '@nuxt/fonts': 0.12.1(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2)(magicast@0.5.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)) '@nuxt/icon': 2.1.0(magicast@0.5.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) '@nuxt/kit': 4.2.2(magicast@0.5.1) '@nuxt/schema': 4.2.2 @@ -8766,7 +9109,7 @@ snapshots: knitwork: 1.3.0 magic-string: 0.30.21 mlly: 1.8.0 - motion-v: 1.7.4(@vueuse/core@13.9.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) + motion-v: 1.7.4(@vueuse/core@13.9.0(vue@3.5.25(typescript@5.9.3)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vue@3.5.25(typescript@5.9.3)) ohash: 2.0.11 pathe: 2.0.3 reka-ui: 2.6.0(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) @@ -8782,7 +9125,7 @@ snapshots: vaul-vue: 0.4.1(reka-ui@2.6.0(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) vue-component-type-helpers: 3.1.5 optionalDependencies: - '@nuxt/content': 3.9.0(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(magicast@0.5.1)(mysql2@3.15.3)(valibot@1.2.0(typescript@5.9.3)) + '@nuxt/content': 3.9.0(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(magicast@0.5.1)(mysql2@3.15.3)(valibot@1.2.0(typescript@5.9.3)) valibot: 1.2.0(typescript@5.9.3) vue-router: 4.6.3(vue@3.5.25(typescript@5.9.3)) zod: 4.2.1 @@ -8827,7 +9170,68 @@ snapshots: - vite - vue - '@nuxt/vite-builder@4.2.2(@types/node@25.0.3)(eslint@9.39.2(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.5.1)(nuxt@4.2.2(29cf92ef53281a2598cea37085a6dda0))(optionator@0.9.4)(rolldown@1.0.0-beta.55)(rollup@4.53.3)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.1.8(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3))(yaml@2.8.2)': + '@nuxt/vite-builder@4.2.2(@types/node@25.0.3)(eslint@9.39.2(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.5.1)(nuxt@4.2.2(3b13fce02b4e8ad8c6ca8131442d4dba))(optionator@0.9.4)(rolldown@1.0.0-beta.55)(rollup@4.53.3)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.1.8(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3))(yaml@2.8.2)': + dependencies: + '@nuxt/kit': 4.2.2(magicast@0.5.1) + '@rollup/plugin-replace': 6.0.3(rollup@4.53.3) + '@vitejs/plugin-vue': 6.0.2(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) + '@vitejs/plugin-vue-jsx': 5.1.2(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) + autoprefixer: 10.4.22(postcss@8.5.6) + consola: 3.4.2 + cssnano: 7.1.2(postcss@8.5.6) + defu: 6.1.4 + esbuild: 0.27.1 + escape-string-regexp: 5.0.0 + exsolve: 1.0.8 + get-port-please: 3.2.0 + h3: 1.15.5 + jiti: 2.6.1 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.0 + mocked-exports: 0.1.1 + nuxt: 4.2.2(3b13fce02b4e8ad8c6ca8131442d4dba) + pathe: 2.0.3 + pkg-types: 2.3.0 + postcss: 8.5.6 + rollup-plugin-visualizer: 6.0.5(rolldown@1.0.0-beta.55)(rollup@4.53.3) + seroval: 1.4.0 + std-env: 3.10.0 + ufo: 1.6.3 + unenv: 2.0.0-rc.24 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2) + vite-node: 5.2.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2) + vite-plugin-checker: 0.12.0(eslint@9.39.2(jiti@2.6.1))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@3.1.8(typescript@5.9.3)) + vue: 3.5.25(typescript@5.9.3) + vue-bundle-renderer: 2.2.0 + optionalDependencies: + rolldown: 1.0.0-beta.55 + transitivePeerDependencies: + - '@biomejs/biome' + - '@types/node' + - eslint + - less + - lightningcss + - magicast + - meow + - optionator + - oxlint + - rollup + - sass + - sass-embedded + - stylelint + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - vls + - vti + - vue-tsc + - yaml + + '@nuxt/vite-builder@4.2.2(@types/node@25.0.3)(eslint@9.39.2(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.5.1)(nuxt@4.2.2(fa4fa017741a39d7f93d443429824224))(optionator@0.9.4)(rolldown@1.0.0-beta.55)(rollup@4.53.3)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.1.8(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3))(yaml@2.8.2)': dependencies: '@nuxt/kit': 4.2.2(magicast@0.5.1) '@rollup/plugin-replace': 6.0.3(rollup@4.53.3) @@ -8847,7 +9251,7 @@ snapshots: magic-string: 0.30.21 mlly: 1.8.0 mocked-exports: 0.1.1 - nuxt: 4.2.2(29cf92ef53281a2598cea37085a6dda0) + nuxt: 4.2.2(fa4fa017741a39d7f93d443429824224) pathe: 2.0.3 pkg-types: 2.3.0 postcss: 8.5.6 @@ -9216,20 +9620,143 @@ snapshots: safe-stable-stringify: 2.5.0 secure-json-parse: 4.1.0 - '@quansync/fs@1.0.0': + '@prisma/adapter-libsql@5.22.0(@libsql/client@0.15.15)': dependencies: - quansync: 1.0.0 + '@libsql/client': 0.15.15 + '@prisma/driver-adapter-utils': 5.22.0 + async-mutex: 0.5.0 - '@resvg/resvg-js-android-arm-eabi@2.6.2': + '@prisma/client-runtime-utils@7.2.0': optional: true - '@resvg/resvg-js-android-arm64@2.6.2': - optional: true + '@prisma/client@5.22.0(prisma@5.22.0)': + optionalDependencies: + prisma: 5.22.0 - '@resvg/resvg-js-darwin-arm64@2.6.2': + '@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3)': + dependencies: + '@prisma/client-runtime-utils': 7.2.0 + optionalDependencies: + prisma: 7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + typescript: 5.9.3 optional: true - '@resvg/resvg-js-darwin-x64@2.6.2': + '@prisma/config@7.2.0(magicast@0.5.1)': + dependencies: + c12: 3.1.0(magicast@0.5.1) + deepmerge-ts: 7.1.5 + effect: 3.18.4 + empathic: 2.0.0 + transitivePeerDependencies: + - magicast + optional: true + + '@prisma/debug@5.22.0': {} + + '@prisma/debug@6.8.2': + optional: true + + '@prisma/debug@7.2.0': + optional: true + + '@prisma/dev@0.17.0(typescript@5.9.3)': + dependencies: + '@electric-sql/pglite': 0.3.2 + '@electric-sql/pglite-socket': 0.0.6(@electric-sql/pglite@0.3.2) + '@electric-sql/pglite-tools': 0.2.7(@electric-sql/pglite@0.3.2) + '@hono/node-server': 1.19.6(hono@4.10.6) + '@mrleebo/prisma-ast': 0.12.1 + '@prisma/get-platform': 6.8.2 + '@prisma/query-plan-executor': 6.18.0 + foreground-child: 3.3.1 + get-port-please: 3.1.2 + hono: 4.10.6 + http-status-codes: 2.3.0 + pathe: 2.0.3 + proper-lockfile: 4.1.2 + remeda: 2.21.3 + std-env: 3.9.0 + valibot: 1.2.0(typescript@5.9.3) + zeptomatch: 2.0.2 + transitivePeerDependencies: + - typescript + optional: true + + '@prisma/driver-adapter-utils@5.22.0': + dependencies: + '@prisma/debug': 5.22.0 + + '@prisma/engines-version@5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2': {} + + '@prisma/engines-version@7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3': + optional: true + + '@prisma/engines@5.22.0': + dependencies: + '@prisma/debug': 5.22.0 + '@prisma/engines-version': 5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2 + '@prisma/fetch-engine': 5.22.0 + '@prisma/get-platform': 5.22.0 + + '@prisma/engines@7.2.0': + dependencies: + '@prisma/debug': 7.2.0 + '@prisma/engines-version': 7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3 + '@prisma/fetch-engine': 7.2.0 + '@prisma/get-platform': 7.2.0 + optional: true + + '@prisma/fetch-engine@5.22.0': + dependencies: + '@prisma/debug': 5.22.0 + '@prisma/engines-version': 5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2 + '@prisma/get-platform': 5.22.0 + + '@prisma/fetch-engine@7.2.0': + dependencies: + '@prisma/debug': 7.2.0 + '@prisma/engines-version': 7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3 + '@prisma/get-platform': 7.2.0 + optional: true + + '@prisma/get-platform@5.22.0': + dependencies: + '@prisma/debug': 5.22.0 + + '@prisma/get-platform@6.8.2': + dependencies: + '@prisma/debug': 6.8.2 + optional: true + + '@prisma/get-platform@7.2.0': + dependencies: + '@prisma/debug': 7.2.0 + optional: true + + '@prisma/query-plan-executor@6.18.0': + optional: true + + '@prisma/studio-core@0.9.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@types/react': 19.2.8 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optional: true + + '@quansync/fs@1.0.0': + dependencies: + quansync: 1.0.0 + + '@resvg/resvg-js-android-arm-eabi@2.6.2': + optional: true + + '@resvg/resvg-js-android-arm64@2.6.2': + optional: true + + '@resvg/resvg-js-darwin-arm64@2.6.2': + optional: true + + '@resvg/resvg-js-darwin-x64@2.6.2': optional: true '@resvg/resvg-js-linux-arm-gnueabihf@2.6.2': @@ -9832,6 +10359,11 @@ snapshots: '@types/pluralize@0.0.33': {} + '@types/react@19.2.8': + dependencies: + csstype: 3.2.3 + optional: true + '@types/resolve@1.20.2': {} '@types/unist@2.0.11': {} @@ -10336,13 +10868,13 @@ snapshots: '@vueuse/metadata@14.1.0': {} - '@vueuse/nuxt@14.1.0(magicast@0.5.1)(nuxt@4.2.2(29cf92ef53281a2598cea37085a6dda0))(vue@3.5.25(typescript@5.9.3))': + '@vueuse/nuxt@14.1.0(magicast@0.5.1)(nuxt@4.2.2(fa4fa017741a39d7f93d443429824224))(vue@3.5.25(typescript@5.9.3))': dependencies: '@nuxt/kit': 4.2.2(magicast@0.5.1) '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) '@vueuse/metadata': 14.1.0 local-pkg: 1.1.2 - nuxt: 4.2.2(29cf92ef53281a2598cea37085a6dda0) + nuxt: 4.2.2(fa4fa017741a39d7f93d443429824224) vue: 3.5.25(typescript@5.9.3) transitivePeerDependencies: - magicast @@ -10473,6 +11005,10 @@ snapshots: '@babel/parser': 7.28.5 ast-kit: 2.2.0 + async-mutex@0.5.0: + dependencies: + tslib: 2.8.1 + async-retry@1.3.3: dependencies: retry: 0.13.1 @@ -10613,6 +11149,24 @@ snapshots: bytes@3.1.2: {} + c12@3.1.0(magicast@0.5.1): + dependencies: + chokidar: 4.0.3 + confbox: 0.2.2 + defu: 6.1.4 + dotenv: 16.6.1 + exsolve: 1.0.8 + giget: 2.0.0 + jiti: 2.6.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 1.0.0 + pkg-types: 2.3.0 + rc9: 2.1.2 + optionalDependencies: + magicast: 0.5.1 + optional: true + c12@3.3.3(magicast@0.5.1): dependencies: chokidar: 5.0.0 @@ -10696,6 +11250,16 @@ snapshots: character-reference-invalid@2.0.1: {} + chevrotain@10.5.0: + dependencies: + '@chevrotain/cst-dts-gen': 10.5.0 + '@chevrotain/gast': 10.5.0 + '@chevrotain/types': 10.5.0 + '@chevrotain/utils': 10.5.0 + lodash: 4.17.21 + regexp-to-ast: 0.5.0 + optional: true + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -10930,12 +11494,20 @@ snapshots: data-uri-to-buffer@4.0.1: {} - db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3): + db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3): optionalDependencies: '@electric-sql/pglite': 0.3.14 '@libsql/client': 0.15.15 better-sqlite3: 12.5.0 - drizzle-orm: 0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7) + drizzle-orm: 0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0) + mysql2: 3.15.3 + + db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3): + optionalDependencies: + '@electric-sql/pglite': 0.3.14 + '@libsql/client': 0.15.15 + better-sqlite3: 12.5.0 + drizzle-orm: 0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)) mysql2: 3.15.3 debug@4.3.7: @@ -10958,6 +11530,9 @@ snapshots: deep-is@0.1.4: {} + deepmerge-ts@7.1.5: + optional: true + deepmerge@4.3.1: {} default-browser-id@5.0.1: {} @@ -11040,15 +11615,30 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7): + drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0): optionalDependencies: '@cloudflare/workers-types': 4.20251219.0 '@electric-sql/pglite': 0.3.14 '@libsql/client': 0.15.15 + '@prisma/client': 5.22.0(prisma@5.22.0) '@upstash/redis': 1.35.8 better-sqlite3: 12.5.0 mysql2: 3.15.3 postgres: 3.4.7 + prisma: 5.22.0 + optional: true + + drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)): + optionalDependencies: + '@cloudflare/workers-types': 4.20251219.0 + '@electric-sql/pglite': 0.3.14 + '@libsql/client': 0.15.15 + '@prisma/client': 7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3) + '@upstash/redis': 1.35.8 + better-sqlite3: 12.5.0 + mysql2: 3.15.3 + postgres: 3.4.7 + prisma: 7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) dts-resolver@2.1.3: {} @@ -11064,6 +11654,12 @@ snapshots: ee-first@1.1.1: {} + effect@3.18.4: + dependencies: + '@standard-schema/spec': 1.0.0 + fast-check: 3.23.2 + optional: true + electron-to-chromium@1.5.266: {} embla-carousel-auto-height@8.6.0(embla-carousel@8.6.0): @@ -11541,6 +12137,11 @@ snapshots: fake-indexeddb@6.2.5: {} + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + optional: true + fast-deep-equal@3.1.3: {} fast-fifo@1.3.2: {} @@ -11653,7 +12254,7 @@ snapshots: unicode-properties: 1.4.1 unicode-trie: 2.0.0 - fontless@0.1.0(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)): + fontless@0.1.0(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)): dependencies: consola: 3.4.2 css-tree: 3.1.0 @@ -11667,7 +12268,7 @@ snapshots: pathe: 2.0.3 ufo: 1.6.3 unifont: 0.6.0 - unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2) + unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2) optionalDependencies: vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2) transitivePeerDependencies: @@ -11704,11 +12305,14 @@ snapshots: fraction.js@5.3.4: {} - framer-motion@12.23.12: + framer-motion@12.23.12(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: motion-dom: 12.23.12 motion-utils: 12.23.6 tslib: 2.8.1 + optionalDependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) fresh@2.0.0: {} @@ -11742,6 +12346,9 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-port-please@3.1.2: + optional: true + get-port-please@3.2.0: {} get-proto@1.0.1: @@ -11820,6 +12427,9 @@ snapshots: graceful-fs@4.2.11: {} + grammex@3.1.12: + optional: true + gzip-size@7.0.0: dependencies: duplexer: 0.1.2 @@ -11990,6 +12600,9 @@ snapshots: hey-listen@1.0.8: {} + hono@4.10.6: + optional: true + hookable@5.5.3: {} hookable@6.0.1: {} @@ -12010,6 +12623,9 @@ snapshots: http-shutdown@1.2.2: {} + http-status-codes@2.3.0: + optional: true + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 @@ -12082,7 +12698,7 @@ snapshots: ipaddr.js@1.9.1: {} - ipx@3.1.1(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2): + ipx@3.1.1(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2): dependencies: '@fastify/accept-negotiator': 2.0.1 citty: 0.1.6 @@ -12098,7 +12714,7 @@ snapshots: sharp: 0.34.5 svgo: 4.0.0 ufo: 1.6.3 - unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2) + unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2) xss: 1.0.15 transitivePeerDependencies: - '@azure/app-configuration' @@ -12367,6 +12983,9 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + lilconfig@2.1.0: + optional: true + lilconfig@3.1.3: {} linebreak@1.1.0: @@ -12875,10 +13494,10 @@ snapshots: motion-utils@12.23.6: {} - motion-v@1.7.4(@vueuse/core@13.9.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)): + motion-v@1.7.4(@vueuse/core@13.9.0(vue@3.5.25(typescript@5.9.3)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vue@3.5.25(typescript@5.9.3)): dependencies: '@vueuse/core': 13.9.0(vue@3.5.25(typescript@5.9.3)) - framer-motion: 12.23.12 + framer-motion: 12.23.12(react-dom@19.2.3(react@19.2.3))(react@19.2.3) hey-listen: 1.0.8 motion-dom: 12.23.12 vue: 3.5.25(typescript@5.9.3) @@ -12925,7 +13544,109 @@ snapshots: negotiator@1.0.0: {} - nitropack@2.12.9(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3)(rolldown@1.0.0-beta.55): + nitropack@2.12.9(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3)(rolldown@1.0.0-beta.55): + dependencies: + '@cloudflare/kv-asset-handler': 0.4.1 + '@rollup/plugin-alias': 5.1.1(rollup@4.53.3) + '@rollup/plugin-commonjs': 28.0.9(rollup@4.53.3) + '@rollup/plugin-inject': 5.0.5(rollup@4.53.3) + '@rollup/plugin-json': 6.1.0(rollup@4.53.3) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.53.3) + '@rollup/plugin-replace': 6.0.3(rollup@4.53.3) + '@rollup/plugin-terser': 0.4.4(rollup@4.53.3) + '@vercel/nft': 0.30.4(rollup@4.53.3) + archiver: 7.0.1 + c12: 3.3.3(magicast@0.5.1) + chokidar: 4.0.3 + citty: 0.1.6 + compatx: 0.2.0 + confbox: 0.2.2 + consola: 3.4.2 + cookie-es: 2.0.0 + croner: 9.1.0 + crossws: 0.3.5 + db0: 0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3) + defu: 6.1.4 + destr: 2.0.5 + dot-prop: 10.1.0 + esbuild: 0.25.12 + escape-string-regexp: 5.0.0 + etag: 1.8.1 + exsolve: 1.0.8 + globby: 15.0.0 + gzip-size: 7.0.0 + h3: 1.15.5 + hookable: 5.5.3 + httpxy: 0.1.7 + ioredis: 5.8.2 + jiti: 2.6.1 + klona: 2.0.6 + knitwork: 1.3.0 + listhen: 1.9.0 + magic-string: 0.30.21 + magicast: 0.5.1 + mime: 4.1.0 + mlly: 1.8.0 + node-fetch-native: 1.6.7 + node-mock-http: 1.0.4 + ofetch: 1.5.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 + pretty-bytes: 7.1.0 + radix3: 1.1.2 + rollup: 4.53.3 + rollup-plugin-visualizer: 6.0.5(rolldown@1.0.0-beta.55)(rollup@4.53.3) + scule: 1.3.0 + semver: 7.7.3 + serve-placeholder: 2.0.2 + serve-static: 2.2.0 + source-map: 0.7.6 + std-env: 3.10.0 + ufo: 1.6.3 + ultrahtml: 1.6.0 + uncrypto: 0.1.3 + unctx: 2.4.1 + unenv: 2.0.0-rc.24 + unimport: 5.5.0 + unplugin-utils: 0.3.1 + unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3))(ioredis@5.8.2) + untyped: 2.0.0 + unwasm: 0.3.11 + youch: 4.1.0-beta.13 + youch-core: 0.3.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bare-abort-controller + - better-sqlite3 + - drizzle-orm + - encoding + - idb-keyval + - mysql2 + - react-native-b4a + - rolldown + - sqlite3 + - supports-color + - uploadthing + + nitropack@2.12.9(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3)(rolldown@1.0.0-beta.55): dependencies: '@cloudflare/kv-asset-handler': 0.4.1 '@rollup/plugin-alias': 5.1.1(rollup@4.53.3) @@ -12946,7 +13667,7 @@ snapshots: cookie-es: 2.0.0 croner: 9.1.0 crossws: 0.3.5 - db0: 0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3) + db0: 0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3) defu: 6.1.4 destr: 2.0.5 dot-prop: 10.1.0 @@ -12992,7 +13713,7 @@ snapshots: unenv: 2.0.0-rc.24 unimport: 5.5.0 unplugin-utils: 0.3.1 - unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2) + unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2) untyped: 2.0.0 unwasm: 0.3.11 youch: 4.1.0-beta.13 @@ -13121,7 +13842,7 @@ snapshots: transitivePeerDependencies: - magicast - nuxt-og-image@5.1.13(@unhead/vue@2.0.19(vue@3.5.25(typescript@5.9.3)))(h3@1.15.5)(magicast@0.5.1)(unstorage@1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2))(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)): + nuxt-og-image@5.1.13(@unhead/vue@2.0.19(vue@3.5.25(typescript@5.9.3)))(h3@1.15.5)(magicast@0.5.1)(unstorage@1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2))(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)): dependencies: '@nuxt/devtools-kit': 3.1.1(magicast@0.5.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)) '@nuxt/kit': 4.2.2(magicast@0.5.1) @@ -13152,7 +13873,7 @@ snapshots: strip-literal: 3.1.0 ufo: 1.6.3 unplugin: 2.3.11 - unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2) + unstorage: 1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2) unwasm: 0.5.2 yoga-wasm-web: 0.3.3 transitivePeerDependencies: @@ -13187,16 +13908,139 @@ snapshots: - magicast - vue - nuxt@4.2.2(29cf92ef53281a2598cea37085a6dda0): + nuxt@4.2.2(3b13fce02b4e8ad8c6ca8131442d4dba): dependencies: '@dxup/nuxt': 0.2.2(magicast@0.5.1) '@nuxt/cli': 3.31.1(cac@6.7.14)(magicast@0.5.1) '@nuxt/devtools': 3.1.1(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) '@nuxt/kit': 4.2.2(magicast@0.5.1) - '@nuxt/nitro-server': 4.2.2(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(ioredis@5.8.2)(magicast@0.5.1)(mysql2@3.15.3)(nuxt@4.2.2(29cf92ef53281a2598cea37085a6dda0))(rolldown@1.0.0-beta.55)(typescript@5.9.3) + '@nuxt/nitro-server': 4.2.2(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(better-sqlite3@12.5.0)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3))(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(ioredis@5.8.2)(magicast@0.5.1)(mysql2@3.15.3)(nuxt@4.2.2(3b13fce02b4e8ad8c6ca8131442d4dba))(rolldown@1.0.0-beta.55)(typescript@5.9.3) '@nuxt/schema': 4.2.2 '@nuxt/telemetry': 2.6.6(magicast@0.5.1) - '@nuxt/vite-builder': 4.2.2(@types/node@25.0.3)(eslint@9.39.2(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.5.1)(nuxt@4.2.2(29cf92ef53281a2598cea37085a6dda0))(optionator@0.9.4)(rolldown@1.0.0-beta.55)(rollup@4.53.3)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.1.8(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3))(yaml@2.8.2) + '@nuxt/vite-builder': 4.2.2(@types/node@25.0.3)(eslint@9.39.2(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.5.1)(nuxt@4.2.2(3b13fce02b4e8ad8c6ca8131442d4dba))(optionator@0.9.4)(rolldown@1.0.0-beta.55)(rollup@4.53.3)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.1.8(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3))(yaml@2.8.2) + '@unhead/vue': 2.0.19(vue@3.5.25(typescript@5.9.3)) + '@vue/shared': 3.5.25 + c12: 3.3.3(magicast@0.5.1) + chokidar: 5.0.0 + compatx: 0.2.0 + consola: 3.4.2 + cookie-es: 2.0.0 + defu: 6.1.4 + destr: 2.0.5 + devalue: 5.6.1 + errx: 0.1.0 + escape-string-regexp: 5.0.0 + exsolve: 1.0.8 + h3: 1.15.5 + hookable: 5.5.3 + ignore: 7.0.5 + impound: 1.0.0 + jiti: 2.6.1 + klona: 2.0.6 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.0 + nanotar: 0.2.0 + nypm: 0.6.2 + ofetch: 1.5.1 + ohash: 2.0.11 + on-change: 6.0.1 + oxc-minify: 0.102.0 + oxc-parser: 0.102.0 + oxc-transform: 0.102.0 + oxc-walker: 0.6.0(oxc-parser@0.102.0) + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 + radix3: 1.1.2 + scule: 1.3.0 + semver: 7.7.3 + std-env: 3.10.0 + tinyglobby: 0.2.15 + ufo: 1.6.3 + ultrahtml: 1.6.0 + uncrypto: 0.1.3 + unctx: 2.4.1 + unimport: 5.5.0 + unplugin: 2.3.11 + unplugin-vue-router: 0.19.1(@vue/compiler-sfc@3.5.25)(typescript@5.9.3)(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) + untyped: 2.0.0 + vue: 3.5.25(typescript@5.9.3) + vue-router: 4.6.3(vue@3.5.25(typescript@5.9.3)) + optionalDependencies: + '@parcel/watcher': 2.5.1 + '@types/node': 25.0.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@biomejs/biome' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - '@vitejs/devtools' + - '@vue/compiler-sfc' + - aws4fetch + - bare-abort-controller + - better-sqlite3 + - bufferutil + - cac + - commander + - db0 + - drizzle-orm + - encoding + - eslint + - idb-keyval + - ioredis + - less + - lightningcss + - magicast + - meow + - mysql2 + - optionator + - oxlint + - react-native-b4a + - rolldown + - rollup + - sass + - sass-embedded + - sqlite3 + - stylelint + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - uploadthing + - utf-8-validate + - vite + - vls + - vti + - vue-tsc + - xml2js + - yaml + + nuxt@4.2.2(fa4fa017741a39d7f93d443429824224): + dependencies: + '@dxup/nuxt': 0.2.2(magicast@0.5.1) + '@nuxt/cli': 3.31.1(cac@6.7.14)(magicast@0.5.1) + '@nuxt/devtools': 3.1.1(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) + '@nuxt/kit': 4.2.2(magicast@0.5.1) + '@nuxt/nitro-server': 4.2.2(fc969faf5d3879a1af702f7bf022d801) + '@nuxt/schema': 4.2.2 + '@nuxt/telemetry': 2.6.6(magicast@0.5.1) + '@nuxt/vite-builder': 4.2.2(@types/node@25.0.3)(eslint@9.39.2(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.5.1)(nuxt@4.2.2(fa4fa017741a39d7f93d443429824224))(optionator@0.9.4)(rolldown@1.0.0-beta.55)(rollup@4.53.3)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.1.8(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3))(yaml@2.8.2) '@unhead/vue': 2.0.19(vue@3.5.25(typescript@5.9.3)) '@vue/shared': 3.5.25 c12: 3.3.3(magicast@0.5.1) @@ -13529,6 +14373,9 @@ snapshots: pathe@2.0.3: {} + perfect-debounce@1.0.0: + optional: true + perfect-debounce@2.0.0: {} picocolors@1.1.1: {} @@ -13749,6 +14596,30 @@ snapshots: dependencies: parse-ms: 4.0.0 + prisma@5.22.0: + dependencies: + '@prisma/engines': 5.22.0 + optionalDependencies: + fsevents: 2.3.3 + + prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3): + dependencies: + '@prisma/config': 7.2.0(magicast@0.5.1) + '@prisma/dev': 0.17.0(typescript@5.9.3) + '@prisma/engines': 7.2.0 + '@prisma/studio-core': 0.9.0(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + mysql2: 3.15.3 + postgres: 3.4.7 + optionalDependencies: + better-sqlite3: 12.5.0 + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/react' + - magicast + - react + - react-dom + optional: true + process-nextick-args@2.0.1: {} process@0.11.10: {} @@ -13760,6 +14631,13 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + optional: true + property-information@7.1.0: {} protocols@2.0.2: {} @@ -13776,6 +14654,9 @@ snapshots: punycode@2.3.1: {} + pure-rand@6.1.0: + optional: true + qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -13813,6 +14694,15 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 + react-dom@19.2.3(react@19.2.3): + dependencies: + react: 19.2.3 + scheduler: 0.27.0 + optional: true + + react@19.2.3: + optional: true + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -13870,6 +14760,9 @@ snapshots: '@eslint-community/regexpp': 4.12.2 refa: 0.12.1 + regexp-to-ast@0.5.0: + optional: true + regexp-tree@0.1.27: {} regjsparser@0.13.0: @@ -14005,6 +14898,11 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 + remeda@2.21.3: + dependencies: + type-fest: 4.41.0 + optional: true + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -14025,6 +14923,9 @@ snapshots: restructure@3.0.2: {} + retry@0.12.0: + optional: true + retry@0.13.1: {} reusify@1.1.0: {} @@ -14157,6 +15058,9 @@ snapshots: sax@1.4.3: {} + scheduler@0.27.0: + optional: true + scslre@0.3.0: dependencies: '@eslint-community/regexpp': 4.12.2 @@ -14291,6 +15195,9 @@ snapshots: siginfo@2.0.0: {} + signal-exit@3.0.7: + optional: true + signal-exit@4.1.0: {} simple-concat@1.0.1: {} @@ -14388,6 +15295,9 @@ snapshots: std-env@3.10.0: {} + std-env@3.9.0: + optional: true + streamx@2.23.0: dependencies: events-universal: 1.0.1 @@ -14626,6 +15536,9 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@4.41.0: + optional: true + type-fest@5.3.0: dependencies: tagged-tag: 1.0.0 @@ -14887,7 +15800,7 @@ snapshots: dependencies: rolldown: 1.0.0-beta.55 - unstorage@1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3))(ioredis@5.8.2): + unstorage@1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3))(ioredis@5.8.2): dependencies: anymatch: 3.1.3 chokidar: 5.0.0 @@ -14901,7 +15814,24 @@ snapshots: '@upstash/redis': 1.35.8 '@vercel/blob': 2.0.0 aws4fetch: 1.0.20 - db0: 0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7))(mysql2@3.15.3) + db0: 0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@5.22.0))(mysql2@3.15.3) + ioredis: 5.8.2 + + unstorage@1.17.4(@upstash/redis@1.35.8)(@vercel/blob@2.0.0)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3))(ioredis@5.8.2): + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.5 + lru-cache: 11.2.4 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.3 + optionalDependencies: + '@upstash/redis': 1.35.8 + '@vercel/blob': 2.0.0 + aws4fetch: 1.0.20 + db0: 0.3.4(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(better-sqlite3@12.5.0)(drizzle-orm@0.45.1(@cloudflare/workers-types@4.20251219.0)(@electric-sql/pglite@0.3.14)(@libsql/client@0.15.15)(@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3))(@upstash/redis@1.35.8)(better-sqlite3@12.5.0)(mysql2@3.15.3)(postgres@3.4.7)(prisma@7.2.0(@types/react@19.2.8)(better-sqlite3@12.5.0)(magicast@0.5.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)))(mysql2@3.15.3) ioredis: 5.8.2 untun@0.1.3: @@ -15292,6 +16222,11 @@ snapshots: cookie-es: 2.0.0 youch-core: 0.3.3 + zeptomatch@2.0.2: + dependencies: + grammex: 3.1.12 + optional: true + zip-stream@6.0.1: dependencies: archiver-utils: 5.0.2 diff --git a/src/db/adapters/drizzle.ts b/src/db/adapters/drizzle.ts new file mode 100644 index 000000000..85d3d1c08 --- /dev/null +++ b/src/db/adapters/drizzle.ts @@ -0,0 +1,291 @@ +import type { HubDbAdapter, HubDbAdapterContext, Driver } from './interface' + +export const drizzleAdapter: HubDbAdapter = { + name: 'drizzle', + schemaPath: 'server/db/schema.ts', + requiredDeps: ['drizzle-orm'], + requiredDevDeps: ['drizzle-kit'], + + async validateSchema(_ctx: HubDbAdapterContext): Promise { + // Drizzle schema validation is handled by TypeScript compilation + // No additional validation needed + }, + + checkMissingDeps(deps: Record, driver: Driver): string[] { + const missing: string[] = [] + + if (!deps['drizzle-orm']) missing.push('drizzle-orm') + if (!deps['drizzle-kit']) missing.push('drizzle-kit') + + // Driver-specific deps + if (driver === 'postgres-js' && !deps['postgres']) missing.push('postgres') + if (driver === 'neon-http' && !deps['@neondatabase/serverless']) missing.push('@neondatabase/serverless') + if (driver === 'pglite' && !deps['@electric-sql/pglite']) missing.push('@electric-sql/pglite') + if (driver === 'mysql2' && !deps.mysql2) missing.push('mysql2') + if (driver === 'libsql' && !deps['@libsql/client']) missing.push('@libsql/client') + + return missing + }, + + createClientCode(ctx: HubDbAdapterContext): string { + const { dbConfig, hub } = ctx + const { dialect, driver, connection, mode, casing } = dbConfig + + const modeOption = dialect === 'mysql' ? `, mode: '${mode || 'default'}'` : '' + const casingOption = casing ? `, casing: '${casing}'` : '' + + const executeMethod = dialect === 'sqlite' ? 'run' : 'execute' + const getRowsCode = dialect === 'mysql' + ? '(result) => result[0] || []' + : '(result) => result.results || result.rows || result || []' + + // Default implementation + let code = `import { drizzle } from 'drizzle-orm/${driver}' +import { sql } from 'drizzle-orm' +import * as schema from './db/schema.mjs' + +const db = drizzle({ connection: ${JSON.stringify(connection)}, schema${modeOption}${casingOption} }) + +// Execute raw SQL for migrations (ORM-agnostic interface) +async function executeRaw(query) { + return db.${executeMethod}(sql.raw(query)) +} +const getRows = ${getRowsCode} + +export { db, schema, executeRaw, getRows } +` + + if (driver === 'pglite' && ctx.nuxt.options.dev) { + // PGlite instance exported for use in devtools Drizzle Studio + code = `import { drizzle } from 'drizzle-orm/pglite' +import { sql } from 'drizzle-orm' +import { PGlite } from '@electric-sql/pglite' +import * as schema from './db/schema.mjs' + +const client = new PGlite(${JSON.stringify(connection.dataDir)}) +const db = drizzle({ client, schema${casingOption} }) + +async function executeRaw(query) { return db.${executeMethod}(sql.raw(query)) } +const getRows = ${getRowsCode} + +export { db, schema, client, executeRaw, getRows } +` + } + + if (driver === 'postgres-js' && ctx.nuxt.options.dev) { + const replicaUrls = (dbConfig.replicas || []).filter(Boolean) + const hasReplicas = replicaUrls.length > 0 + + if (hasReplicas) { + code = `import { drizzle } from 'drizzle-orm/postgres-js' +import { sql } from 'drizzle-orm' +import { withReplicas } from 'drizzle-orm/pg-core' +import postgres from 'postgres' +import * as schema from './db/schema.mjs' + +const primaryClient = postgres(${JSON.stringify(connection.url)}, { onnotice: () => {} }) +const primary = drizzle({ client: primaryClient, schema${casingOption} }) +const replicas = [${replicaUrls.map(url => `drizzle({ client: postgres(${JSON.stringify(url)}, { onnotice: () => {} }), schema${casingOption} })`).join(', ')}] +const db = withReplicas(primary, replicas) + +async function executeRaw(query) { return primary.${executeMethod}(sql.raw(query)) } +const getRows = ${getRowsCode} + +export { db, schema, executeRaw, getRows } +` + } else { + code = `import { drizzle } from 'drizzle-orm/postgres-js' +import { sql } from 'drizzle-orm' +import postgres from 'postgres' +import * as schema from './db/schema.mjs' + +const client = postgres(${JSON.stringify(connection.url)}, { + onnotice: () => {} +}) +const db = drizzle({ client, schema${casingOption} }) + +async function executeRaw(query) { return db.${executeMethod}(sql.raw(query)) } +const getRows = ${getRowsCode} + +export { db, schema, executeRaw, getRows } +` + } + } + + if (driver === 'mysql2' && ctx.nuxt.options.dev) { + const replicaUrls = (dbConfig.replicas || []).filter(Boolean) + const hasReplicas = replicaUrls.length > 0 + + if (hasReplicas) { + code = `import { drizzle } from 'drizzle-orm/mysql2' +import { sql } from 'drizzle-orm' +import { withReplicas } from 'drizzle-orm/mysql-core' +import * as schema from './db/schema.mjs' + +const primary = drizzle({ connection: ${JSON.stringify(connection)}, schema${modeOption}${casingOption} }) +const replicas = [${replicaUrls.map(url => `drizzle({ connection: { uri: ${JSON.stringify(url)} }, schema${modeOption}${casingOption} })`).join(', ')}] +const db = withReplicas(primary, replicas) + +async function executeRaw(query) { return primary.${executeMethod}(sql.raw(query)) } +const getRows = ${getRowsCode} + +export { db, schema, executeRaw, getRows } +` + } + } + + if (driver === 'neon-http') { + code = `import { neon } from '@neondatabase/serverless' +import { drizzle } from 'drizzle-orm/neon-http' +import { sql as sqlTag } from 'drizzle-orm' +import * as schema from './db/schema.mjs' + +const neonSql = neon(${JSON.stringify(connection.url)}) +const db = drizzle(neonSql, { schema${casingOption} }) + +async function executeRaw(query) { return db.${executeMethod}(sqlTag.raw(query)) } +const getRows = ${getRowsCode} + +export { db, schema, executeRaw, getRows } +` + } + + if (driver === 'd1') { + // D1 requires lazy binding access - bindings only available in request context on CF Workers + code = `import { drizzle } from 'drizzle-orm/d1' +import { sql } from 'drizzle-orm' +import * as schema from './db/schema.mjs' + +let _db +function getDb() { + if (!_db) { + const binding = process.env.DB || globalThis.__env__?.DB || globalThis.DB + if (!binding) throw new Error('DB binding not found') + _db = drizzle(binding, { schema${casingOption} }) + } + return _db +} +const db = new Proxy({}, { get(_, prop) { return getDb()[prop] } }) + +async function executeRaw(query) { return getDb().${executeMethod}(sql.raw(query)) } +const getRows = ${getRowsCode} + +export { db, schema, executeRaw, getRows } +` + } + + if (driver === 'd1-http') { + // D1 over HTTP using sqlite-proxy - use env vars at runtime to avoid token exposure in generated code + code = `import { drizzle } from 'drizzle-orm/sqlite-proxy' +import { sql as sqlTag } from 'drizzle-orm' +import * as schema from './db/schema.mjs' + +const accountId = process.env.NUXT_HUB_CLOUDFLARE_ACCOUNT_ID +const databaseId = process.env.NUXT_HUB_CLOUDFLARE_DATABASE_ID +const apiToken = process.env.NUXT_HUB_CLOUDFLARE_API_TOKEN + +async function d1HttpDriver(sql, params, method) { + if (method === 'values') method = 'all' + + const { errors, success, result } = await $fetch(\`https://api.cloudflare.com/client/v4/accounts/\${accountId}/d1/db/\${databaseId}/raw\`, { + method: 'POST', + headers: { + Authorization: \`Bearer \${apiToken}\`, + 'Content-Type': 'application/json' + }, + async onResponseError({ request, response, options }) { + console.error( + "D1 HTTP Error:", + request, + options.body, + response.status, + response._data, + ) + }, + body: { sql, params } + }) + + if (errors?.length > 0 || !success) { + throw new Error(\`D1 HTTP error: \${JSON.stringify({ errors, success, result })}\`) + } + + const queryResult = result?.[0] + if (!queryResult?.success) { + throw new Error(\`D1 HTTP error: \${JSON.stringify({ errors, success, result })}\`) + } + + const rows = queryResult.results?.rows || [] + + if (method === 'get') { + if (rows.length === 0) { + return { rows: [] } + } + return { rows: rows[0] } + } + + return { rows } +} + +const db = drizzle(d1HttpDriver, { schema${casingOption} }) + +async function executeRaw(query) { return db.${executeMethod}(sqlTag.raw(query)) } +const getRowsFn = ${getRowsCode} + +export { db, schema, executeRaw, getRows: getRowsFn } +` + } + + if (['postgres-js', 'mysql2'].includes(driver) && hub.hosting.includes('cloudflare')) { + // Hyperdrive requires lazy binding access - bindings only available in request context on CF Workers + const bindingName = driver === 'postgres-js' ? 'POSTGRES' : 'MYSQL' + code = `import { drizzle } from 'drizzle-orm/${driver}' +import { sql } from 'drizzle-orm' +import * as schema from './db/schema.mjs' + +let _db +function getDb() { + if (!_db) { + const hyperdrive = process.env.${bindingName} || globalThis.__env__?.${bindingName} || globalThis.${bindingName} + if (!hyperdrive) throw new Error('${bindingName} binding not found') + _db = drizzle({ connection: hyperdrive.connectionString, schema${modeOption}${casingOption} }) + } + return _db +} +const db = new Proxy({}, { get(_, prop) { return getDb()[prop] } }) + +async function executeRaw(query) { return getDb().${executeMethod}(sql.raw(query)) } +const getRows = ${getRowsCode} + +export { db, schema, executeRaw, getRows } +` + } + + return code + }, + + getClientTypes(ctx: HubDbAdapterContext): string { + const { driver } = ctx.dbConfig + // For types, d1-http uses sqlite-proxy + const driverForTypes = driver === 'd1-http' ? 'sqlite-proxy' : driver + + return `import type { DrizzleConfig } from 'drizzle-orm' +import { drizzle as drizzleCore } from 'drizzle-orm/${driverForTypes}' +import * as schema from './db/schema.mjs' + +declare module 'hub:db' { + /** + * The database schema object + * Defined in server/db/schema.ts and server/db/schema/*.ts + */ + export { schema } + /** + * The ${driver} database client. + */ + export const db: ReturnType> + /** Execute raw SQL for migrations */ + export function executeRaw(query: string): Promise + /** Extract rows from query result */ + export function getRows(result: unknown): unknown[] +}` + } +} diff --git a/src/db/adapters/interface.ts b/src/db/adapters/interface.ts new file mode 100644 index 000000000..535ba42eb --- /dev/null +++ b/src/db/adapters/interface.ts @@ -0,0 +1,71 @@ +import type { Nuxt } from '@nuxt/schema' +import type { ResolvedDatabaseConfig, ResolvedHubConfig } from '@nuxthub/core' + +export type OrmType = 'drizzle' | 'prisma' +export type Dialect = 'sqlite' | 'postgresql' | 'mysql' +export type Driver = 'better-sqlite3' | 'libsql' | 'bun-sqlite' | 'd1' | 'd1-http' | 'postgres-js' | 'pglite' | 'neon-http' | 'mysql2' + +export interface HubDbAdapterContext { + nuxt: Nuxt + hub: ResolvedHubConfig + dbConfig: ResolvedDatabaseConfig +} + +/** + * Adapter interface for ORM integrations. + * Implementations generate client code, type definitions, and handle ORM-specific setup. + */ +export interface HubDbAdapter { + /** Unique adapter identifier */ + name: OrmType + + /** Default schema file path (e.g., 'server/db/schema.ts' for Drizzle, 'prisma/schema.prisma' for Prisma) */ + schemaPath: string + + /** Validate schema exists and is correctly configured */ + validateSchema(ctx: HubDbAdapterContext): Promise + + /** Generate the runtime client module code exported from 'hub:db' */ + createClientCode(ctx: HubDbAdapterContext): string + + /** Generate TypeScript declaration for 'hub:db' module */ + getClientTypes(ctx: HubDbAdapterContext): string + + /** Start database studio UI (optional). Returns the port number. */ + startStudio?(ctx: HubDbAdapterContext, port: number): Promise + + /** Runtime dependencies required by this adapter (e.g., 'drizzle-orm') */ + requiredDeps: string[] + + /** Dev dependencies required by this adapter (e.g., 'drizzle-kit') */ + requiredDevDeps: string[] + + /** Returns list of missing dependencies based on installed deps and driver */ + checkMissingDeps(installedDeps: Record, driver: Driver): string[] + + /** Hook called during 'prepare:types' for additional setup (e.g., Prisma generate) */ + onPrepareTypes?(ctx: HubDbAdapterContext): Promise +} + +/** Registry of available adapters */ +const adapters = new Map Promise>() + +export function registerAdapter(name: OrmType, loader: () => Promise) { + adapters.set(name, loader) +} + +export async function getAdapter(name: OrmType): Promise { + const loader = adapters.get(name) + if (!loader) { + throw new Error(`Unknown ORM adapter: ${name}. Available: ${[...adapters.keys()].join(', ')}`) + } + return loader() +} + +export function getAvailableAdapters(): OrmType[] { + return [...adapters.keys()] +} + +// Register built-in adapters +registerAdapter('drizzle', () => import('./drizzle').then(m => m.drizzleAdapter)) +registerAdapter('prisma', () => import('./prisma').then(m => m.prismaAdapter)) diff --git a/src/db/adapters/prisma.ts b/src/db/adapters/prisma.ts new file mode 100644 index 000000000..465e10b35 --- /dev/null +++ b/src/db/adapters/prisma.ts @@ -0,0 +1,140 @@ +import type { HubDbAdapter, HubDbAdapterContext, Driver } from './interface' + +export const prismaAdapter: HubDbAdapter = { + name: 'prisma', + schemaPath: 'prisma/schema.prisma', + requiredDeps: ['@prisma/client'], + requiredDevDeps: ['prisma'], + + async validateSchema(ctx: HubDbAdapterContext): Promise { + const { existsSync } = await import('node:fs') + const { join } = await import('pathe') + const schemaPath = join(ctx.nuxt.options.rootDir, 'prisma/schema.prisma') + if (!existsSync(schemaPath)) { + throw new Error(`Prisma schema not found at ${schemaPath}. Run \`npx prisma init\` to create it.`) + } + }, + + checkMissingDeps(deps: Record, driver: Driver): string[] { + const missing: string[] = [] + + if (!deps['@prisma/client']) missing.push('@prisma/client') + if (!deps.prisma) missing.push('prisma') + + // Prisma adapter-specific deps + if (driver === 'd1' && !deps['@prisma/adapter-d1']) missing.push('@prisma/adapter-d1') + if (driver === 'pglite' && !deps['@prisma/adapter-pg-lite']) missing.push('@prisma/adapter-pg-lite') + if (driver === 'libsql') { + if (!deps['@prisma/adapter-libsql']) missing.push('@prisma/adapter-libsql') + if (!deps['@libsql/client']) missing.push('@libsql/client') + } + + return missing + }, + + createClientCode(ctx: HubDbAdapterContext): string { + const { driver, connection } = ctx.dbConfig + + if (driver === 'd1') { + return `import pkg from '@prisma/client' +const { PrismaClient } = pkg +import { PrismaD1 } from '@prisma/adapter-d1' + +let _db +function getDb() { + if (!_db) { + const binding = process.env.DB || globalThis.__env__?.DB || globalThis.DB + if (!binding) throw new Error('DB binding not found') + const adapter = new PrismaD1(binding) + _db = new PrismaClient({ adapter }) + } + return _db +} +const db = new Proxy({}, { get(_, prop) { return getDb()[prop] } }) + +async function executeRaw(query) { return getDb().$executeRawUnsafe(query) } +const getRows = (result) => result || [] + +export { db, executeRaw, getRows } +` + } + + if (driver === 'pglite') { + return `import pkg from '@prisma/client' +const { PrismaClient } = pkg +import { PrismaPGlite } from '@prisma/adapter-pg-lite' +import { PGlite } from '@electric-sql/pglite' + +const client = new PGlite(${JSON.stringify(connection.dataDir)}) +const adapter = new PrismaPGlite(client) +const db = new PrismaClient({ adapter }) + +async function executeRaw(query) { return db.$executeRawUnsafe(query) } +const getRows = (result) => result || [] + +export { db, client, executeRaw, getRows } +` + } + + if (driver === 'libsql') { + return `import pkg from '@prisma/client' +const { PrismaClient } = pkg +import { PrismaLibSQL } from '@prisma/adapter-libsql' +import { createClient } from '@libsql/client' + +const libsql = createClient(${JSON.stringify(connection)}) +const adapter = new PrismaLibSQL(libsql) +const db = new PrismaClient({ adapter }) + +async function executeRaw(query) { return db.$executeRawUnsafe(query) } +const getRows = (result) => result || [] + +export { db, executeRaw, getRows } +` + } + + // Default: use DATABASE_URL from env + return `import pkg from '@prisma/client' +const { PrismaClient } = pkg + +const db = new PrismaClient() + +async function executeRaw(query) { return db.$executeRawUnsafe(query) } +const getRows = (result) => result || [] + +export { db, executeRaw, getRows } +` + }, + + getClientTypes(_ctx: HubDbAdapterContext): string { + return `import { PrismaClient } from '@prisma/client' + +declare module 'hub:db' { + /** + * The Prisma database client. + */ + export const db: PrismaClient + /** Execute raw SQL for migrations */ + export function executeRaw(query: string): Promise + /** Extract rows from query result */ + export function getRows(result: unknown): unknown[] +}` + }, + + async onPrepareTypes(ctx: HubDbAdapterContext): Promise { + const { execa } = await import('execa') + const { logger } = await import('@nuxt/kit') + const log = logger.withTag('nuxt:hub') + + log.info('Generating Prisma client...') + try { + await execa('npx', ['prisma', 'generate'], { + cwd: ctx.nuxt.options.rootDir, + stdio: 'inherit' + }) + } catch (error) { + log.error('Failed to generate Prisma client:', error) + throw error + } + } +} diff --git a/src/db/lib/build.ts b/src/db/lib/build.ts index 46734440f..cf7b527ff 100644 --- a/src/db/lib/build.ts +++ b/src/db/lib/build.ts @@ -3,7 +3,6 @@ import { join, relative, resolve } from 'pathe' import type { Nitro } from 'nitropack' import type { ResolvedHubConfig } from '@nuxthub/core' import { consola } from 'consola' -import { createDrizzleClient } from './client' import { applyDatabaseMigrations, applyDatabaseQueries } from './migrations' import { build } from 'tsdown' @@ -57,19 +56,31 @@ export async function applyBuildTimeMigrations(nitro: Nitro, hub: ResolvedHubCon if (!hub.db || !hub.db.applyMigrationsDuringBuild) return try { + // Dynamically import drizzle-orm and client only when needed + const { sql } = await import('drizzle-orm') + const { createDrizzleClient } = await import('./client') const db = await createDrizzleClient(hub.db, hub.dir) + // Wrap Drizzle client in executor interface for migrations + const executor = { + executeRaw: async (query: string) => { + const result = await db.run(sql.raw(query)) + return result.rows || [] + }, + getRows: (result: unknown) => (result as unknown[]) || [] + } + const buildHubConfig = { ...hub, dir: nitro.options.output.serverDir } as ResolvedHubConfig log.info('Applying database migrations...') - const migrationsApplied = await applyDatabaseMigrations(buildHubConfig, db) + const migrationsApplied = await applyDatabaseMigrations(buildHubConfig, executor) if (migrationsApplied === false) { process.exit(1) } - const queriesApplied = await applyDatabaseQueries(buildHubConfig, db) + const queriesApplied = await applyDatabaseQueries(buildHubConfig, executor) if (queriesApplied === false) { process.exit(1) } diff --git a/src/db/lib/migrations.ts b/src/db/lib/migrations.ts index 1f1cf2d61..f7c030ee5 100644 --- a/src/db/lib/migrations.ts +++ b/src/db/lib/migrations.ts @@ -4,39 +4,56 @@ import type { ResolvedHubConfig } from '@nuxthub/core' import { AppliedDatabaseMigrationsQuery, getCreateMigrationsTableQuery, splitSqlQueries } from './utils' import { useDatabaseMigrationsStorage, getDatabaseMigrationFiles, useDatabaseQueriesStorage, getDatabaseQueryFiles } from './storage' +interface DbExecutor { + executeRaw: (query: string) => Promise + getRows?: (result: unknown) => unknown[] +} + +/** Escape single quotes in SQL string literals to prevent injection */ +function escapeSqlString(value: string): string { + return value.replace(/'/g, '\'\'') +} + +/** Extract error message from unknown error */ +function getErrorMessage(error: unknown): string { + if (error instanceof Error) { + const cause = error.cause + if (cause instanceof Error) return cause.message + return error.message + } + return String(error) +} + +/** Type for migration row results (handles both object and array formats) */ +type MigrationRow = { name: string } | [unknown, string] + function getRelativePath(fullPath: string) { return relative(process.cwd(), fullPath) } -export async function applyDatabaseMigrations(hub: ResolvedHubConfig, db: any) { +export async function applyDatabaseMigrations(hub: ResolvedHubConfig, executor: DbExecutor) { if (!hub.db) return // Create a logger for this function (at runtime so we can have the debug level when run by the CLI) const log = consola.withTag('nuxt:hub') const migrationsStorage = useDatabaseMigrationsStorage(hub) - const dialect = hub.db.dialect - const execute = dialect === 'sqlite' ? 'run' : 'execute' - const getRows = (result: any) => (dialect === 'mysql' ? result[0] : result.results || result.rows || result) || [] + const { executeRaw, getRows = (r: unknown) => (r as unknown[]) || [] } = executor const createMigrationsTableQuery = getCreateMigrationsTableQuery({ dialect: hub.db.dialect }) log.debug('Creating migrations table if not exists...') - const drizzleOrmPkg = 'drizzle-orm' - const sql = await import(drizzleOrmPkg).then(m => m.sql) try { - await db[execute](sql.raw(createMigrationsTableQuery)) - } catch (error: any) { - const message = error.cause?.message || error.message - log.error(`Failed to create migrations table\n${message}`) + await executeRaw(createMigrationsTableQuery) + } catch (error) { + log.error(`Failed to create migrations table\n${getErrorMessage(error)}`) return false } log.debug('Successfully created migrations table if not exists') - let appliedRows = [] + let appliedRows: unknown[] = [] try { - appliedRows = getRows(await db[execute](sql.raw(AppliedDatabaseMigrationsQuery))) - } catch (error: any) { - const message = error.cause?.message || error.message - log.error(`Failed to fetch applied migrations\n${message}`) + appliedRows = getRows(await executeRaw(AppliedDatabaseMigrationsQuery)) + } catch (error) { + log.error(`Failed to fetch applied migrations\n${getErrorMessage(error)}`) return false } if (!import.meta.dev) { @@ -44,8 +61,9 @@ export async function applyDatabaseMigrations(hub: ResolvedHubConfig, db: any) { } const localMigrations = await getDatabaseMigrationFiles(hub) - const pendingMigrations = localMigrations.filter(migration => !appliedRows.find((row: any) => { - const name = row.name || row[1] // Handle both object and array responses + const pendingMigrations = localMigrations.filter(migration => !appliedRows.find((row) => { + const r = row as MigrationRow + const name = Array.isArray(r) ? r[1] : r.name return name === migration.name })) if (!pendingMigrations.length) { @@ -55,19 +73,22 @@ export async function applyDatabaseMigrations(hub: ResolvedHubConfig, db: any) { for (const migration of pendingMigrations) { let query = await migrationsStorage.getItem(migration.filename) - if (!query) continue - query += `\nINSERT INTO _hub_migrations (name) values ('${migration.name}');` + if (!query) { + log.warn(`Migration file \`${migration.filename}\` is empty or could not be read, skipping`) + continue + } + query += `\nINSERT INTO _hub_migrations (name) values ('${escapeSqlString(migration.name)}');` const queries = splitSqlQueries(query) try { log.debug(`Applying database migration \`${getRelativePath(join(hub.dir!, 'db/migrations', migration.filename))}\`...`) - for (const query of queries) { - await db[execute](sql.raw(query)) + for (const q of queries) { + await executeRaw(q) } - } catch (error: any) { - const message = error.cause?.message || error.message + } catch (error) { + const message = getErrorMessage(error) log.error(`Failed to apply migration \`${getRelativePath(join(hub.dir!, 'db/migrations', migration.filename))}\`\n${message}`) - if (message?.includes('already exists')) { + if (message.includes('already exists')) { log.info(`To mark this migration as applied, run \`npx nuxt db mark-as-migrated ${migration.name}\``) log.info('To drop a table, run `npx nuxt db drop `') } @@ -80,29 +101,29 @@ export async function applyDatabaseMigrations(hub: ResolvedHubConfig, db: any) { return true } -export async function applyDatabaseQueries(hub: ResolvedHubConfig, db: any) { +export async function applyDatabaseQueries(hub: ResolvedHubConfig, executor: { executeRaw: (query: string) => Promise }) { if (!hub.db) return // Create a logger for this function (at runtime so we can have the debug level when run by the CLI) const log = consola.withTag('nuxt:hub') const queriesStorage = useDatabaseQueriesStorage(hub) const queriesFiles = await getDatabaseQueryFiles(hub) if (!queriesFiles.length) return - const execute = hub.db.dialect === 'sqlite' ? 'run' : 'execute' + const { executeRaw } = executor for (const queryFile of queriesFiles) { const sqlQuery = await queriesStorage.getItem(queryFile.filename) - if (!sqlQuery) continue + if (!sqlQuery) { + log.warn(`Query file \`${queryFile.filename}\` is empty or could not be read, skipping`) + continue + } const queries = splitSqlQueries(sqlQuery) - const drizzleOrmPkg = 'drizzle-orm' - const sql = await import(drizzleOrmPkg).then(m => m.sql) try { log.debug(`Applying database query \`${getRelativePath(join(hub.dir!, 'db/queries', queryFile.filename))}\`...`) - for (const query of queries) { - await db[execute](sql.raw(query)) + for (const q of queries) { + await executeRaw(q) } - } catch (error: any) { - const message = error.cause?.message || error.message - log.error(`Failed to apply query \`${getRelativePath(join(hub.dir!, 'db/queries', queryFile.filename))}\`\n${message}`) + } catch (error) { + log.error(`Failed to apply query \`${getRelativePath(join(hub.dir!, 'db/queries', queryFile.filename))}\`\n${getErrorMessage(error)}`) return false } diff --git a/src/db/runtime/plugins/migrations.dev.ts b/src/db/runtime/plugins/migrations.dev.ts index 71d2ccc19..7a909b088 100644 --- a/src/db/runtime/plugins/migrations.dev.ts +++ b/src/db/runtime/plugins/migrations.dev.ts @@ -8,10 +8,11 @@ export default defineNitroPlugin(async () => { const hub = useRuntimeConfig().hub as ResolvedHubConfig if (!hub.db) return - let db + let executeRaw, getRows try { const module = await import('hub:db') - db = module.db + executeRaw = module.executeRaw + getRows = module.getRows } catch (error) { console.error('[nuxt:hub] Failed to import hub:db module:', error instanceof Error ? error.message : error) console.error('[nuxt:hub] This may happen when using remote bindings before the proxy is initialized.') @@ -19,6 +20,6 @@ export default defineNitroPlugin(async () => { return } - await applyDatabaseMigrations(hub, db) - await applyDatabaseQueries(hub, db) + await applyDatabaseMigrations(hub, { executeRaw, getRows }) + await applyDatabaseQueries(hub, { executeRaw }) }) diff --git a/src/db/setup.ts b/src/db/setup.ts index a9cde46b7..f3209cee1 100644 --- a/src/db/setup.ts +++ b/src/db/setup.ts @@ -1,4 +1,4 @@ -import { mkdir, copyFile, writeFile, readFile, stat } from 'node:fs/promises' +import { mkdir, copyFile, writeFile, readFile } from 'node:fs/promises' import chokidar from 'chokidar' import { glob } from 'tinyglobby' import { join, resolve as resolveFs, relative } from 'pathe' @@ -7,34 +7,14 @@ import { addServerImports, addTemplate, addServerPlugin, addTypeTemplate, getLay import { resolve, resolvePath, logWhenReady, addWranglerBinding } from '../utils' import { copyDatabaseMigrationsToHubDir, copyDatabaseQueriesToHubDir, copyDatabaseAssets, applyBuildTimeMigrations, getDatabaseSchemaPathMetadata, buildDatabaseSchema } from './lib' import { cloudflareHooks } from '../hosting/cloudflare' +import { getAdapter } from './adapters/interface' +import type { HubDbAdapter } from './adapters/interface' import type { Nuxt } from '@nuxt/schema' import type { HubConfig, ResolvedHubConfig, ResolvedDatabaseConfig } from '@nuxthub/core' const log = logger.withTag('nuxt:hub') -/** - * Generate a lazy-initialized db template with Proxy wrapper - * Used for runtime env resolution (Docker/multi-deploy) and CF bindings - */ -function generateLazyDbTemplate(imports: string, getDbBody: string): string { - return `${imports} -import * as schema from './db/schema.mjs' - -let _db -function getDb() { - if (!_db) { - try { -${getDbBody} - } catch (e) { throw new Error('[nuxt-hub] ' + e.message) } - } - return _db -} -const db = new Proxy({}, { get(_, prop) { return getDb()[prop] } }) -export { db, schema } -` -} - /** * Resolve database configuration from string or object format */ @@ -43,6 +23,7 @@ export async function resolveDatabaseConfig(nuxt: Nuxt, hub: HubConfig): Promise let config = typeof hub.db === 'string' ? { dialect: hub.db } : hub.db config = defu(config, { + orm: 'drizzle', migrationsDirs: getLayerDirectories(nuxt).map(layer => join(layer.server, 'db/migrations')), queriesPaths: [], applyMigrationsDuringBuild: true @@ -123,6 +104,9 @@ export async function resolveDatabaseConfig(nuxt: Nuxt, hub: HubConfig): Promise } break } + default: { + throw new Error(`Unsupported database dialect: ${config.dialect}. Supported: sqlite, postgresql, mysql`) + } } // Disable migrations if database connection is not supported in CI @@ -133,13 +117,16 @@ export async function resolveDatabaseConfig(nuxt: Nuxt, hub: HubConfig): Promise return config as ResolvedDatabaseConfig } -export async function setupDatabase(nuxt: Nuxt, hub: HubConfig, deps: Record) { +export async function setupDatabase(nuxt: Nuxt, hub: HubConfig, deps: Record): Promise { hub.db = await resolveDatabaseConfig(nuxt, hub) if (!hub.db) return - const { dialect, driver, connection, migrationsDirs, queriesPaths } = hub.db as ResolvedDatabaseConfig + const { orm, dialect, driver, connection, migrationsDirs, queriesPaths } = hub.db as ResolvedDatabaseConfig - logWhenReady(nuxt, `\`hub:db\` using \`${dialect}\` database with \`${driver}\` driver`, 'info') + // Get the ORM adapter + const adapter = await getAdapter(orm) + + logWhenReady(nuxt, `\`hub:db\` using \`${dialect}\` database with \`${driver}\` driver (${orm})`, 'info') if (driver === 'd1' && connection?.databaseId) { addWranglerBinding(nuxt, 'd1_databases', { binding: 'DB', database_id: connection.databaseId }) @@ -149,20 +136,10 @@ export async function setupDatabase(nuxt: Nuxt, hub: HubConfig, deps: Record 0) { + logWhenReady(nuxt, `Please run \`npx nypm i ${missingDeps.join(' ')}\` to properly setup ${orm} with NuxtHub.`, 'error') } // Add Server scanning @@ -170,8 +147,10 @@ export async function setupDatabase(nuxt: Nuxt, hub: HubConfig, deps: Record { - // generate database schema - await generateDatabaseSchema(nuxt, hub as ResolvedHubConfig) + // generate database schema (Drizzle only - Prisma uses its own schema format) + if (orm === 'drizzle') { + await generateDatabaseSchema(nuxt, hub as ResolvedHubConfig) + } // Call hub:db:migrations:dirs hook await nuxt.callHook('hub:db:migrations:dirs', migrationsDirs) // Copy all migrations files to the hub.dir directory @@ -208,8 +187,8 @@ export async function setupDatabase(nuxt: Nuxt, hub: HubConfig, deps: Record databaseTypes }, { nitro: true, nuxt: true }) - // Setup Drizzle ORM - - // Generate simplified drizzle() implementation - const modeOption = dialect === 'mysql' ? `, mode: '${mode || 'default'}'` : '' - const casingOption = casing ? `, casing: '${casing}'` : '' - let drizzleOrmContent = `import { drizzle } from 'drizzle-orm/${driver}' -import * as schema from './db/schema.mjs' - -const db = drizzle({ connection: ${JSON.stringify(connection)}, schema${modeOption}${casingOption} }) -export { db, schema } -` - - if (driver === 'pglite' && nuxt.options.dev) { - // PGlite instance exported for use in devtools Drizzle Studio - drizzleOrmContent = `import { drizzle } from 'drizzle-orm/pglite' -import { PGlite } from '@electric-sql/pglite' -import * as schema from './db/schema.mjs' - -const client = new PGlite(${JSON.stringify(connection.dataDir)}) -const db = drizzle({ client, schema${casingOption} }) -export { db, schema, client } -` + // Generate client code via adapter + const clientCode = adapter.createClientCode(ctx) + // For Drizzle with PGlite in dev, add the studio launch handler + if (orm === 'drizzle' && driver === 'pglite' && nuxt.options.dev) { addServerHandler({ handler: await resolvePath('db/runtime/api/launch-studio.post.dev'), method: 'post', route: '/api/_hub/db/launch-studio' }) } - if (driver === 'postgres-js' && nuxt.options.dev) { - // disable notice logger for postgres-js in dev - const replicaUrls = (replicas || []).filter(Boolean) - const hasReplicas = replicaUrls.length > 0 - - drizzleOrmContent = `import { drizzle } from 'drizzle-orm/postgres-js' -${hasReplicas ? `import { withReplicas } from 'drizzle-orm/pg-core'\n` : ''}import postgres from 'postgres' -import * as schema from './db/schema.mjs' - -const client = postgres('${connection.url}', { onnotice: () => {} }) -${hasReplicas - ? `const primary = drizzle({ client, schema${casingOption} }) - -const replicaUrls = ${JSON.stringify(replicaUrls)} -const replicaConnections = replicaUrls.map(replicaUrl => { - const replicaClient = postgres(replicaUrl, { onnotice: () => {} }) - return drizzle({ client: replicaClient, schema${casingOption} }) -}) -const db = withReplicas(primary, replicaConnections)` - : `const db = drizzle({ client, schema${casingOption} })`} -export { db, schema } -` - } - if (driver === 'mysql2' && nuxt.options.dev) { - const replicaUrls = (replicas || []).filter(Boolean) - const hasReplicas = replicaUrls.length > 0 - - if (hasReplicas) { - drizzleOrmContent = `import { drizzle } from 'drizzle-orm/mysql2' -import { withReplicas } from 'drizzle-orm/mysql-core' -import * as schema from './db/schema.mjs' - -const primary = drizzle({ connection: ${JSON.stringify(connection)}, schema${modeOption}${casingOption} }) - -const replicaUrls = ${JSON.stringify(replicaUrls)} -const replicaConnections = replicaUrls.map(replicaUrl => { - return drizzle({ connection: { uri: replicaUrl }, schema${modeOption}${casingOption} }) -}) -const db = withReplicas(primary, replicaConnections) -export { db, schema } -` - } - } - if (driver === 'neon-http') { - const urlExpr = connection.url ? `'${connection.url}'` : `process.env.POSTGRES_URL || process.env.POSTGRESQL_URL || process.env.DATABASE_URL` - drizzleOrmContent = generateLazyDbTemplate( - `import { neon } from '@neondatabase/serverless'\nimport { drizzle } from 'drizzle-orm/neon-http'`, - ` const url = ${urlExpr} - if (!url) throw new Error('DATABASE_URL, POSTGRES_URL, or POSTGRESQL_URL required') - const sql = neon(url) - _db = drizzle(sql, { schema${casingOption} })` - ) - } - if (driver === 'd1') { - drizzleOrmContent = generateLazyDbTemplate( - `import { drizzle } from 'drizzle-orm/d1'`, - ` const binding = process.env.DB || globalThis.__env__?.DB || globalThis.DB - if (!binding) throw new Error('DB binding not found') - _db = drizzle(binding, { schema${casingOption} })` - ) - } - if (driver === 'd1-http') { - // D1 over HTTP using sqlite-proxy - drizzleOrmContent = `import { drizzle } from 'drizzle-orm/sqlite-proxy' -import * as schema from './db/schema.mjs' - -const accountId = ${JSON.stringify(connection.accountId)} -const databaseId = ${JSON.stringify(connection.databaseId)} -const apiToken = ${JSON.stringify(connection.apiToken)} - -async function d1HttpDriver(sql, params, method) { - if (method === 'values') method = 'all' - - const { errors, success, result } = await $fetch(\`https://api.cloudflare.com/client/v4/accounts/\${accountId}/d1/database/\${databaseId}/raw\`, { - method: 'POST', - headers: { - Authorization: \`Bearer \${apiToken}\`, - 'Content-Type': 'application/json' - }, - async onResponseError({ request, response, options }) { - console.error( - "D1 HTTP Error:", - request, - options.body, - response.status, - response._data, - ) - }, - body: { sql, params } - }) - - if (errors?.length > 0 || !success) { - throw new Error(\`D1 HTTP error: \${JSON.stringify({ errors, success, result })}\`) - } - - const queryResult = result?.[0] - if (!queryResult?.success) { - throw new Error(\`D1 HTTP error: \${JSON.stringify({ errors, success, result })}\`) - } - const rows = queryResult.results?.rows || [] + const databaseTemplate = addTemplate({ + filename: 'hub/db.mjs', + getContents: () => clientCode, + write: true + }) + nuxt.options.alias!['hub:db'] = databaseTemplate.dst + addServerImports({ name: 'db', from: 'hub:db', meta: { description: `The ${orm} ${driver} database client.` } }) - if (method === 'get') { - if (rows.length === 0) { - return { rows: [] } - } - return { rows: rows[0] } + // For Drizzle, also export the schema + if (orm === 'drizzle') { + addServerImports({ name: 'schema', from: 'hub:db', meta: { description: `The database schema object` } }) } - return { rows } -} - -const db = drizzle(d1HttpDriver, { schema${casingOption} }) - -export { db, schema } -` - } - if (['postgres-js', 'mysql2'].includes(driver) && hub.hosting.includes('cloudflare') && connection?.hyperdriveId) { - const bindingName = driver === 'postgres-js' ? 'POSTGRES' : 'MYSQL' - drizzleOrmContent = generateLazyDbTemplate( - `import { drizzle } from 'drizzle-orm/${driver}'`, - ` const hyperdrive = process.env.${bindingName} || globalThis.__env__?.${bindingName} || globalThis.${bindingName} - if (!hyperdrive) throw new Error('${bindingName} binding not found') - _db = drizzle({ connection: hyperdrive.connectionString, schema${modeOption}${casingOption} })` - ) - } - // Non-CF postgres-js: lazy env resolution for Docker/multi-deploy scenarios - if (driver === 'postgres-js' && !nuxt.options.dev && !hub.hosting.includes('cloudflare')) { - const urlExpr = connection.url ? `'${connection.url}'` : `process.env.POSTGRES_URL || process.env.POSTGRESQL_URL || process.env.DATABASE_URL` - const replicaUrls = (replicas || []).filter(Boolean) - const hasReplicas = replicaUrls.length > 0 - - drizzleOrmContent = generateLazyDbTemplate( - `import { drizzle } from 'drizzle-orm/postgres-js' -${hasReplicas ? `import { withReplicas } from 'drizzle-orm/pg-core'\n` : ''}import postgres from 'postgres'`, - ` const url = ${urlExpr} - if (!url) throw new Error('DATABASE_URL, POSTGRES_URL, or POSTGRESQL_URL required') - const client = postgres(url, { onnotice: () => {} }) -${hasReplicas - ? ` const primary = drizzle({ client, schema${casingOption} }) - - const replicaUrls = ${JSON.stringify(replicaUrls)} - const replicaConnections = replicaUrls.map(replicaUrl => { - const replicaClient = postgres(replicaUrl, { onnotice: () => {} }) - return drizzle({ client: replicaClient, schema${casingOption} }) - }) - _db = withReplicas(primary, replicaConnections)` - : ` _db = drizzle({ client, schema${casingOption} })`}` - ) - } - // Non-CF mysql2: lazy env resolution for Docker/multi-deploy scenarios - if (driver === 'mysql2' && !nuxt.options.dev && !hub.hosting.includes('cloudflare')) { - const uriExpr = connection.uri ? `'${connection.uri}'` : `process.env.MYSQL_URL || process.env.DATABASE_URL` - const replicaUrls = (replicas || []).filter(Boolean) - const hasReplicas = replicaUrls.length > 0 - - drizzleOrmContent = generateLazyDbTemplate( - `import { drizzle } from 'drizzle-orm/mysql2'${hasReplicas ? `\nimport { withReplicas } from 'drizzle-orm/mysql-core'` : ''}`, - ` const uri = ${uriExpr} - if (!uri) throw new Error('DATABASE_URL or MYSQL_URL required') -${hasReplicas - ? ` const primary = drizzle({ connection: { uri }, schema${modeOption}${casingOption} }) - - const replicaUrls = ${JSON.stringify(replicaUrls)} - const replicaConnections = replicaUrls.map(replicaUrl => { - return drizzle({ connection: { uri: replicaUrl }, schema${modeOption}${casingOption} }) + // Handle Prisma's prepare:types hook for client generation + if (adapter.onPrepareTypes) { + nuxt.hook('prepare:types', async () => { + await adapter.onPrepareTypes!(ctx) }) - _db = withReplicas(primary, replicaConnections)` - : ` _db = drizzle({ connection: { uri }, schema${modeOption}${casingOption} })`}` - ) - } - // libsql: lazy env resolution for Docker/multi-deploy scenarios (when no URL baked in) - if (driver === 'libsql' && !connection.url) { - drizzleOrmContent = generateLazyDbTemplate( - `import { drizzle } from 'drizzle-orm/libsql'`, - ` const url = process.env.TURSO_DATABASE_URL || process.env.LIBSQL_URL || process.env.DATABASE_URL - const authToken = process.env.TURSO_AUTH_TOKEN || process.env.LIBSQL_AUTH_TOKEN - if (!url) throw new Error('Database URL not found. Set TURSO_DATABASE_URL, LIBSQL_URL, or DATABASE_URL') - _db = drizzle({ connection: { url, authToken }, schema${casingOption} })` - ) - } - - // Write to node_modules/@nuxthub/db/ for direct imports (workflow compatibility) - const physicalDbDir = join(nuxt.options.rootDir, 'node_modules', '@nuxthub', 'db') - await mkdir(physicalDbDir, { recursive: true }) - - // Write db.mjs to node_modules/@nuxthub/db/ - await writeFile( - join(physicalDbDir, 'db.mjs'), - drizzleOrmContent.replace(/from '\.\/db\/schema\.mjs'/g, 'from \'./schema.mjs\'') - ) - - // Write db.d.ts for TypeScript support - const physicalDbTypes = `import type { DrizzleConfig } from 'drizzle-orm' -import { drizzle as drizzleCore } from 'drizzle-orm/${driverForTypes}' -import * as schema from './schema.mjs' - -/** - * The database schema object - * Defined in server/db/schema.ts and server/db/schema/*.ts - */ -export { schema } -/** - * The ${driver} database client. - */ -export const db: ReturnType> -` - - await writeFile( - join(physicalDbDir, 'db.d.ts'), - physicalDbTypes - ) - - // Create package.json and stub schema files for Node.js module resolution - // These are needed during `nuxt prepare` so tsconfig paths resolve correctly - const packageJson = { - name: '@nuxthub/db', - version: '0.0.0', - type: 'module', - exports: { - '.': { types: './db.d.ts', default: './db.mjs' }, - './schema': { types: './schema.d.mts', default: './schema.mjs' } - } - } - try { - await writeFile(join(physicalDbDir, 'package.json'), JSON.stringify(packageJson, null, 2)) - // Stub schema files only if they don't exist (real types written by app:templatesGenerated hook) - const schemaPath = join(physicalDbDir, 'schema.mjs') - const schemaDtsPath = join(physicalDbDir, 'schema.d.mts') - const schemaExists = await stat(schemaPath).then(s => s.size > 20).catch(() => false) - const schemaDtsExists = await stat(schemaDtsPath).then(s => s.size > 20).catch(() => false) - if (!schemaExists) await writeFile(schemaPath, 'export {}') - if (!schemaDtsExists) await writeFile(schemaDtsPath, 'export {}') - } catch (error) { - throw new Error(`Failed to create @nuxthub/db package files: ${(error as Error).message}`) } - - // Create hub:db alias to @nuxthub/db for backwards compatibility - nuxt.options.alias!['hub:db'] = '@nuxthub/db' - - // Add auto-imports for both @nuxthub/db and hub:db - addServerImports({ name: 'db', from: '@nuxthub/db', meta: { description: `The ${driver} database client.` } }) - addServerImports({ name: 'schema', from: '@nuxthub/db', meta: { description: `The database schema object` } }) } -async function setupDatabaseConfig(nuxt: Nuxt, hub: ResolvedHubConfig) { - // generate drizzle.config.ts in .nuxt/hub/db/drizzle.config.ts - const { dialect, casing } = hub.db as ResolvedDatabaseConfig - const casingConfig = casing ? `\n casing: '${casing}',` : '' - addTemplate({ - filename: 'hub/db/drizzle.config.ts', - write: true, - getContents: () => `import { defineConfig } from 'drizzle-kit' +async function setupDatabaseConfig(nuxt: Nuxt, hub: ResolvedHubConfig, _adapter: HubDbAdapter) { + const { orm, dialect, casing } = hub.db as ResolvedDatabaseConfig + + // Only generate drizzle.config.ts for Drizzle ORM + if (orm === 'drizzle') { + const casingConfig = casing ? `\n casing: '${casing}',` : '' + addTemplate({ + filename: 'hub/db/drizzle.config.ts', + write: true, + getContents: () => `import { defineConfig } from 'drizzle-kit' export default defineConfig({ dialect: '${dialect}',${casingConfig} schema: '${relative(nuxt.options.rootDir, resolve(nuxt.options.buildDir, 'hub/db/schema.mjs'))}', out: '${relative(nuxt.options.rootDir, resolve(nuxt.options.rootDir, `server/db/migrations/${dialect}`))}' });` }) + } } diff --git a/src/devtools.ts b/src/devtools.ts index f1cb4772e..7acc136d0 100644 --- a/src/devtools.ts +++ b/src/devtools.ts @@ -6,35 +6,54 @@ import { glob } from 'tinyglobby' let isReady = false let promise: Promise | null = null +// Default port for database studio (Drizzle Studio uses this convention) let port = 4983 const log = logger.withTag('nuxt:hub') -async function launchDrizzleStudio(nuxt: Nuxt, hub: HubConfig) { +async function launchDatabaseStudio(nuxt: Nuxt, hub: HubConfig) { const dbConfig = hub.db as ResolvedDatabaseConfig - if (!dbConfig || typeof dbConfig === 'boolean' || typeof dbConfig === 'string') { + if (!dbConfig) { throw new Error('Database configuration not resolved properly. Please ensure database is configured in hub.db') } port = await getPort({ port: 4983 }) + const { orm, dialect, driver, connection } = dbConfig try { - const { dialect, driver, connection } = dbConfig + // Prisma Studio + if (orm === 'prisma') { + log.info(`Launching Prisma Studio on port ${port}...`) + const { execa } = await import('execa') + // Use execa with array args to avoid shell injection, don't await - studio runs in background + const childProcess = execa('npx', ['prisma', 'studio', '--port', String(port)], { + cwd: nuxt.options.rootDir, + stdio: 'inherit', + reject: false + }) + // Wait briefly for studio to start, then mark as ready + await new Promise(resolve => setTimeout(resolve, 2000)) + if (childProcess.exitCode !== null && childProcess.exitCode !== 0) { + throw new Error(`Prisma Studio failed to start (exit code: ${childProcess.exitCode})`) + } + isReady = true + return + } + + // Drizzle Studio const { schema } = await import(nuxt.options.alias!['hub:db'] as string) - // Launch Drizzle Studio based on dialect and driver if (dialect === 'postgresql') { if (driver === 'pglite') { log.info(`Launching Drizzle Studio with PGlite...`) - - // Trigger studio launch in the Nitro process for PGlite instance const nitroDevUrl = `${nuxt.options.devServer.https ? 'https' : 'http'}://localhost:${nuxt.options.devServer.port || 3000}` - await fetch(`${nitroDevUrl}/api/_hub/db/launch-studio?port=${port}`, { - method: 'POST' - }) + try { + await fetch(`${nitroDevUrl}/api/_hub/db/launch-studio?port=${port}`, { method: 'POST' }) + } catch (fetchError) { + throw new Error(`Failed to launch PGlite studio - is the dev server running? ${fetchError}`) + } } else { const { startStudioPostgresServer } = await import('drizzle-kit/api') - // For postgres-js and other PostgreSQL drivers log.info(`Launching Drizzle Studio with PostgreSQL...`) await startStudioPostgresServer(schema, connection, { port }) } @@ -71,47 +90,53 @@ async function launchDrizzleStudio(nuxt: Nuxt, hub: HubConfig) { isReady = true } catch (error) { - log.error('Failed to launch Drizzle Studio:', error) + log.error('Failed to launch database studio:', error) throw error } } export function addDevToolsCustomTabs(nuxt: Nuxt, hub: HubConfig) { nuxt.hook('devtools:customTabs', (tabs) => { - if (nuxt.options.nitro.experimental?.openAPI)({ - category: 'server', - name: 'hub-open-api', - title: 'OpenAPI', - icon: 'i-lucide-file-text', - view: { - type: 'iframe', - src: `/_scalar` - } - }) + if (nuxt.options.nitro.experimental?.openAPI) { + tabs.push({ + category: 'server', + name: 'hub-open-api', + title: 'OpenAPI', + icon: 'i-lucide-file-text', + view: { + type: 'iframe', + src: `/_scalar` + } + }) + } - if (hub.db) tabs.push({ - category: 'server', - name: 'hub-db', - title: 'Database', - icon: 'i-lucide-database', - view: isReady && port - ? { - type: 'iframe', - src: `https://local.drizzle.studio?port=${port}`, - permissions: ['local-network-access https://local.drizzle.studio'] - } - : { - type: 'launch', - description: 'Launch Drizzle Studio', - actions: [{ - label: promise ? 'Starting...' : 'Launch', - pending: isReady, - handle() { - promise = promise || launchDrizzleStudio(nuxt, hub) - return promise - } - }] - } - }) + if (hub.db) { + const dbConfig = hub.db as ResolvedDatabaseConfig + const orm = dbConfig?.orm || 'drizzle' + const studioName = orm === 'prisma' ? 'Prisma Studio' : 'Drizzle Studio' + const studioUrl = orm === 'prisma' ? `http://localhost:${port}` : `https://local.drizzle.studio?port=${port}` + const permissions = orm === 'prisma' ? [] : ['local-network-access https://local.drizzle.studio'] + + tabs.push({ + category: 'server', + name: 'hub-db', + title: 'Database', + icon: 'i-lucide-database', + view: isReady && port + ? { type: 'iframe', src: studioUrl, permissions } + : { + type: 'launch', + description: `Launch ${studioName}`, + actions: [{ + label: promise ? 'Starting...' : 'Launch', + pending: !!promise && !isReady, + handle() { + promise = promise || launchDatabaseStudio(nuxt, hub) + return promise + } + }] + } + }) + } }) } diff --git a/src/types/config.ts b/src/types/config.ts index 91a9bd57f..4c32d8204 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -3,6 +3,7 @@ import type { FSDriverOptions } from '@nuxthub/core/blob/drivers/fs' import type { S3DriverOptions } from '@nuxthub/core/blob/drivers/s3' import type { VercelDriverOptions } from '@nuxthub/core/blob/drivers/vercel-blob' import type { CloudflareDriverOptions } from '@nuxthub/core/blob/drivers/cloudflare-r2' +import type { Driver, OrmType } from '../db/adapters/interface' export interface HubConfig { blob: boolean | BlobConfig @@ -160,6 +161,11 @@ type DatabaseConnection = { } export type DatabaseConfig = { + /** + * ORM to use for database operations + * @default 'drizzle' + */ + orm?: OrmType /** * Database dialect */ @@ -171,11 +177,17 @@ export type DatabaseConfig = { * PostgreSQL drivers: 'postgres-js', 'pglite', 'neon-http' * MySQL drivers: 'mysql2' */ - driver?: 'better-sqlite3' | 'libsql' | 'bun-sqlite' | 'd1' | 'd1-http' | 'postgres-js' | 'pglite' | 'neon-http' | 'mysql2' + driver?: Driver /** * Database connection configuration */ connection?: DatabaseConnection + /** + * Read replica URLs for horizontal read scaling. + * Uses Drizzle's withReplicas() to route reads to replicas and writes to primary. + * Only supported for 'postgres-js' and 'mysql2' drivers. + */ + replicas?: string[] /** * The directories to scan for database migrations. * @default ['server/db/migrations'] @@ -221,8 +233,9 @@ export type DatabaseConfig = { } export type ResolvedDatabaseConfig = DatabaseConfig & { + orm: OrmType dialect: 'sqlite' | 'postgresql' | 'mysql' - driver: 'better-sqlite3' | 'libsql' | 'bun-sqlite' | 'd1' | 'd1-http' | 'postgres-js' | 'pglite' | 'neon-http' | 'mysql2' + driver: Driver connection: DatabaseConnection migrationsDirs: string[] queriesPaths: string[] diff --git a/test/adapter.test.ts b/test/adapter.test.ts new file mode 100644 index 000000000..c8c890db8 --- /dev/null +++ b/test/adapter.test.ts @@ -0,0 +1,298 @@ +import { describe, expect, it } from 'vitest' +import type { Nuxt } from '@nuxt/schema' +import { getAdapter, getAvailableAdapters, registerAdapter } from '../src/db/adapters/interface' +import type { HubDbAdapterContext, Driver, OrmType } from '../src/db/adapters/interface' +import type { ResolvedHubConfig, ResolvedDatabaseConfig } from '../src/types/config' +import { drizzleAdapter } from '../src/db/adapters/drizzle' +import { prismaAdapter } from '../src/db/adapters/prisma' + +type MockContextOptions = { + driver: Driver + dialect?: 'sqlite' | 'postgresql' | 'mysql' + orm?: OrmType + connection?: Record + casing?: 'snake_case' | 'camelCase' + mode?: 'default' | 'planetscale' + hosting?: string + dev?: boolean + replicas?: string[] +} + +function createMockContext(options: MockContextOptions): HubDbAdapterContext { + return { + nuxt: { options: { dev: options.dev ?? false, rootDir: '/app' } } as Nuxt, + hub: { hosting: options.hosting ?? '', dir: '/tmp' } as ResolvedHubConfig, + dbConfig: { + orm: options.orm ?? 'drizzle', + dialect: options.dialect ?? 'sqlite', + driver: options.driver, + connection: options.connection ?? {}, + casing: options.casing, + mode: options.mode, + replicas: options.replicas, + migrationsDirs: [], + queriesPaths: [], + applyMigrationsDuringBuild: true + } as ResolvedDatabaseConfig + } +} + +describe('Adapter Interface', () => { + describe('getAvailableAdapters', () => { + it('should return drizzle and prisma as available adapters', () => { + const adapters = getAvailableAdapters() + expect(adapters).toContain('drizzle') + expect(adapters).toContain('prisma') + }) + }) + + describe('getAdapter', () => { + it('should return drizzle adapter', async () => { + const adapter = await getAdapter('drizzle') + expect(adapter.name).toBe('drizzle') + }) + + it('should return prisma adapter', async () => { + const adapter = await getAdapter('prisma') + expect(adapter.name).toBe('prisma') + }) + + it('should throw for unknown adapter', async () => { + // @ts-expect-error - testing invalid input + await expect(getAdapter('unknown')).rejects.toThrow('Unknown ORM adapter: unknown') + }) + }) + + describe('registerAdapter', () => { + it('should allow registering custom adapters', () => { + // @ts-expect-error - testing extension point with custom adapter name + registerAdapter('custom', async () => ({ ...drizzleAdapter, name: 'custom' })) + expect(getAvailableAdapters()).toContain('custom') + }) + }) +}) + +describe('Drizzle Adapter', () => { + describe('checkMissingDeps', () => { + it('should return empty array when all deps are installed', () => { + const deps = { 'drizzle-orm': '1.0.0', 'drizzle-kit': '1.0.0', '@libsql/client': '1.0.0' } + const missing = drizzleAdapter.checkMissingDeps(deps, 'libsql') + expect(missing).toEqual([]) + }) + + it('should return missing core drizzle deps', () => { + const missing = drizzleAdapter.checkMissingDeps({}, 'libsql') + expect(missing).toContain('drizzle-orm') + expect(missing).toContain('drizzle-kit') + }) + + it('should return missing postgres driver dep', () => { + const deps = { 'drizzle-orm': '1.0.0', 'drizzle-kit': '1.0.0' } + const missing = drizzleAdapter.checkMissingDeps(deps, 'postgres-js') + expect(missing).toContain('postgres') + }) + + it('should return missing pglite driver dep', () => { + const deps = { 'drizzle-orm': '1.0.0', 'drizzle-kit': '1.0.0' } + const missing = drizzleAdapter.checkMissingDeps(deps, 'pglite') + expect(missing).toContain('@electric-sql/pglite') + }) + + it('should return missing neon-http driver dep', () => { + const deps = { 'drizzle-orm': '1.0.0', 'drizzle-kit': '1.0.0' } + const missing = drizzleAdapter.checkMissingDeps(deps, 'neon-http') + expect(missing).toContain('@neondatabase/serverless') + }) + + it('should return missing mysql2 driver dep', () => { + const deps = { 'drizzle-orm': '1.0.0', 'drizzle-kit': '1.0.0' } + const missing = drizzleAdapter.checkMissingDeps(deps, 'mysql2') + expect(missing).toContain('mysql2') + }) + + it('should return missing libsql driver dep', () => { + const deps = { 'drizzle-orm': '1.0.0', 'drizzle-kit': '1.0.0' } + const missing = drizzleAdapter.checkMissingDeps(deps, 'libsql') + expect(missing).toContain('@libsql/client') + }) + + it('should not require extra deps for d1 driver', () => { + const deps = { 'drizzle-orm': '1.0.0', 'drizzle-kit': '1.0.0' } + const missing = drizzleAdapter.checkMissingDeps(deps, 'd1') + expect(missing).toEqual([]) + }) + }) + + describe('createClientCode', () => { + it('should generate libsql client code', () => { + const ctx = createMockContext({ driver: 'libsql', connection: { url: 'file:test.db' } }) + const code = drizzleAdapter.createClientCode(ctx) + expect(code).toContain('import { drizzle } from \'drizzle-orm/libsql\'') + expect(code).toContain('export { db, schema, executeRaw, getRows }') + }) + + it('should generate d1 client code with lazy binding', () => { + const ctx = createMockContext({ driver: 'd1' }) + const code = drizzleAdapter.createClientCode(ctx) + expect(code).toContain('import { drizzle } from \'drizzle-orm/d1\'') + expect(code).toContain('globalThis.__env__?.DB') + expect(code).toContain('new Proxy') + }) + + it('should generate postgres-js client code', () => { + const ctx = createMockContext({ driver: 'postgres-js', dialect: 'postgresql', connection: { url: 'postgres://localhost' } }) + const code = drizzleAdapter.createClientCode(ctx) + expect(code).toContain('import { drizzle } from \'drizzle-orm/postgres-js\'') + }) + + it('should include casing option when specified', () => { + const ctx = createMockContext({ driver: 'libsql', connection: { url: 'file:test.db' }, casing: 'snake_case' }) + const code = drizzleAdapter.createClientCode(ctx) + expect(code).toContain('casing: \'snake_case\'') + }) + + it('should include mode option for mysql', () => { + const ctx = createMockContext({ driver: 'mysql2', dialect: 'mysql', connection: { uri: 'mysql://localhost' }, mode: 'planetscale' }) + const code = drizzleAdapter.createClientCode(ctx) + expect(code).toContain('mode: \'planetscale\'') + }) + + it('should generate postgres-js with replicas', () => { + const ctx = createMockContext({ + driver: 'postgres-js', + dialect: 'postgresql', + connection: { url: 'postgres://primary' }, + replicas: ['postgres://replica1', 'postgres://replica2'], + dev: true + }) + const code = drizzleAdapter.createClientCode(ctx) + expect(code).toContain('withReplicas') + expect(code).toContain('drizzle-orm/pg-core') + expect(code).toContain('postgres://replica1') + expect(code).toContain('postgres://replica2') + }) + + it('should generate mysql2 with replicas', () => { + const ctx = createMockContext({ + driver: 'mysql2', + dialect: 'mysql', + connection: { uri: 'mysql://primary' }, + replicas: ['mysql://replica1', 'mysql://replica2'], + dev: true + }) + const code = drizzleAdapter.createClientCode(ctx) + expect(code).toContain('withReplicas') + expect(code).toContain('drizzle-orm/mysql-core') + expect(code).toContain('mysql://replica1') + expect(code).toContain('mysql://replica2') + }) + + it('should not add replicas for unsupported drivers', () => { + const ctx = createMockContext({ + driver: 'pglite', + dialect: 'postgresql', + connection: { dataDir: '/tmp/pglite' }, + replicas: ['postgres://replica1'], + dev: true + }) + const code = drizzleAdapter.createClientCode(ctx) + expect(code).not.toContain('withReplicas') + }) + }) + + describe('getClientTypes', () => { + it('should generate proper type definitions', () => { + const ctx = createMockContext({ driver: 'libsql' }) + const types = drizzleAdapter.getClientTypes(ctx) + expect(types).toContain('declare module \'hub:db\'') + expect(types).toContain('export { schema }') + expect(types).toContain('drizzle-orm/libsql') + }) + + it('should use sqlite-proxy for d1-http driver types', () => { + const ctx = createMockContext({ driver: 'd1-http' }) + const types = drizzleAdapter.getClientTypes(ctx) + expect(types).toContain('drizzle-orm/sqlite-proxy') + }) + }) +}) + +describe('Prisma Adapter', () => { + describe('checkMissingDeps', () => { + it('should return empty array when all deps are installed for postgres-js', () => { + const deps = { '@prisma/client': '5.0.0', prisma: '5.0.0' } + const missing = prismaAdapter.checkMissingDeps(deps, 'postgres-js') + expect(missing).toEqual([]) + }) + + it('should return missing core prisma deps', () => { + const missing = prismaAdapter.checkMissingDeps({}, 'postgres-js') + expect(missing).toContain('@prisma/client') + expect(missing).toContain('prisma') + }) + + it('should return missing d1 adapter dep', () => { + const deps = { '@prisma/client': '5.0.0', prisma: '5.0.0' } + const missing = prismaAdapter.checkMissingDeps(deps, 'd1') + expect(missing).toContain('@prisma/adapter-d1') + }) + + it('should return missing pglite adapter dep', () => { + const deps = { '@prisma/client': '5.0.0', prisma: '5.0.0' } + const missing = prismaAdapter.checkMissingDeps(deps, 'pglite') + expect(missing).toContain('@prisma/adapter-pg-lite') + }) + + it('should return missing libsql adapter deps', () => { + const deps = { '@prisma/client': '5.0.0', prisma: '5.0.0' } + const missing = prismaAdapter.checkMissingDeps(deps, 'libsql') + expect(missing).toContain('@prisma/adapter-libsql') + expect(missing).toContain('@libsql/client') + }) + + it('should return empty when all libsql deps installed', () => { + const deps = { '@prisma/client': '5.0.0', prisma: '5.0.0', '@prisma/adapter-libsql': '5.0.0', '@libsql/client': '0.5.0' } + const missing = prismaAdapter.checkMissingDeps(deps, 'libsql') + expect(missing).toEqual([]) + }) + }) + + describe('createClientCode', () => { + it('should generate d1 client code with adapter', () => { + const ctx = createMockContext({ driver: 'd1', orm: 'prisma' }) + const code = prismaAdapter.createClientCode(ctx) + expect(code).toContain('const { PrismaClient } = pkg') + expect(code).toContain('import { PrismaD1 } from \'@prisma/adapter-d1\'') + expect(code).toContain('new Proxy') + }) + + it('should generate pglite client code with adapter', () => { + const ctx = createMockContext({ driver: 'pglite', orm: 'prisma', dialect: 'postgresql', connection: { dataDir: '/tmp/pglite' } }) + const code = prismaAdapter.createClientCode(ctx) + expect(code).toContain('const { PrismaClient } = pkg') + expect(code).toContain('import { PrismaPGlite } from \'@prisma/adapter-pg-lite\'') + }) + + it('should generate default client code for other drivers', () => { + const ctx = createMockContext({ driver: 'postgres-js', orm: 'prisma', dialect: 'postgresql', connection: { url: 'postgres://localhost' } }) + const code = prismaAdapter.createClientCode(ctx) + expect(code).toContain('const { PrismaClient } = pkg') + expect(code).toContain('new PrismaClient()') + }) + }) + + describe('getClientTypes', () => { + it('should generate proper type definitions', () => { + const ctx = createMockContext({ driver: 'd1', orm: 'prisma' }) + const types = prismaAdapter.getClientTypes(ctx) + expect(types).toContain('declare module \'hub:db\'') + expect(types).toContain('export const db: PrismaClient') + }) + }) + + describe('schemaPath', () => { + it('should have correct default schema path', () => { + expect(prismaAdapter.schemaPath).toBe('prisma/schema.prisma') + }) + }) +}) diff --git a/test/database.config.test.ts b/test/database.config.test.ts index 23c064557..292d57cca 100644 --- a/test/database.config.test.ts +++ b/test/database.config.test.ts @@ -492,6 +492,66 @@ describe('resolveDatabaseConfig', () => { }) }) + describe('ORM configuration', () => { + it('should default orm to drizzle', async () => { + const nuxt = createMockNuxt() + const hub = createBaseHubConfig('sqlite') + + const result = await resolveDatabaseConfig(nuxt, hub) + + expect(result).not.toBe(false) + if (result !== false) { + expect(result.orm).toBe('drizzle') + } + }) + + it('should accept orm: drizzle explicitly', async () => { + const nuxt = createMockNuxt() + const hub = createBaseHubConfig({ + dialect: 'sqlite', + orm: 'drizzle' + }) + + const result = await resolveDatabaseConfig(nuxt, hub) + + expect(result).not.toBe(false) + if (result !== false) { + expect(result.orm).toBe('drizzle') + } + }) + + it('should accept orm: prisma', async () => { + const nuxt = createMockNuxt() + const hub = createBaseHubConfig({ + dialect: 'sqlite', + orm: 'prisma' + }) + + const result = await resolveDatabaseConfig(nuxt, hub) + + expect(result).not.toBe(false) + if (result !== false) { + expect(result.orm).toBe('prisma') + } + }) + + it('should set orm for postgresql with pglite', async () => { + const nuxt = createMockNuxt() + const hub = createBaseHubConfig({ + dialect: 'postgresql', + orm: 'prisma' + }) + + const result = await resolveDatabaseConfig(nuxt, hub) + + expect(result).not.toBe(false) + if (result !== false) { + expect(result.orm).toBe('prisma') + expect(result.driver).toBe('pglite') + } + }) + }) + describe('edge cases', () => { it('should handle empty layers', async () => { const nuxt = createMockNuxt([]) diff --git a/test/db-drizzle.e2e.test.ts b/test/db-drizzle.e2e.test.ts new file mode 100644 index 000000000..a8e217d7b --- /dev/null +++ b/test/db-drizzle.e2e.test.ts @@ -0,0 +1,66 @@ +import { fileURLToPath } from 'node:url' +import fs from 'node:fs/promises' +import { describe, it, expect } from 'vitest' +import { setup, $fetch } from '@nuxt/test-utils/e2e' + +const cleanUp = async () => { + await fs.rm(fileURLToPath(new URL('./fixtures/db-drizzle/.data', import.meta.url)), { force: true, recursive: true }) + await fs.rm(fileURLToPath(new URL('./fixtures/db-drizzle/.nuxt', import.meta.url)), { force: true, recursive: true }) +} + +describe('Database E2E - Drizzle', async () => { + await cleanUp() + + await setup({ + rootDir: fileURLToPath(new URL('./fixtures/db-drizzle', import.meta.url)), + dev: true, + setupTimeout: 180000 + }) + + it('should have db enabled with drizzle', async () => { + const manifest = await $fetch('/api/manifest') + expect(manifest.db).toBeTruthy() + }) + + it('should list users (empty)', async () => { + const users = await $fetch('/api/users') + expect(users).toEqual([]) + }) + + it('should create a user', async () => { + const user = await $fetch('/api/users', { + method: 'POST', + body: { name: 'John Doe', email: 'john@example.com' } + }) + expect(user).toMatchObject({ id: 1, name: 'John Doe', email: 'john@example.com' }) + }) + + it('should get user by id', async () => { + const user = await $fetch('/api/users/1') + expect(user).toMatchObject({ id: 1, name: 'John Doe', email: 'john@example.com' }) + }) + + it('should update user', async () => { + const user = await $fetch('/api/users/1', { + method: 'PUT', + body: { name: 'Jane Doe' } + }) + expect(user).toMatchObject({ id: 1, name: 'Jane Doe', email: 'john@example.com' }) + }) + + it('should list users (1 user)', async () => { + const users = await $fetch('/api/users') + expect(users).toHaveLength(1) + expect(users[0]).toMatchObject({ name: 'Jane Doe' }) + }) + + it('should delete user', async () => { + const result = await $fetch('/api/users/1', { method: 'DELETE' }) + expect(result).toEqual({ success: true }) + }) + + it('should return 404 for deleted user', async () => { + const error = await $fetch('/api/users/1').catch(e => e) + expect(error.response?.status).toBe(404) + }) +}) diff --git a/test/db-prisma.e2e.test.ts b/test/db-prisma.e2e.test.ts new file mode 100644 index 000000000..462c5e30a --- /dev/null +++ b/test/db-prisma.e2e.test.ts @@ -0,0 +1,68 @@ +import { fileURLToPath } from 'node:url' +import fs from 'node:fs/promises' +import { describe, it, expect } from 'vitest' +import { setup, $fetch } from '@nuxt/test-utils/e2e' + +const fixtureDir = fileURLToPath(new URL('./fixtures/db-prisma', import.meta.url)) + +const cleanUp = async () => { + await fs.rm(fileURLToPath(new URL('./fixtures/db-prisma/.data', import.meta.url)), { force: true, recursive: true }) + await fs.rm(fileURLToPath(new URL('./fixtures/db-prisma/.nuxt', import.meta.url)), { force: true, recursive: true }) +} + +describe('Database E2E - Prisma', async () => { + await cleanUp() + + await setup({ + rootDir: fixtureDir, + dev: true, + setupTimeout: 120000 + }) + + it('should have db enabled with prisma', async () => { + const manifest = await $fetch('/api/manifest') + expect(manifest.db).toBeTruthy() + }) + + it('should list users (empty)', async () => { + const users = await $fetch('/api/users') + expect(users).toEqual([]) + }) + + it('should create a user', async () => { + const user = await $fetch('/api/users', { + method: 'POST', + body: { name: 'John Doe', email: 'john@example.com' } + }) + expect(user).toMatchObject({ id: 1, name: 'John Doe', email: 'john@example.com' }) + }) + + it('should get user by id', async () => { + const user = await $fetch('/api/users/1') + expect(user).toMatchObject({ id: 1, name: 'John Doe', email: 'john@example.com' }) + }) + + it('should update user', async () => { + const user = await $fetch('/api/users/1', { + method: 'PUT', + body: { name: 'Jane Doe' } + }) + expect(user).toMatchObject({ id: 1, name: 'Jane Doe', email: 'john@example.com' }) + }) + + it('should list users (1 user)', async () => { + const users = await $fetch('/api/users') + expect(users).toHaveLength(1) + expect(users[0]).toMatchObject({ name: 'Jane Doe' }) + }) + + it('should delete user', async () => { + const result = await $fetch('/api/users/1', { method: 'DELETE' }) + expect(result).toEqual({ success: true }) + }) + + it('should return 404 for deleted user', async () => { + const error = await $fetch('/api/users/1').catch(e => e) + expect(error.response?.status).toBe(404) + }) +}) diff --git a/test/fixtures/db-drizzle/nuxt.config.ts b/test/fixtures/db-drizzle/nuxt.config.ts new file mode 100644 index 000000000..d4a248543 --- /dev/null +++ b/test/fixtures/db-drizzle/nuxt.config.ts @@ -0,0 +1,9 @@ +import { defineNuxtConfig } from 'nuxt/config' + +export default defineNuxtConfig({ + extends: ['../basic'], + modules: ['../../../src/module'], + hub: { + db: { orm: 'drizzle', dialect: 'sqlite' } + } +}) diff --git a/test/fixtures/db-drizzle/package.json b/test/fixtures/db-drizzle/package.json new file mode 100644 index 000000000..15860404e --- /dev/null +++ b/test/fixtures/db-drizzle/package.json @@ -0,0 +1 @@ +{ "name": "fixture-db-drizzle", "private": true } diff --git a/test/fixtures/db-drizzle/server/api/users/[id].delete.ts b/test/fixtures/db-drizzle/server/api/users/[id].delete.ts new file mode 100644 index 000000000..f36a1af7e --- /dev/null +++ b/test/fixtures/db-drizzle/server/api/users/[id].delete.ts @@ -0,0 +1,10 @@ +import { eventHandler, getRouterParam, createError } from 'h3' +import { eq } from 'drizzle-orm' +import { db, schema } from 'hub:db' + +export default eventHandler(async (event) => { + const id = Number(getRouterParam(event, 'id')) + const result = await db.delete(schema.users).where(eq(schema.users.id, id)).returning() + if (!result.length) throw createError({ statusCode: 404, message: 'User not found' }) + return { success: true } +}) diff --git a/test/fixtures/db-drizzle/server/api/users/[id].get.ts b/test/fixtures/db-drizzle/server/api/users/[id].get.ts new file mode 100644 index 000000000..47d0d7591 --- /dev/null +++ b/test/fixtures/db-drizzle/server/api/users/[id].get.ts @@ -0,0 +1,10 @@ +import { eventHandler, getRouterParam, createError } from 'h3' +import { eq } from 'drizzle-orm' +import { db, schema } from 'hub:db' + +export default eventHandler(async (event) => { + const id = Number(getRouterParam(event, 'id')) + const result = await db.select().from(schema.users).where(eq(schema.users.id, id)) + if (!result.length) throw createError({ statusCode: 404, message: 'User not found' }) + return result[0] +}) diff --git a/test/fixtures/db-drizzle/server/api/users/[id].put.ts b/test/fixtures/db-drizzle/server/api/users/[id].put.ts new file mode 100644 index 000000000..1f5be0e1b --- /dev/null +++ b/test/fixtures/db-drizzle/server/api/users/[id].put.ts @@ -0,0 +1,11 @@ +import { eventHandler, getRouterParam, readBody, createError } from 'h3' +import { eq } from 'drizzle-orm' +import { db, schema } from 'hub:db' + +export default eventHandler(async (event) => { + const id = Number(getRouterParam(event, 'id')) + const body = await readBody(event) + const result = await db.update(schema.users).set(body).where(eq(schema.users.id, id)).returning() + if (!result.length) throw createError({ statusCode: 404, message: 'User not found' }) + return result[0] +}) diff --git a/test/fixtures/db-drizzle/server/api/users/index.get.ts b/test/fixtures/db-drizzle/server/api/users/index.get.ts new file mode 100644 index 000000000..eeccaaab4 --- /dev/null +++ b/test/fixtures/db-drizzle/server/api/users/index.get.ts @@ -0,0 +1,6 @@ +import { eventHandler } from 'h3' +import { db, schema } from 'hub:db' + +export default eventHandler(async () => { + return db.select().from(schema.users) +}) diff --git a/test/fixtures/db-drizzle/server/api/users/index.post.ts b/test/fixtures/db-drizzle/server/api/users/index.post.ts new file mode 100644 index 000000000..4a19d8df8 --- /dev/null +++ b/test/fixtures/db-drizzle/server/api/users/index.post.ts @@ -0,0 +1,8 @@ +import { eventHandler, readBody } from 'h3' +import { db, schema } from 'hub:db' + +export default eventHandler(async (event) => { + const body = await readBody(event) + const result = await db.insert(schema.users).values(body).returning() + return result[0] +}) diff --git a/test/fixtures/db-drizzle/server/db/migrations/sqlite/0000_create_users.sql b/test/fixtures/db-drizzle/server/db/migrations/sqlite/0000_create_users.sql new file mode 100644 index 000000000..361f4a6a3 --- /dev/null +++ b/test/fixtures/db-drizzle/server/db/migrations/sqlite/0000_create_users.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS `users` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `name` text NOT NULL, + `email` text NOT NULL +); +CREATE UNIQUE INDEX IF NOT EXISTS `users_email_unique` ON `users` (`email`); diff --git a/test/fixtures/db-drizzle/server/db/schema.ts b/test/fixtures/db-drizzle/server/db/schema.ts new file mode 100644 index 000000000..cb2ffedcc --- /dev/null +++ b/test/fixtures/db-drizzle/server/db/schema.ts @@ -0,0 +1,7 @@ +import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core' + +export const users = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull(), + email: text('email').notNull().unique() +}) diff --git a/test/fixtures/db-drizzle/server/tsconfig.json b/test/fixtures/db-drizzle/server/tsconfig.json new file mode 100644 index 000000000..79371fcbe --- /dev/null +++ b/test/fixtures/db-drizzle/server/tsconfig.json @@ -0,0 +1 @@ +{ "extends": "../.nuxt/tsconfig.server.json" } diff --git a/test/fixtures/db-prisma/nuxt.config.ts b/test/fixtures/db-prisma/nuxt.config.ts new file mode 100644 index 000000000..e625b32e2 --- /dev/null +++ b/test/fixtures/db-prisma/nuxt.config.ts @@ -0,0 +1,9 @@ +import { defineNuxtConfig } from 'nuxt/config' + +export default defineNuxtConfig({ + extends: ['../basic'], + modules: ['../../../src/module'], + hub: { + db: { orm: 'prisma', dialect: 'sqlite' } + } +}) diff --git a/test/fixtures/db-prisma/package.json b/test/fixtures/db-prisma/package.json new file mode 100644 index 000000000..69bc5fa6d --- /dev/null +++ b/test/fixtures/db-prisma/package.json @@ -0,0 +1,12 @@ +{ + "name": "fixture-db-prisma", + "private": true, + "dependencies": { + "@prisma/client": "^6.9.0", + "@prisma/adapter-libsql": "^6.9.0", + "@libsql/client": "^0.17.0" + }, + "devDependencies": { + "prisma": "^6.9.0" + } +} diff --git a/test/fixtures/db-prisma/prisma/schema.prisma b/test/fixtures/db-prisma/prisma/schema.prisma new file mode 100644 index 000000000..ddddde11e --- /dev/null +++ b/test/fixtures/db-prisma/prisma/schema.prisma @@ -0,0 +1,15 @@ +generator client { + provider = "prisma-client-js" + previewFeatures = ["driverAdapters"] +} + +datasource db { + provider = "sqlite" + url = "file:../server/.data/hub/db/sqlite.db" +} + +model User { + id Int @id @default(autoincrement()) + name String + email String @unique +} diff --git a/test/fixtures/db-prisma/server/api/users/[id].delete.ts b/test/fixtures/db-prisma/server/api/users/[id].delete.ts new file mode 100644 index 000000000..f3a096552 --- /dev/null +++ b/test/fixtures/db-prisma/server/api/users/[id].delete.ts @@ -0,0 +1,12 @@ +import { eventHandler, getRouterParam, createError } from 'h3' +import { db } from 'hub:db' + +export default eventHandler(async (event) => { + const id = Number(getRouterParam(event, 'id')) + try { + await db.user.delete({ where: { id } }) + return { success: true } + } catch { + throw createError({ statusCode: 404, message: 'User not found' }) + } +}) diff --git a/test/fixtures/db-prisma/server/api/users/[id].get.ts b/test/fixtures/db-prisma/server/api/users/[id].get.ts new file mode 100644 index 000000000..77d914fef --- /dev/null +++ b/test/fixtures/db-prisma/server/api/users/[id].get.ts @@ -0,0 +1,9 @@ +import { eventHandler, getRouterParam, createError } from 'h3' +import { db } from 'hub:db' + +export default eventHandler(async (event) => { + const id = Number(getRouterParam(event, 'id')) + const user = await db.user.findUnique({ where: { id } }) + if (!user) throw createError({ statusCode: 404, message: 'User not found' }) + return user +}) diff --git a/test/fixtures/db-prisma/server/api/users/[id].put.ts b/test/fixtures/db-prisma/server/api/users/[id].put.ts new file mode 100644 index 000000000..a95c50564 --- /dev/null +++ b/test/fixtures/db-prisma/server/api/users/[id].put.ts @@ -0,0 +1,12 @@ +import { eventHandler, getRouterParam, readBody, createError } from 'h3' +import { db } from 'hub:db' + +export default eventHandler(async (event) => { + const id = Number(getRouterParam(event, 'id')) + const body = await readBody(event) + try { + return await db.user.update({ where: { id }, data: body }) + } catch { + throw createError({ statusCode: 404, message: 'User not found' }) + } +}) diff --git a/test/fixtures/db-prisma/server/api/users/index.get.ts b/test/fixtures/db-prisma/server/api/users/index.get.ts new file mode 100644 index 000000000..30e09df70 --- /dev/null +++ b/test/fixtures/db-prisma/server/api/users/index.get.ts @@ -0,0 +1,6 @@ +import { eventHandler } from 'h3' +import { db } from 'hub:db' + +export default eventHandler(async () => { + return db.user.findMany() +}) diff --git a/test/fixtures/db-prisma/server/api/users/index.post.ts b/test/fixtures/db-prisma/server/api/users/index.post.ts new file mode 100644 index 000000000..3a82f35dd --- /dev/null +++ b/test/fixtures/db-prisma/server/api/users/index.post.ts @@ -0,0 +1,7 @@ +import { eventHandler, readBody } from 'h3' +import { db } from 'hub:db' + +export default eventHandler(async (event) => { + const body = await readBody(event) + return db.user.create({ data: body }) +}) diff --git a/test/fixtures/db-prisma/server/db/migrations/sqlite/0000_create_user.sql b/test/fixtures/db-prisma/server/db/migrations/sqlite/0000_create_user.sql new file mode 100644 index 000000000..9bdf05cec --- /dev/null +++ b/test/fixtures/db-prisma/server/db/migrations/sqlite/0000_create_user.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS `User` ( + `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + `name` text NOT NULL, + `email` text NOT NULL +); +CREATE UNIQUE INDEX IF NOT EXISTS `User_email_unique` ON `User` (`email`); diff --git a/test/fixtures/db-prisma/server/tsconfig.json b/test/fixtures/db-prisma/server/tsconfig.json new file mode 100644 index 000000000..79371fcbe --- /dev/null +++ b/test/fixtures/db-prisma/server/tsconfig.json @@ -0,0 +1 @@ +{ "extends": "../.nuxt/tsconfig.server.json" } diff --git a/test/fixtures/wrangler/server/db/schema.ts b/test/fixtures/wrangler/server/db/schema.ts new file mode 100644 index 000000000..05912cadb --- /dev/null +++ b/test/fixtures/wrangler/server/db/schema.ts @@ -0,0 +1,6 @@ +import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core' + +export const users = sqliteTable('users', { + id: integer('id').primaryKey({ autoIncrement: true }), + name: text('name').notNull() +}) diff --git a/test/wrangler.test.ts b/test/wrangler.test.ts index b5c3adfcf..4f3a00b52 100644 --- a/test/wrangler.test.ts +++ b/test/wrangler.test.ts @@ -13,7 +13,7 @@ describe('addWranglerBinding', () => { }) describe('wrangler bindings e2e', async () => { - await setup({ rootDir: fileURLToPath(new URL('./fixtures/wrangler', import.meta.url)), dev: true }) + await setup({ rootDir: fileURLToPath(new URL('./fixtures/wrangler', import.meta.url)), server: false }) it('should auto-generate all wrangler bindings from hub config', () => { const { nuxt } = useTestContext()