diff --git a/apps/server/tests/verifications/_harness.ts b/apps/server/tests/verifications/_harness.ts new file mode 100644 index 000000000..7bb2b266a --- /dev/null +++ b/apps/server/tests/verifications/_harness.ts @@ -0,0 +1,265 @@ +import type { Database } from '../../src/libs/db' + +import { Buffer } from 'node:buffer' + +import { vi } from 'vitest' + +import { buildApp } from '../../src/app' +import { mockDB } from '../../src/libs/mock-db' +import { createAdminFluxGrantsService } from '../../src/services/admin-flux-grants' +import { createBillingService } from '../../src/services/billing/billing-service' +import { createFluxService } from '../../src/services/flux' +import { createUserDeletionService } from '../../src/services/user-deletion' +import { userFluxRedisKey } from '../../src/utils/redis-keys' + +import * as schema from '../../src/schemas' + +// NOTICE: +// drizzle-kit's `pushSchema` (called by `mockDB`) takes ~500ms per invocation. +// Vitest spawns a fresh worker per test file, so a module-level promise scopes +// the cache correctly: schema push runs once per file, every +// `startVerificationContext()` after that reuses the in-memory PGlite and +// only truncates rows. See `docs/ai/context/verification-automation.md` for +// the broader rationale on test boot cost. +let sharedDbPromise: Promise | null = null + +async function getSharedDb(): Promise { + sharedDbPromise ??= mockDB(schema) + return sharedDbPromise +} + +async function resetDataRows(db: Database): Promise { + // Delete in FK-safe order. better-auth's session / account / verification + // tables reference user with `onDelete: cascade`, so deleting `user` last + // implicitly clears them — we still call them out for clarity and so a + // future test that seeds sessions directly does not silently leak rows. + await db.delete(schema.fluxTransaction) + await db.delete(schema.userFlux) + await db.delete(schema.session) + await db.delete(schema.account) + await db.delete(schema.user) +} + +interface SeedUserOptions { + id: string + email?: string + balance: number +} + +interface SessionUser { + id: string + email: string + emailVerified?: boolean + name?: string +} + +export type Harness = Awaited> + +/** + * Boots a Hono app with the same wiring as production for a verification + * scenario. + * + * Use when: + * - You need to assert a full user path (HTTP -> route -> service -> DB / ledger) + * rather than a unit-level code path + * - You want real `createFluxService` + `createBillingService` against a real + * in-memory Postgres (PGlite), with auth / OIDC / WebSocket / OTel stubbed + * + * Expects: + * - No external network. The mock router never opens sockets so + * pre-flight-rejecting cases never reach it; tests that actually need an + * upstream LLM response must stub `fetch` themselves + * + * Returns: + * - A `Harness` value with the mounted app, drizzle handle, and helpers to + * set a session user, seed flux balance, override config keys, and inspect + * the in-memory Redis store + */ +interface HarnessOptions { + /** + * Comma-separated email allowlist baked into `adminGuard`. Must be set at + * boot time — the guard parses this once at route construction, so flipping + * `ctx.env.ADMIN_EMAILS` mid-test has no effect. Tests that need to swap + * admins should boot a fresh context. + */ + adminEmails?: string +} + +export async function startVerificationContext(opts: HarnessOptions = {}) { + const db = await getSharedDb() + await resetDataRows(db) + + let activeSession: { user: any, session: any } | null = null + + const auth: any = { + api: { + getSession: vi.fn(async () => activeSession), + getOAuthServerConfig: vi.fn(async () => ({})), + getOpenIdConfig: vi.fn(async () => ({})), + }, + handler: vi.fn(async () => new Response('not-found', { status: 404 })), + } + + const configStore: Record = { + FLUX_PER_REQUEST: 1, + INITIAL_USER_FLUX: 0, + AUTH_RATE_LIMIT_MAX: 1000, + AUTH_RATE_LIMIT_WINDOW_SEC: 60, + FLUX_PER_1K_CHARS_TTS: 2, + TTS_DEBT_TTL_SECONDS: 86400, + } + const configKV: any = { + get: vi.fn(async (key: string) => configStore[key]), + getOrThrow: vi.fn(async (key: string) => { + if (configStore[key] === undefined) + throw new Error(`Config key "${key}" is not set`) + return configStore[key] + }), + getOptional: vi.fn(async (key: string) => (configStore[key] ?? null)), + set: vi.fn(async (key: string, value: any) => { + configStore[key] = value + }), + } + + const redisStore = new Map() + const redisSubscriber = { + on: vi.fn(), + subscribe: vi.fn(async () => 1), + unsubscribe: vi.fn(async () => 0), + quit: vi.fn(async () => 'OK'), + } + const redis: any = { + get: vi.fn(async (key: string) => redisStore.get(key) ?? null), + getBuffer: vi.fn(async (key: string) => { + const v = redisStore.get(key) + return v ? Buffer.from(v, 'utf8') : null + }), + set: vi.fn(async (key: string, value: any) => { + redisStore.set(key, String(value)) + return 'OK' + }), + del: vi.fn(async (key: string) => (redisStore.delete(key) ? 1 : 0)), + incrby: vi.fn(async (key: string, by: number) => { + const next = (Number.parseInt(redisStore.get(key) ?? '0', 10) || 0) + by + redisStore.set(key, String(next)) + return next + }), + expire: vi.fn(async () => 1), + duplicate: vi.fn(() => redisSubscriber), + publish: vi.fn(async () => 0), + } + + const fluxService = createFluxService(db, redis, configKV) + const billingService = createBillingService(db, redis, configKV) + const adminFluxGrantsService = createAdminFluxGrantsService({ db, billingService }) + + // NOTICE: + // Production wires 5 soft-delete handlers (stripe / flux / providers / + // characters / chats). The harness only wires `flux` so the verification + // for "balance soft-deleted + ledger preserved" can run without dragging + // in stripe SDK, character / chat / provider services. Tests covering the + // other 4 handlers should opt in via a future option flag rather than + // widening the default wiring. + const userDeletionService = createUserDeletionService() + userDeletionService.register({ + name: 'flux', + priority: 20, + softDelete: ({ userId }) => fluxService.deleteAllForUser(userId), + }) + + // NOTICE: + // The Proxy returns a fresh vi.fn() for every property access. Stand-in for + // services this verification doesn't touch (chat, characters, providers, + // stripe, admin-flux-grants, user-deletion, ttsMeter). If a test exercises + // one of these and starts getting `undefined is not a function` errors, + // wire in a real instance instead of widening this stub. + const stub: any = new Proxy({}, { get: () => vi.fn(async () => undefined) }) + + const env: any = { + API_SERVER_URL: 'http://localhost:3000', + ADMIN_EMAILS: opts.adminEmails ?? '', + OTEL_SERVICE_NAME: 'airi-server-test', + ADDITIONAL_TRUSTED_ORIGINS: '', + HOST: '127.0.0.1', + PORT: 0, + } + + const { app } = await buildApp({ + auth, + db, + characterService: stub, + chatService: stub, + providerService: stub, + fluxService, + fluxTransactionService: stub, + stripeService: stub, + billingService, + adminFluxGrantsService, + ttsMeter: stub, + requestLogService: { logRequest: vi.fn(async () => undefined) } as any, + configKV, + redis, + env, + otel: null, + userDeletionService, + llmRouter: { + route: vi.fn(async () => new Response('{}', { status: 200 })), + invalidateConfig: vi.fn(), + } as any, + posthog: null, + }) + + return { + app, + db, + schema, + redisStore, + configStore, + userDeletionService, + fluxService, + setSessionUser(user: SessionUser | null) { + activeSession = user + ? { + user: { + id: user.id, + email: user.email, + name: user.name ?? user.id, + emailVerified: user.emailVerified ?? true, + createdAt: new Date(), + updatedAt: new Date(), + }, + session: { + id: `sess-${user.id}`, + userId: user.id, + token: `tok-${user.id}`, + createdAt: new Date(), + updatedAt: new Date(), + expiresAt: new Date(Date.now() + 3600_000), + ipAddress: null, + userAgent: null, + }, + } + : null + }, + async seedUser(opts: SeedUserOptions) { + await db.insert(schema.user).values({ + id: opts.id, + name: opts.id, + email: opts.email ?? `${opts.id}@example.com`, + emailVerified: true, + }).onConflictDoNothing() + await db.insert(schema.userFlux).values({ + userId: opts.id, + flux: opts.balance, + }).onConflictDoNothing() + // NOTICE: + // Prime the Redis cache so `fluxService.getFlux()` reads the seeded + // balance directly instead of touching the DB-init path (which would + // create an `initial` flux_transaction row and skew ledger assertions). + redisStore.set(userFluxRedisKey(opts.id), String(opts.balance)) + }, + setConfig(kv: Record) { + Object.assign(configStore, kv) + }, + } +} diff --git a/apps/server/tests/verifications/account-deletion.integration.test.ts b/apps/server/tests/verifications/account-deletion.integration.test.ts new file mode 100644 index 000000000..dafc8f14a --- /dev/null +++ b/apps/server/tests/verifications/account-deletion.integration.test.ts @@ -0,0 +1,116 @@ +// Verification: docs/ai/context/verification-automation.md +// Source doc: apps/server/docs/ai-context/verifications/account-deletion.md +// +// Covers one slice of the verification doc — the part that pins down +// "Flux balance soft-deleted, cache invalidated, ledger preserved". +// +// What this test does NOT cover (intentional, out of harness scope): +// - The Better Auth `/api/auth/delete-user/callback` HTTP entry point. The +// prod trigger lives inside better-auth's plugin internals; testing it +// end-to-end would mean mounting the real `createAuth(...)` against +// better-auth's verification-token flow, which the harness does not do. +// We call `userDeletionService.softDeleteAll(...)` directly — the same +// function better-auth's `beforeDelete` hook calls — so the orchestration +// contract is exercised even though the HTTP boundary is skipped. +// - The stripe / providers / characters / chats handlers. The harness wires +// only the `flux` handler (see `_harness.ts`). Verifying the other four +// needs widening the default wiring or a per-test opt-in. + +import type { Harness } from './_harness' + +import { eq } from 'drizzle-orm' +import { afterAll, beforeEach, describe, expect, it } from 'vitest' + +import { userFluxRedisKey } from '../../src/utils/redis-keys' +import { startVerificationContext } from './_harness' + +describe('verification: account-deletion (flux slice)', () => { + let ctx: Harness + + beforeEach(async () => { + ctx = await startVerificationContext() + }) + + afterAll(async () => { + // PGlite is module-cached and lives for the worker's lifetime. + }) + + it('soft-deletes user_flux, invalidates redis cache, leaves flux_transaction ledger intact', async () => { + const userId = 'user-doomed' + + // Seed: balance 500 + one historical debit ledger row. The ledger row is + // the load-bearing assertion — flux_transaction has no `deleted_at` + // column on purpose, and the bare userId (no FK) is the mechanism that + // lets the ledger outlive the user row. See `schemas/flux-transaction.ts` + // NOTICE comment. + await ctx.seedUser({ id: userId, balance: 500 }) + await ctx.db.insert(ctx.schema.fluxTransaction).values({ + userId, + type: 'debit', + amount: 50, + balanceBefore: 550, + balanceAfter: 500, + description: 'prior llm call', + }) + + // Sanity precondition: balance is 500 and ledger has 1 row. + const balanceBefore = await ctx.fluxService.getFlux(userId) + expect(balanceBefore.flux).toBe(500) + expect(ctx.redisStore.get(userFluxRedisKey(userId))).toBe('500') + const ledgerBefore = await ctx.db.query.fluxTransaction.findMany({ + where: eq(ctx.schema.fluxTransaction.userId, userId), + }) + expect(ledgerBefore).toHaveLength(1) + + // Act: same call better-auth makes inside the delete-user callback hook. + await ctx.userDeletionService.softDeleteAll({ userId, reason: 'user-requested' }) + + // Assert 1: user_flux row is stamped with deletedAt (soft-delete). + const rawRow = await ctx.db + .select() + .from(ctx.schema.userFlux) + .where(eq(ctx.schema.userFlux.userId, userId)) + expect(rawRow).toHaveLength(1) + expect(rawRow[0].deletedAt).not.toBeNull() + expect(rawRow[0].flux).toBe(500) // balance value is NOT zeroed; soft-delete only stamps deletedAt + + // Assert 2: redis cache for the user's balance is dropped. + expect(ctx.redisStore.get(userFluxRedisKey(userId))).toBeUndefined() + + // Assert 3: ledger rows persist. The audit trail outlives the user row. + const ledgerAfter = await ctx.db.query.fluxTransaction.findMany({ + where: eq(ctx.schema.fluxTransaction.userId, userId), + }) + expect(ledgerAfter).toHaveLength(1) + expect(ledgerAfter[0].description).toBe('prior llm call') + + // Assert 4: `fluxService.getFlux` rejects after soft-delete. The read + // path filters on `deletedAt IS NULL`, the init-path's + // `onConflictDoNothing` no-ops against the soft-deleted row, and the + // re-read still finds nothing — so the service throws. In production + // this scenario should not arise because better-auth hard-deletes the + // user row after `softDeleteAll`. The throw is the defense-in-depth + // failure mode described in the `fluxService` NOTICE for any request + // that bypasses `sessionMiddleware` with a soft-deleted user. + await expect(ctx.fluxService.getFlux(userId)).rejects.toThrow(/Failed to initialize flux/) + }) + + it('softDeleteAll is idempotent — calling it twice does not throw and leaves state unchanged', async () => { + // The handler uses `WHERE deletedAt IS NULL` so the second call finds 0 + // rows and is a no-op. `redis.del` is also a no-op when the key is + // absent. Pinning this prevents a future refactor that tightens the + // where-clause and accidentally requires the row to be live. + const userId = 'user-doomed-twice' + await ctx.seedUser({ id: userId, balance: 100 }) + + await ctx.userDeletionService.softDeleteAll({ userId, reason: 'user-requested' }) + await ctx.userDeletionService.softDeleteAll({ userId, reason: 'user-requested' }) + + const rawRow = await ctx.db + .select() + .from(ctx.schema.userFlux) + .where(eq(ctx.schema.userFlux.userId, userId)) + expect(rawRow).toHaveLength(1) + expect(rawRow[0].deletedAt).not.toBeNull() + }) +}) diff --git a/apps/server/tests/verifications/admin-flux-grants.integration.test.ts b/apps/server/tests/verifications/admin-flux-grants.integration.test.ts new file mode 100644 index 000000000..44ccf2457 --- /dev/null +++ b/apps/server/tests/verifications/admin-flux-grants.integration.test.ts @@ -0,0 +1,169 @@ +// Verification: docs/ai/context/verification-automation.md +// Source doc: apps/server/docs/ai-context/verifications/admin-flux-grants.md +// +// Covers the three user paths from the verification doc: +// Path 1: admin POST /api/admin/flux-grants → 200 + granted array, ledger row written +// Path 2: ?dryRun=true → preview returned, ledger unchanged +// Path 3: adminGuard rejects (401 no session / 403 not in allowlist / 403 unverified) + +import type { Harness } from './_harness' + +import { eq } from 'drizzle-orm' +import { afterAll, beforeEach, describe, expect, it } from 'vitest' + +import { startVerificationContext } from './_harness' + +const ADMIN_EMAIL = 'admin@example.com' + +describe('verification: admin-flux-grants', () => { + let ctx: Harness + + beforeEach(async () => { + ctx = await startVerificationContext({ adminEmails: ADMIN_EMAIL }) + ctx.setConfig({ INITIAL_USER_FLUX: 0 }) + // Admin user (caller). emailVerified is required by adminGuard. + await ctx.seedUser({ id: 'admin-1', email: ADMIN_EMAIL, balance: 0 }) + }) + + afterAll(async () => { + // PGlite is per-context and per-test — letting it drop out of scope is enough. + }) + + describe('path 1: admin synchronously grants flux', () => { + it('credits 100 flux to each existing recipient and returns the per-email outcome buckets', async () => { + await ctx.seedUser({ id: 'recipient-1', email: 'rec1@example.com', balance: 0 }) + await ctx.seedUser({ id: 'recipient-2', email: 'rec2@example.com', balance: 25 }) + ctx.setSessionUser({ id: 'admin-1', email: ADMIN_EMAIL }) + + const res = await ctx.app.request('/api/admin/flux-grants', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + description: 'integration-test grant', + amount: 100, + emails: ['rec1@example.com', 'rec2@example.com'], + }), + }) + + expect(res.status).toBe(200) + const body = await res.json() as { + summary: { willGrant: number, totalFluxToIssue: number } + result: { + granted: { email: string, userId: string, fluxTransactionId: string, balanceAfter: number }[] + skipped: unknown[] + failed: unknown[] + } + } + + expect(body.summary.willGrant).toBe(2) + expect(body.summary.totalFluxToIssue).toBe(200) + expect(body.result.failed).toEqual([]) + expect(body.result.skipped).toEqual([]) + expect(body.result.granted).toHaveLength(2) + + const granted1 = body.result.granted.find(g => g.email === 'rec1@example.com') + const granted2 = body.result.granted.find(g => g.email === 'rec2@example.com') + expect(granted1?.balanceAfter).toBe(100) + expect(granted2?.balanceAfter).toBe(125) + expect(granted1?.fluxTransactionId).toBeTruthy() + + // Ledger writes per recipient with type='promo' and the operator id in metadata. + const rec1Ledger = await ctx.db.query.fluxTransaction.findMany({ + where: eq(ctx.schema.fluxTransaction.userId, 'recipient-1'), + }) + expect(rec1Ledger).toHaveLength(1) + expect(rec1Ledger[0].type).toBe('promo') + expect(rec1Ledger[0].amount).toBe(100) + expect(rec1Ledger[0].balanceBefore).toBe(0) + expect(rec1Ledger[0].balanceAfter).toBe(100) + expect(rec1Ledger[0].description).toBe('integration-test grant') + const meta = rec1Ledger[0].metadata as { issuedByUserId?: string, description?: string } + expect(meta?.issuedByUserId).toBe('admin-1') + }) + }) + + describe('path 2: dry-run preview', () => { + it('reports willGrant / notFound / duplicateInInput without writing a ledger row', async () => { + await ctx.seedUser({ id: 'recipient-1', email: 'rec1@example.com', balance: 0 }) + ctx.setSessionUser({ id: 'admin-1', email: ADMIN_EMAIL }) + + const res = await ctx.app.request('/api/admin/flux-grants?dryRun=true', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + description: 'smoke', + amount: 100, + emails: [ + 'rec1@example.com', + 'REC1@example.com', // case-variant duplicate + 'ghost@nope.example', // not_found + 'rec1@example.com', // exact duplicate + ], + }), + }) + + expect(res.status).toBe(200) + const body = await res.json() as { + preview: { + totalEmails: number + willGrant: number + willSkip: { notFound: number, userDeleted: number, duplicateInInput: number } + totalFluxToIssue: number + } + } + expect(body.preview.totalEmails).toBe(4) + expect(body.preview.willGrant).toBe(1) + expect(body.preview.willSkip.notFound).toBe(1) + expect(body.preview.willSkip.duplicateInInput).toBe(2) + expect(body.preview.totalFluxToIssue).toBe(100) + + // Ledger must be untouched. + const ledger = await ctx.db.query.fluxTransaction.findMany({ + where: eq(ctx.schema.fluxTransaction.userId, 'recipient-1'), + }) + expect(ledger).toEqual([]) + }) + }) + + describe('path 3: adminGuard rejects unauthorized callers', () => { + it('returns 401 when no session is attached', async () => { + ctx.setSessionUser(null) + + const res = await ctx.app.request('/api/admin/flux-grants', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ description: 'x', amount: 1, emails: ['a@b.com'] }), + }) + + expect(res.status).toBe(401) + }) + + it('returns 403 when the session user is not in ADMIN_EMAILS', async () => { + await ctx.seedUser({ id: 'normie', email: 'normie@example.com', balance: 0 }) + ctx.setSessionUser({ id: 'normie', email: 'normie@example.com', emailVerified: true }) + + const res = await ctx.app.request('/api/admin/flux-grants', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ description: 'x', amount: 1, emails: ['a@b.com'] }), + }) + + expect(res.status).toBe(403) + }) + + it('returns 403 when the admin email is in the allowlist but not yet verified', async () => { + // Same email as ADMIN_EMAIL but emailVerified=false. Guards against a + // fresh signup with an admin's address slipping past before they prove + // ownership. + ctx.setSessionUser({ id: 'admin-1', email: ADMIN_EMAIL, emailVerified: false }) + + const res = await ctx.app.request('/api/admin/flux-grants', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ description: 'x', amount: 1, emails: ['a@b.com'] }), + }) + + expect(res.status).toBe(403) + }) + }) +}) diff --git a/apps/server/tests/verifications/flux-unbilled-exploit.integration.test.ts b/apps/server/tests/verifications/flux-unbilled-exploit.integration.test.ts new file mode 100644 index 000000000..0f3c4132c --- /dev/null +++ b/apps/server/tests/verifications/flux-unbilled-exploit.integration.test.ts @@ -0,0 +1,117 @@ +// Verification: docs/ai/context/verification-automation.md +// Source doc: apps/server/docs/ai-context/verifications/flux-unbilled-exploit-fix.md +// +// Covers the "user path" section of the verification doc: +// Scenario: user with 0 < balance < fallbackRate fires N concurrent LLM +// completion requests. +// Expected (post-patch): all N are rejected at pre-flight with 402; the +// upstream router is never invoked; flux_transaction ledger gains +// no 'debit' row; user_flux.flux stays at the seeded value. + +import type { Harness } from './_harness' + +import { and, eq } from 'drizzle-orm' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' + +import { startVerificationContext } from './_harness' + +describe('verification: flux-unbilled-exploit-fix', () => { + let ctx: Harness + + beforeAll(async () => { + ctx = await startVerificationContext() + }) + + beforeEach(async () => { + // Clean ledger between cases so balanceBefore / balanceAfter assertions + // don't carry state across tests. + await ctx.db.delete(ctx.schema.fluxTransaction) + await ctx.db.delete(ctx.schema.userFlux) + ctx.redisStore.clear() + }) + + afterAll(async () => { + // PGlite is in-memory — letting it fall out of scope is enough. + }) + + it('rejects N concurrent partial-balance requests at pre-flight, never writes a debit ledger row', async () => { + // ROOT CAUSE: + // + // Before commit 7267b0d6b the pre-flight gate read `if (flux.flux <= 0)`, + // so users with `0 < balance < FLUX_PER_REQUEST` could spawn N concurrent + // requests, each pass pre-flight, complete the upstream LLM call, and + // race on a post-billing debit that almost always failed (insufficient + // funds for the requested amount, full-amount rollback). Result: N free + // LLM responses. + // + // After 7267b0d6b: pre-flight rejects when `flux.flux < fallbackRate` + // before the upstream call. This test pins the after-patch behavior so + // a regression that loosens the gate back to `<= 0` will fail here. + + const userId = 'user-partial-balance' + const N = 5 + + ctx.setConfig({ FLUX_PER_REQUEST: 100, FLUX_PER_1K_TOKENS: 50 }) + await ctx.seedUser({ id: userId, balance: 5 }) + ctx.setSessionUser({ id: userId, email: `${userId}@example.com` }) + + const responses = await Promise.all( + Array.from({ length: N }, () => ctx.app.request('/api/v1/openai/chat/completions', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ model: 'auto', messages: [{ role: 'user', content: 'hi' }] }), + })), + ) + + // All N must be rejected before the gateway is touched. + expect(responses).toHaveLength(N) + for (const res of responses) { + expect(res.status).toBe(402) + } + const bodies = await Promise.all(responses.map(r => r.json() as Promise<{ error: string, message: string }>)) + for (const body of bodies) { + expect(body.error).toBe('PAYMENT_REQUIRED') + expect(body.message).toMatch(/Insufficient flux/i) + } + + // Ledger must be untouched. The pre-flight reject path never reaches + // `consumeFluxForLLM`, so no `debit` rows should exist. + const ledger = await ctx.db.query.fluxTransaction.findMany({ + where: eq(ctx.schema.fluxTransaction.userId, userId), + }) + expect(ledger).toEqual([]) + + // Balance must be exactly the seeded value. No drain, no rollback. + const fluxRow = await ctx.db.query.userFlux.findFirst({ + where: and( + eq(ctx.schema.userFlux.userId, userId), + // Active rows only — deletedAt IS NULL is fluxService's read guard + ), + }) + expect(fluxRow?.flux).toBe(5) + }) + + it('allows a request when balance >= fallbackRate (pre-flight pass-through smoke check)', async () => { + // Companion case: with sufficient balance the pre-flight gate must NOT + // block. We don't run the request to completion (no upstream gateway + // available in this harness), only assert that the failure mode here is + // upstream-fetch error (not 402). This protects against a regression + // that flips the comparison and rejects everyone. + const userId = 'user-funded' + + ctx.setConfig({ FLUX_PER_REQUEST: 100, FLUX_PER_1K_TOKENS: 50 }) + await ctx.seedUser({ id: userId, balance: 1000 }) + ctx.setSessionUser({ id: userId, email: `${userId}@example.com` }) + + const res = await ctx.app.request('/api/v1/openai/chat/completions', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ model: 'auto', messages: [{ role: 'user', content: 'hi' }] }), + }) + + // Pre-flight passed -> route delegated to the mock router. The harness + // wires `llmRouter.route` to a vi.fn that returns 200, so we only assert + // the pre-flight gate did NOT short-circuit with 402. + expect(res.status).not.toBe(402) + }) +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ccf9a0789..f16016804 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -619,10 +619,10 @@ importers: dependencies: '@better-auth/drizzle-adapter': specifier: ^1.6.5 - version: 1.6.5(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1))(@better-auth/utils@0.3.0)(drizzle-orm@0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9)) + version: 1.6.5(@better-auth/core@1.6.5(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1))(@better-auth/utils@0.4.0)(drizzle-orm@0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9)) '@better-auth/oauth-provider': specifier: 'catalog:' - version: 1.5.6(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1))(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.5(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(better-sqlite3@12.5.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9))(pg@8.20.0)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3)))(better-call@1.1.8(zod@4.3.6)) + version: 1.5.6(@better-auth/core@1.6.5(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.5(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(better-sqlite3@12.5.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9))(pg@8.20.0)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3)))(better-call@1.3.5(zod@4.3.6)) '@dotenvx/dotenvx': specifier: ^1.61.1 version: 1.61.1 @@ -755,7 +755,7 @@ importers: devDependencies: '@better-auth/cli': specifier: ^1.4.21 - version: 1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(better-call@1.1.8(zod@4.3.6))(drizzle-kit@0.31.10)(jose@6.2.2)(kysely@0.28.14)(magicast@0.5.2)(nanostores@1.1.1)(postgres@3.4.9)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3)) + version: 1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(drizzle-kit@0.31.10)(jose@6.2.2)(kysely@0.28.14)(magicast@0.5.2)(nanostores@1.1.1)(postgres@3.4.9)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3)) '@types/pg': specifier: ^8.20.0 version: 8.20.0 @@ -1465,7 +1465,7 @@ importers: version: 3.0.2(electron@41.2.1) '@electron-toolkit/tsconfig': specifier: ^2.0.0 - version: 2.0.0(@types/node@25.6.0) + version: 2.0.0(@types/node@24.12.2) '@electron-toolkit/utils': specifier: ^4.0.0 version: 4.0.0(electron@41.2.1) @@ -1504,7 +1504,7 @@ importers: version: 3.1.0 '@intlify/unplugin-vue-i18n': specifier: ^11.0.7 - version: 11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) + version: 11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) '@modelcontextprotocol/sdk': specifier: 'catalog:' version: 1.29.0(@cfworker/json-schema@4.1.1)(zod@4.3.6) @@ -1540,10 +1540,10 @@ importers: version: link:../../packages/ui-transitions '@proj-airi/unplugin-fetch': specifier: 'catalog:' - version: 0.2.3(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 0.2.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@proj-airi/unplugin-live2d-sdk': specifier: ^0.1.7 - version: 0.1.7(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 0.1.7(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) '@types/audioworklet': specifier: 'catalog:' version: 0.0.97 @@ -1570,7 +1570,7 @@ importers: version: 2.10.3 '@vitejs/plugin-vue': specifier: ^6.0.6 - version: 6.0.6(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) + version: 6.0.6(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) '@vue-macros/volar': specifier: ^3.1.2 version: 3.1.2(typescript@5.9.3)(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) @@ -1603,7 +1603,7 @@ importers: version: 6.8.3 electron-vite: specifier: ^5.0.0 - version: 5.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 5.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) get-port-please: specifier: 'catalog:' version: 3.2.0 @@ -1624,31 +1624,31 @@ importers: version: 2.2.6 unocss-preset-scrollbar: specifier: ^4.0.0 - version: 4.0.0(unocss@66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))) + version: 4.0.0(unocss@66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))) unplugin-info: specifier: ^1.3.2 - version: 1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) unplugin-yaml: specifier: ^4.1.0 - version: 4.1.0(@nuxt/kit@3.20.2(magicast@0.5.2))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vite: specifier: 'catalog:' - version: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vite-bundle-visualizer: specifier: ^1.2.1 version: 1.2.1(rolldown@1.0.0-rc.16)(rollup@4.60.1) vite-plugin-mkcert: specifier: 'catalog:' - version: 2.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 2.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plugin-vue-devtools: specifier: ^8.1.1 - version: 8.1.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) + version: 8.1.1(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)) vite-plugin-vue-layouts: specifier: ^0.11.0 - version: 0.11.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) + version: 0.11.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) vue-macros: specifier: ^3.1.2 - version: 3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) + version: 3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) vue-tsc: specifier: ^3.2.6 version: 3.2.6(typescript@5.9.3) @@ -19334,13 +19334,13 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@better-auth/cli@1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(better-call@1.1.8(zod@4.3.6))(drizzle-kit@0.31.10)(jose@6.2.2)(kysely@0.28.14)(magicast@0.5.2)(nanostores@1.1.1)(postgres@3.4.9)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3))': + '@better-auth/cli@1.4.21(@better-fetch/fetch@1.1.21)(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(drizzle-kit@0.31.10)(jose@6.2.2)(kysely@0.28.14)(magicast@0.5.2)(nanostores@1.1.1)(postgres@3.4.9)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3))': dependencies: '@babel/core': 7.29.0 '@babel/preset-react': 7.28.5(@babel/core@7.29.0) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1) - '@better-auth/telemetry': 1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1)) + '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1) + '@better-auth/telemetry': 1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1)) '@better-auth/utils': 0.3.0 '@clack/prompts': 0.11.0 '@mrleebo/prisma-ast': 0.13.1 @@ -19417,6 +19417,17 @@ snapshots: nanostores: 1.1.1 zod: 4.3.6 + '@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1)': + dependencies: + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.21 + '@standard-schema/spec': 1.1.0 + better-call: 1.3.5(zod@4.3.6) + jose: 6.2.2 + kysely: 0.28.14 + nanostores: 1.1.1 + zod: 4.3.6 + '@better-auth/core@1.6.5(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1)': dependencies: '@better-auth/utils': 0.4.0 @@ -19430,13 +19441,6 @@ snapshots: nanostores: 1.1.1 zod: 4.3.6 - '@better-auth/drizzle-adapter@1.6.5(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1))(@better-auth/utils@0.3.0)(drizzle-orm@0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9))': - dependencies: - '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1) - '@better-auth/utils': 0.3.0 - optionalDependencies: - drizzle-orm: 0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9) - '@better-auth/drizzle-adapter@1.6.5(@better-auth/core@1.6.5(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1))(@better-auth/utils@0.4.0)(drizzle-orm@0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9))': dependencies: '@better-auth/core': 1.6.5(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1) @@ -19461,13 +19465,13 @@ snapshots: '@better-auth/core': 1.6.5(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1) '@better-auth/utils': 0.4.0 - '@better-auth/oauth-provider@1.5.6(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1))(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.5(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(better-sqlite3@12.5.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9))(pg@8.20.0)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3)))(better-call@1.1.8(zod@4.3.6))': + '@better-auth/oauth-provider@1.5.6(@better-auth/core@1.6.5(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.5(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(better-sqlite3@12.5.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9))(pg@8.20.0)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3)))(better-call@1.3.5(zod@4.3.6))': dependencies: - '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1) - '@better-auth/utils': 0.3.0 + '@better-auth/core': 1.6.5(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1) + '@better-auth/utils': 0.4.0 '@better-fetch/fetch': 1.1.21 better-auth: 1.6.5(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(better-sqlite3@12.5.0)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9))(pg@8.20.0)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3)) - better-call: 1.1.8(zod@4.3.6) + better-call: 1.3.5(zod@4.3.6) jose: 6.2.2 zod: 4.3.6 @@ -19478,9 +19482,9 @@ snapshots: optionalDependencies: '@prisma/client': 5.22.0 - '@better-auth/telemetry@1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1))': + '@better-auth/telemetry@1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1))': dependencies: - '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1) + '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1) '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 @@ -19836,9 +19840,9 @@ snapshots: dependencies: electron: 41.2.1 - '@electron-toolkit/tsconfig@2.0.0(@types/node@25.6.0)': + '@electron-toolkit/tsconfig@2.0.0(@types/node@24.12.2)': dependencies: - '@types/node': 25.6.0 + '@types/node': 24.12.2 '@electron-toolkit/utils@4.0.0(electron@41.2.1)': dependencies: @@ -20732,6 +20736,31 @@ snapshots: - supports-color - typescript + '@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3))': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + '@intlify/bundle-utils': 11.0.7(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3))) + '@intlify/shared': 11.3.2 + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.3.2)(@vue/compiler-dom@3.5.32)(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) + '@rollup/pluginutils': 5.3.0(rollup@4.60.1) + '@typescript-eslint/scope-manager': 8.58.1 + '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) + debug: 4.4.3(supports-color@10.2.2) + fast-glob: 3.3.3 + pathe: 2.0.3 + picocolors: 1.1.1 + unplugin: 2.3.11 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vue: 3.5.32(typescript@5.9.3) + optionalDependencies: + vue-i18n: 11.3.2(vue@3.5.32(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/compiler-dom' + - eslint + - rollup + - supports-color + - typescript + '@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.32)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-i18n@11.3.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) @@ -22713,11 +22742,35 @@ snapshots: transitivePeerDependencies: - magicast + '@proj-airi/unplugin-fetch@0.2.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + ofetch: 1.5.1 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + '@proj-airi/unplugin-fetch@0.2.3(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: ofetch: 1.5.1 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + '@proj-airi/unplugin-live2d-sdk@0.1.7(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)': + dependencies: + ofetch: 1.5.1 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + yauzl: 3.3.0 + transitivePeerDependencies: + - '@types/node' + - '@vitejs/devtools' + - esbuild + - jiti + - less + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + '@proj-airi/unplugin-live2d-sdk@0.1.7(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)': dependencies: ofetch: 1.5.1 @@ -23618,6 +23671,7 @@ snapshots: '@types/node@25.6.0': dependencies: undici-types: 7.19.2 + optional: true '@types/nprogress@0.2.3': {} @@ -24283,26 +24337,18 @@ snapshots: vite: 6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vue: 3.5.32(typescript@5.9.3) + '@vitejs/plugin-vue@6.0.6(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3))': + dependencies: + '@rolldown/pluginutils': 1.0.0-rc.13 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vue: 3.5.32(typescript@5.9.3) + '@vitejs/plugin-vue@6.0.6(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.13 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vue: 3.5.32(typescript@5.9.3) - '@vitest/browser-playwright@4.1.4(bufferutil@4.1.0)(playwright@1.59.1)(utf-8-validate@5.0.10)(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4)': - dependencies: - '@vitest/browser': 4.1.4(bufferutil@4.1.0)(utf-8-validate@5.0.10)(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4) - '@vitest/mocker': 4.1.4(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - playwright: 1.59.1 - tinyrainbow: 3.1.0 - vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - transitivePeerDependencies: - - bufferutil - - msw - - utf-8-validate - - vite - optional: true - '@vitest/browser-playwright@4.1.4(bufferutil@4.1.0)(playwright@1.59.1)(utf-8-validate@5.0.10)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4)': dependencies: '@vitest/browser': 4.1.4(bufferutil@4.1.0)(utf-8-validate@5.0.10)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4) @@ -24330,24 +24376,6 @@ snapshots: - vite optional: true - '@vitest/browser@4.1.4(bufferutil@4.1.0)(utf-8-validate@5.0.10)(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4)': - dependencies: - '@blazediff/core': 1.9.1 - '@vitest/mocker': 4.1.4(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vitest/utils': 4.1.4 - magic-string: 0.30.21 - pngjs: 7.0.0 - sirv: 3.0.2 - tinyrainbow: 3.1.0 - vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - ws: 8.20.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - msw - - utf-8-validate - - vite - optional: true - '@vitest/browser@4.1.4(bufferutil@4.1.0)(utf-8-validate@5.0.10)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4)': dependencies: '@blazediff/core': 1.9.1 @@ -24395,9 +24423,9 @@ snapshots: obug: 2.1.1 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) optionalDependencies: - '@vitest/browser': 4.1.4(bufferutil@4.1.0)(utf-8-validate@5.0.10)(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4) + '@vitest/browser': 4.1.4(bufferutil@4.1.0)(utf-8-validate@5.0.10)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4) '@vitest/eslint-plugin@1.6.15(@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3)(vitest@4.1.4)': dependencies: @@ -24420,14 +24448,6 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.4(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - '@vitest/spy': 4.1.4 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/mocker@4.1.4(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.4 @@ -24625,6 +24645,15 @@ snapshots: transitivePeerDependencies: - vue + '@vue-macros/devtools@3.1.2(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + sirv: 3.0.2 + vue: 3.5.32(typescript@5.9.3) + optionalDependencies: + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + transitivePeerDependencies: + - typescript + '@vue-macros/devtools@3.1.2(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: sirv: 3.0.2 @@ -25537,7 +25566,7 @@ snapshots: better-auth@1.4.21(@prisma/client@5.22.0)(better-sqlite3@12.5.0)(drizzle-kit@0.31.10)(drizzle-orm@0.41.0(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9))(pg@8.20.0)(react@19.2.3)(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3)): dependencies: '@better-auth/core': 1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1) - '@better-auth/telemetry': 1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1)) + '@better-auth/telemetry': 1.4.21(@better-auth/core@1.4.21(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.2)(kysely@0.28.14)(nanostores@1.1.1)) '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 '@noble/ciphers': 2.1.1 @@ -25584,7 +25613,7 @@ snapshots: drizzle-orm: 0.45.2(@electric-sql/pglite@0.4.4)(@opentelemetry/api@1.9.1)(@prisma/client@5.22.0)(@types/pg@8.20.0)(better-sqlite3@12.5.0)(kysely@0.28.14)(pg@8.20.0)(postgres@3.4.9) pg: 8.20.0 react: 19.2.3 - vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vue: 3.5.32(typescript@5.9.3) transitivePeerDependencies: - '@cloudflare/workers-types' @@ -26766,7 +26795,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron-vite@5.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + electron-vite@5.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) @@ -26774,7 +26803,7 @@ snapshots: esbuild: 0.25.12 magic-string: 0.30.21 picocolors: 1.1.1 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -32684,7 +32713,8 @@ snapshots: undici-types@7.16.0: {} - undici-types@7.19.2: {} + undici-types@7.19.2: + optional: true undici@6.24.1: {} @@ -32796,11 +32826,6 @@ snapshots: '@unocss/preset-mini': 66.6.8 unocss: 66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - unocss-preset-scrollbar@4.0.0(unocss@66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))): - dependencies: - '@unocss/preset-mini': 66.6.8 - unocss: 66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - unocss@66.6.8(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@unocss/cli': 66.6.8 @@ -32897,6 +32922,14 @@ snapshots: unplugin: 2.3.11 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + unplugin-combine@2.3.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(unplugin@2.3.11)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + optionalDependencies: + esbuild: 0.27.2 + rolldown: 1.0.0-rc.16 + rollup: 4.60.1 + unplugin: 2.3.11 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + unplugin-combine@2.3.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(unplugin@2.3.11)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): optionalDependencies: esbuild: 0.27.2 @@ -32931,6 +32964,19 @@ snapshots: transitivePeerDependencies: - supports-color + unplugin-info@1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + ci-info: 4.4.0 + git-url-parse: 16.1.0 + simple-git: 3.36.0 + unplugin: 2.3.11 + optionalDependencies: + esbuild: 0.27.2 + rollup: 4.60.1 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + transitivePeerDependencies: + - supports-color + unplugin-info@1.3.2(esbuild@0.27.2)(rollup@4.60.1)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: ci-info: 4.4.0 @@ -33040,6 +33086,17 @@ snapshots: rollup: 4.60.1 vite: 6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + unplugin-yaml@4.1.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.60.1) + unplugin: 3.0.0 + yaml: 2.8.3 + optionalDependencies: + esbuild: 0.27.2 + rolldown: 1.0.0-rc.16 + rollup: 4.60.1 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 @@ -33271,12 +33328,22 @@ snapshots: - rollup - supports-color + vite-dev-rpc@1.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + birpc: 2.9.0 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite-hot-client: 2.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + vite-dev-rpc@1.1.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: birpc: 2.9.0 vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vite-hot-client: 2.1.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + vite-hot-client@2.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite-hot-client@2.1.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) @@ -33322,6 +33389,21 @@ snapshots: - tsx - yaml + vite-plugin-inspect@11.3.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + ansis: 4.2.0 + debug: 4.4.3(supports-color@10.2.2) + error-stack-parser-es: 1.0.5 + ohash: 2.0.11 + open: 10.2.0 + perfect-debounce: 2.1.0 + sirv: 3.0.2 + unplugin-utils: 0.3.1 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite-dev-rpc: 1.1.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + transitivePeerDependencies: + - supports-color + vite-plugin-inspect@11.3.3(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: ansis: 4.2.0 @@ -33353,6 +33435,13 @@ snapshots: - typescript - ws + vite-plugin-mkcert@2.0.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + debug: 4.4.3(supports-color@10.2.2) + supports-color: 10.2.2 + undici: 8.1.0 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite-plugin-mkcert@2.0.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -33371,6 +33460,20 @@ snapshots: transitivePeerDependencies: - supports-color + vite-plugin-vue-devtools@8.1.1(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)): + dependencies: + '@vue/devtools-core': 8.1.1(vue@3.5.32(typescript@5.9.3)) + '@vue/devtools-kit': 8.1.1 + '@vue/devtools-shared': 8.1.1 + sirv: 3.0.2 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite-plugin-inspect: 11.3.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + vite-plugin-vue-inspector: 5.3.2(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + transitivePeerDependencies: + - '@nuxt/kit' + - supports-color + - vue + vite-plugin-vue-devtools@8.1.1(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue@3.5.32(typescript@5.9.3)): dependencies: '@vue/devtools-core': 8.1.1(vue@3.5.32(typescript@5.9.3)) @@ -33385,6 +33488,21 @@ snapshots: - supports-color - vue + vite-plugin-vue-inspector@5.3.2(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.29.0) + '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.29.0) + '@vue/compiler-dom': 3.5.32 + kolorist: 1.8.0 + magic-string: 0.30.21 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + transitivePeerDependencies: + - supports-color + vite-plugin-vue-inspector@5.3.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@babel/core': 7.29.0 @@ -33400,6 +33518,16 @@ snapshots: transitivePeerDependencies: - supports-color + vite-plugin-vue-layouts@0.11.0(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)): + dependencies: + debug: 4.4.3(supports-color@10.2.2) + fast-glob: 3.3.3 + vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vue: 3.5.32(typescript@5.9.3) + vue-router: 5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) + transitivePeerDependencies: + - supports-color + vite-plugin-vue-layouts@0.11.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-router@5.0.4(@pinia/colada@1.2.1(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)): dependencies: debug: 4.4.3(supports-color@10.2.2) @@ -33520,7 +33648,7 @@ snapshots: vitest-browser-vue@2.1.0(vitest@4.1.4)(vue@3.5.32(typescript@5.9.3)): dependencies: '@vue/test-utils': 2.4.6 - vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + vitest: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vue: 3.5.32(typescript@5.9.3) vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@24.12.2)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): @@ -33554,37 +33682,6 @@ snapshots: transitivePeerDependencies: - msw - vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - '@vitest/expect': 4.1.4 - '@vitest/mocker': 4.1.4(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vitest/pretty-format': 4.1.4 - '@vitest/runner': 4.1.4 - '@vitest/snapshot': 4.1.4 - '@vitest/spy': 4.1.4 - '@vitest/utils': 4.1.4 - es-module-lexer: 2.0.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 4.1.0 - tinybench: 2.9.0 - tinyexec: 1.1.1 - tinyglobby: 0.2.16 - tinyrainbow: 3.1.0 - vite: 6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - why-is-node-running: 2.3.0 - optionalDependencies: - '@opentelemetry/api': 1.9.1 - '@types/node': 25.6.0 - '@vitest/browser-playwright': 4.1.4(bufferutil@4.1.0)(playwright@1.59.1)(utf-8-validate@5.0.10)(vite@6.4.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.4) - '@vitest/coverage-v8': 4.1.4(@vitest/browser@4.1.4)(vitest@4.1.4) - jsdom: 29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3) - transitivePeerDependencies: - - msw - vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.4)(@vitest/coverage-v8@4.1.4)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.2.3))(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.4 @@ -33697,6 +33794,54 @@ snapshots: - vue-tsc - webpack + vue-macros@3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)): + dependencies: + '@vue-macros/better-define': 3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/boolean-prop': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/chain-call': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/common': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/config': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/define-emit': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/define-models': 3.1.2(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/define-prop': 3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/define-props': 3.1.2(@vue-macros/reactivity-transform@3.1.2(vue@3.5.32(typescript@5.9.3)))(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/define-props-refs': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/define-render': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/define-slots': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/define-stylex': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/devtools': 3.1.2(typescript@5.9.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vue-macros/export-expose': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/export-props': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/export-render': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/hoist-static': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/jsx-directive': 3.1.2(typescript@5.9.3) + '@vue-macros/named-template': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/reactivity-transform': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/script-lang': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/setup-block': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/setup-component': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/setup-sfc': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/short-bind': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/short-emits': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/short-vmodel': 3.1.2(vue@3.5.32(typescript@5.9.3)) + '@vue-macros/volar': 3.1.2(typescript@5.9.3)(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)) + unplugin: 2.3.11 + unplugin-combine: 2.3.0(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(unplugin@2.3.11)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + unplugin-vue-define-options: 3.1.2(vue@3.5.32(typescript@5.9.3)) + vue: 3.5.32(typescript@5.9.3) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + - '@rspack/core' + - '@vueuse/core' + - esbuild + - rolldown + - rollup + - typescript + - vite + - vue-tsc + - webpack + vue-macros@3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@vueuse/core@14.2.1(vue@3.5.32(typescript@5.9.3)))(esbuild@0.27.2)(rolldown@1.0.0-rc.16)(rollup@4.60.1)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(less@4.6.4)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(vue-tsc@3.2.6(typescript@5.9.3))(vue@3.5.32(typescript@5.9.3)): dependencies: '@vue-macros/better-define': 3.1.2(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(vue@3.5.32(typescript@5.9.3))