diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c31456d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +**/node_modules +**/dist +**/.astro +.git +.github +**/.env +**/.env.* +!**/.env.example +**/.data +landing +docs +*.png +.playwright-mcp +**/*.log diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 771b780..f4f11b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,7 +131,7 @@ jobs: - name: Push schema + seed demo data run: | - pnpm --filter @kinora/server db:push + pnpm --filter @kinora/server migrate latest pnpm --filter @kinora/server db:seed - name: E2E (boots server + web, runs viewer + web suites) diff --git a/README.md b/README.md index 18b6dcf..3c745ab 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ pnpm install cd packages/server cp .env.example .env docker compose up -d # Postgres on :5436 -pnpm db:push # create tables +pnpm migrate lastest # create tables pnpm db:seed # seed a demo account + data, prints login + an API token pnpm dev # server on :3000 diff --git a/packages/server/Dockerfile b/packages/server/Dockerfile new file mode 100644 index 0000000..3a16cc3 --- /dev/null +++ b/packages/server/Dockerfile @@ -0,0 +1,26 @@ +# Build from the REPO ROOT (needs the pnpm workspace + @kinora/core): +# docker build -f packages/server/Dockerfile -t kinora-server . +FROM node:24-alpine AS base +RUN npm i -g corepack@latest && corepack enable +WORKDIR /repo + +FROM base AS builder +COPY . . +# Install only the server + its workspace deps (@kinora/core). +RUN pnpm install --frozen-lockfile --filter @kinora/server... +# tsdown bundles @kinora/core into dist, so the prod image needs no workspace lib. +RUN pnpm --filter @kinora/server build +# Self-contained package + prod node_modules -> /prod. +RUN pnpm deploy --filter=@kinora/server --prod /prod + +FROM base AS runner +WORKDIR /app +ENV NODE_ENV=production +ENV PORT=3000 +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 kinora +COPY --from=builder --chown=kinora:nodejs /prod /app +USER kinora +EXPOSE 3000 + +CMD ["node", "dist/src/index.mjs"] diff --git a/packages/server/drizzle.config.ts b/packages/server/drizzle.config.ts deleted file mode 100644 index 9c357e4..0000000 --- a/packages/server/drizzle.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from 'drizzle-kit' -import { env } from './src/lib/env' -import 'dotenv/config' - -const pgUrl = `postgres://${env.POSTGRES_USER}:${env.POSTGRES_PASSWORD}@${env.POSTGRES_HOST}:${env.POSTGRES_PORT}/${env.POSTGRES_DB}` - -export default defineConfig({ - out: './drizzle', - schema: './src/db/schemas/index.ts', - dialect: 'postgresql', - dbCredentials: { url: pgUrl }, -}) diff --git a/packages/server/drizzle.test.config.ts b/packages/server/drizzle.test.config.ts deleted file mode 100644 index c20e9a1..0000000 --- a/packages/server/drizzle.test.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -import process from 'node:process' -import { defineConfig } from 'drizzle-kit' - -// Schema push for the integration test DB. Reads only POSTGRES_* from the env that -// global-setup passes in (not the strict app env), always targeting kinora_test. -const url = `postgres://${process.env.POSTGRES_USER}:${process.env.POSTGRES_PASSWORD}@${process.env.POSTGRES_HOST}:${process.env.POSTGRES_PORT}/kinora_test` - -export default defineConfig({ - out: './drizzle', - schema: './src/db/schemas/index.ts', - dialect: 'postgresql', - dbCredentials: { url }, -}) diff --git a/packages/server/migrations/20260609231021_initial_schema.ts b/packages/server/migrations/20260609231021_initial_schema.ts new file mode 100644 index 0000000..5376764 --- /dev/null +++ b/packages/server/migrations/20260609231021_initial_schema.ts @@ -0,0 +1,173 @@ +import type { Knex } from 'knex' + +export async function up(knex: Knex): Promise { + await knex.schema + .createTable('user', (t) => { + t.text('id').primary() + t.text('name').notNullable() + t.text('email').notNullable() + t.boolean('email_verified').notNullable().defaultTo(false) + t.text('image') + t.timestamp('created_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.timestamp('updated_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.unique(['email'], { indexName: 'user_email_unique' }) + }) + .createTable('verification', (t) => { + t.text('id').primary() + t.text('identifier').notNullable() + t.text('value').notNullable() + t.timestamp('expires_at', { useTz: false }).notNullable() + t.timestamp('created_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.timestamp('updated_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.index(['identifier'], 'verification_identifier_idx') + }) + .createTable('apikey', (t) => { + t.text('id').primary() + t.text('config_id').notNullable().defaultTo('default') + t.text('name') + t.text('start') + t.text('prefix') + t.text('key').notNullable() + t.text('reference_id').notNullable() + t.integer('refill_interval') + t.integer('refill_amount') + t.timestamp('last_refill_at', { useTz: false }) + t.boolean('enabled').defaultTo(true) + t.boolean('rate_limit_enabled').defaultTo(true) + t.integer('rate_limit_time_window').defaultTo(86400000) + t.integer('rate_limit_max').defaultTo(10) + t.integer('request_count').defaultTo(0) + t.integer('remaining') + t.timestamp('last_request', { useTz: false }) + t.timestamp('expires_at', { useTz: false }) + t.timestamp('created_at', { useTz: false }).notNullable() + t.timestamp('updated_at', { useTz: false }).notNullable() + t.text('permissions') + t.text('metadata') + t.index(['config_id'], 'apikey_configId_idx') + t.index(['reference_id'], 'apikey_referenceId_idx') + t.index(['key'], 'apikey_key_idx') + }) + .createTable('account', (t) => { + t.text('id').primary() + t.text('account_id').notNullable() + t.text('provider_id').notNullable() + t.text('user_id').notNullable().references('id').inTable('user').onDelete('CASCADE') + t.text('access_token') + t.text('refresh_token') + t.text('id_token') + t.timestamp('access_token_expires_at', { useTz: false }) + t.timestamp('refresh_token_expires_at', { useTz: false }) + t.text('scope') + t.text('password') + t.timestamp('created_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.timestamp('updated_at', { useTz: false }).notNullable() + t.index(['user_id'], 'account_userId_idx') + }) + .createTable('session', (t) => { + t.text('id').primary() + t.timestamp('expires_at', { useTz: false }).notNullable() + t.text('token').notNullable() + t.timestamp('created_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.timestamp('updated_at', { useTz: false }).notNullable() + t.text('ip_address') + t.text('user_agent') + t.text('user_id').notNullable().references('id').inTable('user').onDelete('CASCADE') + t.unique(['token'], { indexName: 'session_token_unique' }) + t.index(['user_id'], 'session_userId_idx') + }) + .createTable('project', (t) => { + t.text('id').primary() + t.text('user_id').notNullable().references('id').inTable('user').onDelete('CASCADE') + t.text('slug').notNullable() + t.text('name').notNullable() + t.text('description') + t.timestamp('created_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.timestamp('updated_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.unique(['user_id', 'slug'], { indexName: 'project_user_slug_uniq' }) + t.index(['user_id'], 'project_userId_idx') + }) + .createTable('run', (t) => { + t.text('id').primary() + t.text('project_id').notNullable().references('id').inTable('project').onDelete('CASCADE') + t.timestamp('started_at', { useTz: false }).notNullable() + t.integer('duration').notNullable() + t.jsonb('counts').notNullable() + t.jsonb('counts_by_tag').notNullable().defaultTo(knex.raw(`'{}'::jsonb`)) + t.text('playwright_version') + t.jsonb('git') + t.jsonb('ci') + t.integer('shards') + t.timestamp('created_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.index(['project_id'], 'run_projectId_idx') + }) + .createTable('test', (t) => { + t.text('id').primary() + t.text('run_id').notNullable().references('id').inTable('run').onDelete('CASCADE') + t.text('project_id').notNullable().references('id').inTable('project').onDelete('CASCADE') + t.text('test_key').notNullable() + t.text('title').notNullable() + t.jsonb('title_path').notNullable() + t.text('file').notNullable() + t.integer('line').notNullable() + t.integer('column').notNullable() + t.text('project_name').notNullable() + t.text('status').notNullable() + t.boolean('ok').notNullable() + t.integer('duration').notNullable() + t.integer('retries').notNullable() + t.jsonb('tags').notNullable() + t.jsonb('annotations').notNullable() + t.jsonb('errors').notNullable() + t.jsonb('attachments').notNullable() + t.timestamp('created_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.index(['run_id'], 'test_runId_idx') + t.index(['project_id', 'test_key'], 'test_project_key_idx') + }) + .createTable('artifact', (t) => { + t.text('id').primary() + t.text('project_id').notNullable().references('id').inTable('project').onDelete('CASCADE') + t.text('run_id').notNullable().references('id').inTable('run').onDelete('CASCADE') + t.text('test_id').references('id').inTable('test').onDelete('CASCADE') + t.text('name').notNullable() + t.text('content_type').notNullable() + t.text('storage_key').notNullable() + t.text('sha1') + t.integer('size') + t.timestamp('created_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.index(['run_id'], 'artifact_runId_idx') + }) + .createTable('subscription', (t) => { + t.text('user_id').primary().references('id').inTable('user').onDelete('CASCADE') + t.text('polar_customer_id').notNullable() + t.text('tier').notNullable().defaultTo('free') + t.text('status') + t.text('product_id') + t.timestamp('current_period_end', { useTz: false }) + t.boolean('cancel_at_period_end').notNullable().defaultTo(false) + t.timestamp('updated_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + }) + .createTable('slack_integration', (t) => { + t.text('project_id').primary().references('id').inTable('project').onDelete('CASCADE') + t.text('webhook_url').notNullable() + t.text('policy').notNullable().defaultTo('on-failure') + t.boolean('enabled').notNullable().defaultTo(true) + t.timestamp('created_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + t.timestamp('updated_at', { useTz: false }).notNullable().defaultTo(knex.fn.now()) + }) +} + +export async function down(knex: Knex): Promise { + await knex.schema + .dropTableIfExists('slack_integration') + .dropTableIfExists('subscription') + .dropTableIfExists('artifact') + .dropTableIfExists('test') + .dropTableIfExists('run') + .dropTableIfExists('project') + .dropTableIfExists('session') + .dropTableIfExists('account') + .dropTableIfExists('apikey') + .dropTableIfExists('verification') + .dropTableIfExists('user') +} diff --git a/packages/server/package.json b/packages/server/package.json index 443ebbd..cfd65c0 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -18,11 +18,9 @@ "build": "tsdown", "typecheck": "tsc --noEmit", "test:integration": "vitest run", - "db:generate": "drizzle-kit generate", - "db:migrate": "drizzle-kit migrate", - "db:push": "drizzle-kit push", "db:seed": "tsx scripts/seed.ts", "db:seed:market": "tsx scripts/seed-market.ts", + "migrate": "tsx scripts/migrate.ts", "purge-expired-runs": "tsx scripts/purge-expired-runs.ts" }, "dependencies": { @@ -38,6 +36,7 @@ "dotenv": "^17.3.1", "drizzle-orm": "^0.45.2", "hono": "^4.12.23", + "knex": "^3.2.10", "pg": "^8.20.0", "pino": "^10.3.1", "pino-pretty": "^13.1.3", @@ -46,7 +45,6 @@ "devDependencies": { "@types/node": "^24.12.3", "@types/pg": "^8.20.0", - "drizzle-kit": "^0.31.10", "tsdown": "^0.22.2", "tsx": "^4.22.4", "typescript": "~6.0.2", diff --git a/packages/server/scripts/migrate.ts b/packages/server/scripts/migrate.ts new file mode 100644 index 0000000..6c39936 --- /dev/null +++ b/packages/server/scripts/migrate.ts @@ -0,0 +1,186 @@ +import type { Knex } from 'knex' +import { resolve } from 'node:path' +import process from 'node:process' +import knex from 'knex' +import { pino, stdSerializers } from 'pino' +import { env } from '../src/lib/env.js' + +const logger = pino({ + level: 'info', + serializers: { + err: stdSerializers.err, + }, +}) + +const migrationsDirectory = resolve(import.meta.dirname, '../migrations') + +const isDev = env.NODE_ENV === 'development' +// .mjs: the build (tsdown) emits ESM migrations as .mjs in dist. +const loadExtensions = ['.js', '.mjs'] + +if (isDev) { + loadExtensions.push('.ts') +} + +const config: Knex.Config = { + client: 'pg', + connection: { + password: env.POSTGRES_PASSWORD, + host: env.POSTGRES_HOST, + port: env.POSTGRES_PORT, + user: env.POSTGRES_USER, + database: env.POSTGRES_DB, + charset: 'utf8mb4', + }, + migrations: { + directory: migrationsDirectory, + loadExtensions, + }, +} + +const migratorConfig = { + extension: 'ts', + disableMigrationsListValidation: true, +} + +const knexWithConfig = knex(config) + +async function make(name: string) { + try { + const fileName = await knexWithConfig.migrate.make(name, migratorConfig) + + logger.info(`Migration file created at ${fileName}!`) + } + catch (err) { + logger.error(err, `Unable to create migration file named ${name}`) + + throw err + } +} + +async function latest(): Promise { + const totalStart = new Date() + + try { + await knexWithConfig.migrate.latest(migratorConfig) + + logger.info('Migration to latest succeeded!') + } + catch (err) { + logger.error( + 'You might need to read http://knexjs.org/#Notes-about-locks You can unlock the knex_migrations table with pnpm migrate unlock', + ) + logger.error( + { + type: 'error', + err, + }, + 'Migration process failed', + ) + + throw err + } + finally { + const totalEnd = new Date() + + logger.info( + { + type: 'run', + start: totalStart.toISOString(), + end: totalEnd.toISOString(), + duration: totalEnd.valueOf() - totalStart.valueOf(), + }, + 'Migration process finished', + ) + } +} + +async function unlock() { + try { + await knexWithConfig.migrate.forceFreeMigrationsLock(migratorConfig) + + logger.info('Unlock succeed!') + } + catch (error) { + logger.error('You might need to read http://knexjs.org/#Notes-about-locks') + + throw error + } +} + +async function rollback() { + try { + await knexWithConfig.migrate.rollback(migratorConfig) + + logger.info('Rollback succeed!') + } + catch (err) { + logger.error(err, 'Rollback failed') + + throw err + } +} + +async function currentVersion() { + try { + const version = await knexWithConfig.migrate.currentVersion(migratorConfig) + + logger.info(`Current version is ${version}`) + } + catch (err) { + logger.error(err, 'Unable to get current version') + + throw err + } +} + +function printHelp(): Promise { + return new Promise((resolve) => { + console.log('make\t\t-\tCreate a migration file') + console.log('rollback\t-\tRollback to previous batch of migrations') + console.log('version\t\t-\tShow current version') + console.log('latest\t\t-\tUpdate database to the latest migration') + console.log('unlock\t\t-\tUnlock the knex_migrations table') + console.log('help\t\t-\tShow this help\n') + + resolve() + }) +} + +async function go(args: string[]) { + switch (args[0]) { + case 'make': { + if (!args[1]) { + throw new Error('Please provide a name for the migration, e.g., pnpm migrate make add_users_table') + } + + return make(args[1]) + } + case 'rollback': { + return rollback() + } + case 'version': { + return currentVersion() + } + case 'latest': { + return latest() + } + case 'unlock': { + return unlock() + } + default: { + return printHelp() + } + } +} + +go(process.argv.slice(2)) + .then(() => { + if (knexWithConfig) { + return knexWithConfig.destroy() + } + }) + .catch((err) => { + logger.error(err, `Error: ${err}`) + process.exit(1) + }) diff --git a/packages/server/test/global-setup.ts b/packages/server/test/global-setup.ts index ca1e380..588d484 100644 --- a/packages/server/test/global-setup.ts +++ b/packages/server/test/global-setup.ts @@ -7,8 +7,9 @@ import { TEST_ENV } from './test-env' const serverDir = resolve(dirname(fileURLToPath(import.meta.url)), '..') -// Create the dedicated test database (separate from the dev `kinora` DB) and push -// the Drizzle schema into it once, before any test runs. +// Recreate the dedicated test DB and run the knex migrations +// into it once, before any test runs. A fresh DB each run also +// validates the migrations against the same schema tests exercise. export default async function setup(): Promise { const admin = new Client({ user: TEST_ENV.POSTGRES_USER, @@ -18,13 +19,11 @@ export default async function setup(): Promise { database: 'postgres', }) await admin.connect() - const { rowCount } = await admin.query('SELECT 1 FROM pg_database WHERE datname = $1', [TEST_ENV.POSTGRES_DB]) - if (!rowCount) - await admin.query(`CREATE DATABASE ${TEST_ENV.POSTGRES_DB}`) + await admin.query(`DROP DATABASE IF EXISTS ${TEST_ENV.POSTGRES_DB} WITH (FORCE)`) + await admin.query(`CREATE DATABASE ${TEST_ENV.POSTGRES_DB}`) await admin.end() - // Dedicated config targets kinora_test and skips the strict app env (env.ts). - execSync('pnpm exec drizzle-kit push --force --config drizzle.test.config.ts', { + execSync('pnpm migrate latest', { cwd: serverDir, stdio: 'inherit', env: { ...process.env, ...TEST_ENV }, diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index a1e327b..d41d1f1 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -4,5 +4,5 @@ "lib": ["ES2023"], "types": ["node"] }, - "include": ["src/**/*.ts", "scripts/**/*.ts", "test/**/*.ts", "drizzle.config.ts", "drizzle.test.config.ts", "tsdown.config.ts", "vitest.config.ts"] + "include": ["src/**/*.ts", "scripts/**/*.ts", "migrations/**/*.ts", "test/**/*.ts", "tsdown.config.ts", "vitest.config.ts"] } diff --git a/packages/server/tsdown.config.ts b/packages/server/tsdown.config.ts index 77aafaf..17ca869 100644 --- a/packages/server/tsdown.config.ts +++ b/packages/server/tsdown.config.ts @@ -1,7 +1,10 @@ import { defineConfig } from 'tsdown' export default defineConfig({ - entry: { index: 'src/index.ts' }, + entry: ['src/index.ts', 'scripts/migrate.ts', 'scripts/purge-expired-runs.ts', 'migrations/*.ts'], platform: 'node', format: 'esm', + // Bundle the workspace lib (its in-repo exports point at TS source) so the + // built server runs in prod without resolving @kinora/core from node_modules. + deps: { alwaysBundle: ['@kinora/core'] }, }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3c0101b..15bc6d5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -88,7 +88,7 @@ importers: dependencies: '@better-auth/api-key': specifier: ^1.5.6 - version: 1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(better-call@1.3.5(zod@4.4.3)) + version: 1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(better-call@1.3.5(zod@4.4.3)) '@hono/node-server': specifier: ^2.0.4 version: 2.0.4(hono@4.12.23) @@ -103,7 +103,7 @@ importers: version: link:../core '@polar-sh/better-auth': specifier: ^1.8.4 - version: 1.8.4(@polar-sh/sdk@0.47.1)(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@stripe/stripe-js@7.9.0)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(react@19.2.7)(zod@4.4.3) + version: 1.8.4(@polar-sh/sdk@0.47.1)(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@stripe/stripe-js@7.9.0)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(react@19.2.7)(zod@4.4.3) '@polar-sh/sdk': specifier: ^0.47.1 version: 0.47.1 @@ -112,16 +112,19 @@ importers: version: 11.17.0(typescript@6.0.3) better-auth: specifier: ^1.5.6 - version: 1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)) + version: 1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)) dotenv: specifier: ^17.3.1 version: 17.4.2 drizzle-orm: specifier: ^0.45.2 - version: 0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0) + version: 0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0) hono: specifier: ^4.12.23 version: 4.12.23 + knex: + specifier: ^3.2.10 + version: 3.2.10(pg@8.21.0) pg: specifier: ^8.20.0 version: 8.21.0 @@ -141,9 +144,6 @@ importers: '@types/pg': specifier: ^8.20.0 version: 8.20.0 - drizzle-kit: - specifier: ^0.31.10 - version: 0.31.10 tsdown: specifier: ^0.22.2 version: 0.22.2(tsx@4.22.4)(typescript@6.0.3) @@ -280,7 +280,7 @@ importers: dependencies: '@better-auth/api-key': specifier: ^1.5.6 - version: 1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(better-call@1.3.5(zod@4.4.3)) + version: 1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(better-call@1.3.5(zod@4.4.3)) '@kinora/core': specifier: workspace:* version: link:../core @@ -292,7 +292,7 @@ importers: version: 1.17.0(vue@3.5.35(typescript@6.0.3)) '@polar-sh/better-auth': specifier: ^1.8.4 - version: 1.8.4(@polar-sh/sdk@0.47.1)(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@stripe/stripe-js@7.9.0)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(react@19.2.7)(zod@4.4.3) + version: 1.8.4(@polar-sh/sdk@0.47.1)(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@stripe/stripe-js@7.9.0)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(react@19.2.7)(zod@4.4.3) '@polar-sh/sdk': specifier: ^0.47.1 version: 0.47.1 @@ -313,7 +313,7 @@ importers: version: 14.3.0(vue-router@5.1.0(@vue/compiler-sfc@3.5.35)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.35(typescript@6.0.3)))(vue@3.5.35(typescript@6.0.3)) better-auth: specifier: ^1.5.6 - version: 1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)) + version: 1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -2186,9 +2186,16 @@ packages: codemirror@6.0.2: resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} + colorette@2.0.19: + resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + commander@8.3.0: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} @@ -2242,6 +2249,15 @@ packages: dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -2409,6 +2425,10 @@ packages: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + es-module-lexer@2.1.0: resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} @@ -2633,6 +2653,10 @@ packages: jiti: optional: true + esm@3.2.25: + resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} + engines: {node: '>=6'} + espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2753,10 +2777,17 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + get-east-asian-width@1.6.0: resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + get-tsconfig@4.14.0: resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} @@ -2764,6 +2795,9 @@ packages: resolution: {integrity: sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==} engines: {node: '>=20.20.0'} + getopts@2.3.0: + resolution: {integrity: sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==} + github-slugger@2.0.0: resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} @@ -2793,6 +2827,10 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + help-me@5.0.0: resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} @@ -2829,10 +2867,18 @@ packages: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} + interpret@2.2.0: + resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==} + engines: {node: '>= 0.10'} + is-builtin-module@5.0.0: resolution: {integrity: sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==} engines: {node: '>=18.20'} + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2916,6 +2962,37 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} + knex@3.2.10: + resolution: {integrity: sha512-oypTHfrc9i72iyxaUQBKHOxhcr0xM65MPf6FpN02nimsftXwzXprIkLjfXdubvhbu4PMWLp023q8o8CYvHSuZw==} + engines: {node: '>=16'} + hasBin: true + peerDependencies: + better-sqlite3: '*' + mysql: '*' + mysql2: '*' + pg: '*' + pg-native: '*' + pg-query-stream: ^4.14.0 + sqlite3: '*' + tedious: '*' + peerDependenciesMeta: + better-sqlite3: + optional: true + mysql: + optional: true + mysql2: + optional: true + pg: + optional: true + pg-native: + optional: true + pg-query-stream: + optional: true + sqlite3: + optional: true + tedious: + optional: true + kysely@0.29.2: resolution: {integrity: sha512-s6WVJyEZrbm6jhBpiKHsGHyePMrVQKJ85wZCFCr9W4QHv6WTjWIrdvTmO9hDEA3bNK0xkrE2DqrHsXMLWuZpQg==} engines: {node: '>=22.0.0'} @@ -3009,6 +3086,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + log-update@7.2.0: resolution: {integrity: sha512-iLs7dGSyjZiUgvrUvuD3FndAxVJk+TywBkkkwUSm9HdYoskJalWg5qVsEiXeufPvRVPbCUmNQewg798rx+sPXg==} engines: {node: '>=20'} @@ -3193,6 +3273,9 @@ packages: module-replacements@3.0.0-beta.8: resolution: {integrity: sha512-sc8TepP9elxoOBXEpxmhPzKKjTjbswHVcmsKGbgvm3k6jZlLu/WMV/Lfmga6IGMgHU/V3WtY2s6VEgM4nTElUQ==} + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3283,6 +3366,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -3298,6 +3384,9 @@ packages: pg-connection-string@2.13.0: resolution: {integrity: sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig==} + pg-connection-string@2.6.2: + resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} @@ -3457,6 +3546,10 @@ packages: real-require@1.0.0: resolution: {integrity: sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==} + rechoir@0.8.0: + resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} + engines: {node: '>= 10.13.0'} + refa@0.12.1: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -3482,9 +3575,18 @@ packages: resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} engines: {node: '>=18'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + restore-cursor@5.1.0: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} @@ -3653,6 +3755,10 @@ packages: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + synckit@0.11.13: resolution: {integrity: sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -3667,6 +3773,10 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + tarn@3.0.2: + resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==} + engines: {node: '>=8.0.0'} + terminal-size@4.0.1: resolution: {integrity: sha512-avMLDQpUI9I5XFrklECw1ZEUPJhqzcwSWsyyI8blhRLT+8N1jLJWLWWYQpB2q2xthq8xDvjZPISVh53T/+CLYQ==} engines: {node: '>=18'} @@ -3675,6 +3785,10 @@ packages: resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} engines: {node: '>=20'} + tildify@2.0.0: + resolution: {integrity: sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==} + engines: {node: '>=8'} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -4124,11 +4238,11 @@ snapshots: '@babel/helper-string-parser': 8.0.0-rc.6 '@babel/helper-validator-identifier': 8.0.0-rc.6 - '@better-auth/api-key@1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(better-call@1.3.5(zod@4.4.3))': + '@better-auth/api-key@1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(better-call@1.3.5(zod@4.4.3))': dependencies: '@better-auth/core': 1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0) '@better-auth/utils': 0.4.1 - better-auth: 1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)) + better-auth: 1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)) better-call: 1.3.5(zod@4.4.3) zod: 4.4.3 @@ -4144,12 +4258,12 @@ snapshots: nanostores: 1.3.0 zod: 4.4.3 - '@better-auth/drizzle-adapter@1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))': + '@better-auth/drizzle-adapter@1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))': dependencies: '@better-auth/core': 1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0) '@better-auth/utils': 0.4.1 optionalDependencies: - drizzle-orm: 0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0) + drizzle-orm: 0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0) '@better-auth/kysely-adapter@1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(kysely@0.29.2)': dependencies: @@ -4256,7 +4370,8 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@drizzle-team/brocli@0.10.2': {} + '@drizzle-team/brocli@0.10.2': + optional: true '@e18e/eslint-plugin@0.4.1(eslint@10.4.1(jiti@2.7.0))': dependencies: @@ -4304,11 +4419,13 @@ snapshots: dependencies: esbuild: 0.18.20 source-map-support: 0.5.21 + optional: true '@esbuild-kit/esm-loader@2.6.5': dependencies: '@esbuild-kit/core-utils': 3.3.2 get-tsconfig: 4.14.0 + optional: true '@esbuild/aix-ppc64@0.25.12': optional: true @@ -4740,11 +4857,11 @@ snapshots: dependencies: playwright: 1.60.0 - '@polar-sh/better-auth@1.8.4(@polar-sh/sdk@0.47.1)(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@stripe/stripe-js@7.9.0)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(react@19.2.7)(zod@4.4.3)': + '@polar-sh/better-auth@1.8.4(@polar-sh/sdk@0.47.1)(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@stripe/stripe-js@7.9.0)(better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)))(react@19.2.7)(zod@4.4.3)': dependencies: '@polar-sh/checkout': 0.2.1(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@stripe/stripe-js@7.9.0)(react@19.2.7) '@polar-sh/sdk': 0.47.1 - better-auth: 1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)) + better-auth: 1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)) zod: 4.4.3 transitivePeerDependencies: - '@stripe/react-stripe-js' @@ -5449,10 +5566,10 @@ snapshots: baseline-browser-mapping@2.10.33: {} - better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)): + better-auth@1.6.14(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(vitest@4.1.8(@types/node@24.13.0)(vite@8.0.16(@types/node@24.13.0)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(vue@3.5.35(typescript@6.0.3)): dependencies: '@better-auth/core': 1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0) - '@better-auth/drizzle-adapter': 1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0)) + '@better-auth/drizzle-adapter': 1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0)) '@better-auth/kysely-adapter': 1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1)(kysely@0.29.2) '@better-auth/memory-adapter': 1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1) '@better-auth/mongo-adapter': 1.6.14(@better-auth/core@1.6.14(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1) @@ -5470,7 +5587,7 @@ snapshots: zod: 4.4.3 optionalDependencies: drizzle-kit: 0.31.10 - drizzle-orm: 0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0) + drizzle-orm: 0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0) pg: 8.21.0 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -5511,7 +5628,8 @@ snapshots: node-releases: 2.0.47 update-browserslist-db: 1.2.3(browserslist@4.28.2) - buffer-from@1.1.2: {} + buffer-from@1.1.2: + optional: true builtin-modules@5.2.0: {} @@ -5570,8 +5688,12 @@ snapshots: '@codemirror/state': 6.6.0 '@codemirror/view': 6.43.0 + colorette@2.0.19: {} + colorette@2.0.20: {} + commander@10.0.1: {} + commander@8.3.0: {} comment-parser@1.4.5: {} @@ -5610,6 +5732,10 @@ snapshots: dateformat@4.6.3: {} + debug@4.3.4: + dependencies: + ms: 2.1.2 + debug@4.4.3: dependencies: ms: 2.1.3 @@ -5640,10 +5766,12 @@ snapshots: '@esbuild-kit/esm-loader': 2.6.5 esbuild: 0.25.12 tsx: 4.22.4 + optional: true - drizzle-orm@0.45.2(@types/pg@8.20.0)(kysely@0.29.2)(pg@8.21.0): + drizzle-orm@0.45.2(@types/pg@8.20.0)(knex@3.2.10(pg@8.21.0))(kysely@0.29.2)(pg@8.21.0): optionalDependencies: '@types/pg': 8.20.0 + knex: 3.2.10(pg@8.21.0) kysely: 0.29.2 pg: 8.21.0 @@ -5668,6 +5796,8 @@ snapshots: environment@1.1.0: {} + es-errors@1.3.0: {} + es-module-lexer@2.1.0: {} esbuild@0.18.20: @@ -5694,6 +5824,7 @@ snapshots: '@esbuild/win32-arm64': 0.18.20 '@esbuild/win32-ia32': 0.18.20 '@esbuild/win32-x64': 0.18.20 + optional: true esbuild@0.25.12: optionalDependencies: @@ -5723,6 +5854,7 @@ snapshots: '@esbuild/win32-arm64': 0.25.12 '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + optional: true esbuild@0.28.0: optionalDependencies: @@ -6032,6 +6164,8 @@ snapshots: transitivePeerDependencies: - supports-color + esm@3.2.25: {} + espree@10.4.0: dependencies: acorn: 8.16.0 @@ -6138,8 +6272,12 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + get-east-asian-width@1.6.0: {} + get-package-type@0.1.0: {} + get-tsconfig@4.14.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -6148,6 +6286,8 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + getopts@2.3.0: {} + github-slugger@2.0.0: {} glob-parent@5.1.2: @@ -6168,6 +6308,10 @@ snapshots: graceful-fs@4.2.11: {} + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + help-me@5.0.0: {} hono@4.12.23: {} @@ -6188,10 +6332,16 @@ snapshots: indent-string@5.0.0: {} + interpret@2.2.0: {} + is-builtin-module@5.0.0: dependencies: builtin-modules: 5.2.0 + is-core-module@2.16.2: + dependencies: + hasown: 2.0.4 + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -6248,6 +6398,27 @@ snapshots: kleur@4.1.5: {} + knex@3.2.10(pg@8.21.0): + dependencies: + colorette: 2.0.19 + commander: 10.0.1 + debug: 4.3.4 + escalade: 3.2.0 + esm: 3.2.25 + get-package-type: 0.1.0 + getopts: 2.3.0 + interpret: 2.2.0 + lodash: 4.18.1 + pg-connection-string: 2.6.2 + rechoir: 0.8.0 + resolve-from: 5.0.0 + tarn: 3.0.2 + tildify: 2.0.0 + optionalDependencies: + pg: 8.21.0 + transitivePeerDependencies: + - supports-color + kysely@0.29.2: {} levn@0.4.1: @@ -6316,6 +6487,8 @@ snapshots: lodash.merge@4.6.2: {} + lodash@4.18.1: {} + log-update@7.2.0: dependencies: ansi-escapes: 7.3.0 @@ -6703,6 +6876,8 @@ snapshots: module-replacements@3.0.0-beta.8: {} + ms@2.1.2: {} + ms@2.1.3: {} muggle-string@0.4.1: {} @@ -6772,6 +6947,8 @@ snapshots: path-key@3.1.1: {} + path-parse@1.0.7: {} + pathe@2.0.3: {} perfect-debounce@1.0.0: {} @@ -6783,6 +6960,8 @@ snapshots: pg-connection-string@2.13.0: {} + pg-connection-string@2.6.2: {} + pg-int8@1.0.1: {} pg-pool@3.14.0(pg@8.21.0): @@ -6946,6 +7125,10 @@ snapshots: real-require@1.0.0: {} + rechoir@0.8.0: + dependencies: + resolve: 1.22.12 + refa@0.12.1: dependencies: '@eslint-community/regexpp': 4.12.2 @@ -6979,8 +7162,17 @@ snapshots: reserved-identifiers@1.2.0: {} + resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@5.1.0: dependencies: onetime: 7.0.0 @@ -7099,8 +7291,10 @@ snapshots: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + optional: true - source-map@0.6.1: {} + source-map@0.6.1: + optional: true spdx-exceptions@2.5.0: {} @@ -7155,6 +7349,8 @@ snapshots: supports-color@10.2.2: {} + supports-preserve-symlinks-flag@1.0.0: {} + synckit@0.11.13: dependencies: '@pkgr/core': 0.3.6 @@ -7165,12 +7361,16 @@ snapshots: tapable@2.3.3: {} + tarn@3.0.2: {} + terminal-size@4.0.1: {} thread-stream@4.2.0: dependencies: real-require: 1.0.0 + tildify@2.0.0: {} + tinybench@2.9.0: {} tinyexec@1.2.4: {}