diff --git a/.env.example b/.env.example index 66916da..37f0193 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,7 @@ -SQLITECLOUD_URL=sqlitecloud://your-project.g6.sqlite.cloud:8860/cloud.db?apikey=your-api-key +TURSO_DATABASE_URL=libsql://your-database-your-org.aws-us-west-2.turso.io +TURSO_AUTH_TOKEN=your-turso-auth-token +# For local development, point at a file instead and leave the token unset: +# TURSO_DATABASE_URL=file:./local.db NEXT_PUBLIC_BASE_URL=https://c0upons.com COINPAY_API_KEY=cp_live_your_api_key COINPAY_CLIENT_ID=cp_live_your_api_key diff --git a/.github/workflows/db-keepalive.yml b/.github/workflows/db-keepalive.yml index 772a4b7..319a2ed 100644 --- a/.github/workflows/db-keepalive.yml +++ b/.github/workflows/db-keepalive.yml @@ -1,10 +1,9 @@ name: db-keepalive -# SQLite Cloud parks a free node after a stretch of inactivity, and a parked -# node refuses new connections — so no amount of visitor traffic revives it, -# only a restart from https://dashboard.sqlitecloud.io. Prevention is the only -# automatable half: this keeps a query flowing so the node never goes idle -# long enough to be parked. +# Turso scales an idle free database to zero and wakes it automatically on the +# next request, but a group left idle for ten days is archived, and that state +# needs an explicit unarchive call. Keeping a query flowing means the ten-day +# clock never runs down. # # Two caveats worth knowing before trusting it as the sole guard: # * GitHub delays scheduled runs under load and drops them entirely when the @@ -47,5 +46,6 @@ jobs: sleep 10 done echo "::error::Database unreachable after 3 attempts (last status $status)." - echo "::error::If the body says the node is paused, restart it at https://dashboard.sqlitecloud.io" + echo "::error::If the group was archived for inactivity, unarchive it:" + echo "::error:: turso group unarchive default (or POST /v1/organizations/{org}/groups/{group}/unarchive)" exit 1 diff --git a/apps/web/app/api/health/db/route.ts b/apps/web/app/api/health/db/route.ts index 34d3e63..67c8a04 100644 --- a/apps/web/app/api/health/db/route.ts +++ b/apps/web/app/api/health/db/route.ts @@ -2,19 +2,19 @@ import { NextResponse } from 'next/server'; import { getDb } from '@/lib/db'; import { dbErrorResponse } from '@/lib/api-error'; -// Never cache: a cached 200 would keep reporting health after the node parks, -// and the keep-alive query has to actually reach SQLite Cloud to count as +// Never cache: a cached 200 would keep reporting health after the database goes +// away, and the keep-alive query has to actually reach Turso to count as // activity. export const dynamic = 'force-dynamic'; /** * Liveness probe for the database, and the query the keep-alive schedule runs. * - * SQLite Cloud parks a free node after a stretch with no queries, and a parked - * node cannot be woken by traffic — only by a restart from the dashboard. So - * the cheapest cure is to never go idle: `.github/workflows/db-keepalive.yml` - * calls this on a schedule, and the `SELECT 1` is the activity that keeps the - * node awake. It doubles as monitoring — a paused node answers 503 here loudly + * Turso archives a free group after ten days without activity, and an archived + * group needs an explicit unarchive call before it serves queries again. So the + * cheapest cure is to never go idle: `.github/workflows/db-keepalive.yml` calls + * this on a schedule, and the `SELECT 1` is the activity that resets the clock. + * It doubles as monitoring — an unreachable database answers 503 here loudly * instead of silently emptying the pages that swallow their own DB errors. */ export async function GET() { diff --git a/apps/web/app/privacy/page.tsx b/apps/web/app/privacy/page.tsx index 6b4c647..d69d109 100644 --- a/apps/web/app/privacy/page.tsx +++ b/apps/web/app/privacy/page.tsx @@ -56,7 +56,7 @@ export default function PrivacyPage() {
diff --git a/apps/web/components/Footer.tsx b/apps/web/components/Footer.tsx index c07b578..b54d9bd 100644 --- a/apps/web/components/Footer.tsx +++ b/apps/web/components/Footer.tsx @@ -71,7 +71,7 @@ export default function Footer() {

© {new Date().getFullYear()} c0upons. Community-powered savings.

-

Built with Next.js · Powered by SQLite Cloud

+

Built with Next.js · Powered by Turso

diff --git a/apps/web/lib/api-error.ts b/apps/web/lib/api-error.ts index 2800e0b..8f93769 100644 --- a/apps/web/lib/api-error.ts +++ b/apps/web/lib/api-error.ts @@ -3,9 +3,9 @@ import { NextResponse } from 'next/server'; import { isDbPaused } from './db'; /** - * What a caller sees when the database node is parked. It names the cause - * rather than the fix: the dashboard restart is an operator action, and the - * person hitting the API can only wait. + * What a caller sees when the database cannot be reached. It names the cause + * rather than the fix: reviving an archived database is an operator action, and + * the person hitting the API can only wait. */ export const DB_PAUSED_MESSAGE = 'The coupon database is temporarily unavailable and should be back shortly.'; @@ -13,11 +13,12 @@ export const DB_PAUSED_MESSAGE = /** * Map an error caught in a route handler onto a response. * - * A paused database is a transient infrastructure state, not a bad request and - * not a bug, so it answers 503 + Retry-After instead of a blanket 500. Anything - * else keeps the route's own 500 and message, so a genuine defect still reads - * as a defect. `code` is stable for clients to branch on — the CLI prints its - * own wording for `database_paused` rather than echoing a raw HTTP status. + * An unreachable database is a transient infrastructure state, not a bad + * request and not a bug, so it answers 503 + Retry-After instead of a blanket + * 500. Anything else keeps the route's own 500 and message, so a genuine defect + * still reads as a defect. The `database_paused` code is the published wire + * contract for clients that want to branch on this rather than parse prose; it + * predates the move to Turso and is kept as-is so existing callers don't break. */ export function dbErrorResponse(err: unknown, fallback: string): NextResponse { if (isDbPaused(err)) { diff --git a/apps/web/lib/db.ts b/apps/web/lib/db.ts index fa89cec..a3d78f8 100644 --- a/apps/web/lib/db.ts +++ b/apps/web/lib/db.ts @@ -1,70 +1,67 @@ import 'server-only'; -import { Database } from '@sqlitecloud/drivers'; +import { createClient, type Client, type InValue } from '@libsql/client'; import { loadRootEnv } from './root-env'; -let client: Database | null = null; +let client: Client | null = null; -function createClient(): Database { +function getClient(): Client { + if (client) return client; loadRootEnv(); - const url = process.env.SQLITECLOUD_URL; - if (!url) throw new Error('SQLITECLOUD_URL is not set'); - return new Database({ connectionstring: url, usewebsocket: true }); + const url = process.env.TURSO_DATABASE_URL; + if (!url) throw new Error('TURSO_DATABASE_URL is not set'); + // A `file:` URL needs no token, which is what makes local runs and tests + // possible without production credentials. + client = createClient({ url, authToken: process.env.TURSO_AUTH_TOKEN }); + return client; } -// A cached client can hold a dead websocket after the SQLite Cloud node pauses -// and resumes (free-tier auto-pause). Without this, getDb() keeps returning the -// same broken connection and every query fails with "Connection unavailable" -// until the process is restarted — which is exactly how /blog silently emptied. -// Treat disconnect-class errors as recoverable: drop the client and retry once -// with a fresh connection. -function isDisconnect(err: unknown): boolean { - const msg = err instanceof Error ? err.message : String(err); - return /connection unavailable|got disconnected|disconnected|connection not been established|ERR_CONNECTION/i.test( - msg - ); -} - -// SQLite Cloud parks a free-tier node after a stretch of inactivity. Every -// query then fails with error 10010 until someone restarts it from the -// dashboard, and the node refuses new sockets too — so reconnecting cannot fix -// it. That is why this is deliberately NOT folded into isDisconnect() above: -// retrying a paused node just pays the connection cost twice before failing -// identically. Callers use it to tell "c0upons is down" (transient, 503) apart -// from "c0upons is broken" (a real 500). -export function isDbPaused(err: unknown): boolean { - const code = (err as { errorCode?: string | number } | null)?.errorCode; - if (code != null && String(code) === '10010') return true; - const msg = err instanceof Error ? err.message : String(err); - return /node has been paused|paused due to inactivity/i.test(msg); +// libSQL refuses `undefined` outright ("undefined cannot be passed as argument +// to the database"), while the routes hand it over freely for absent optional +// fields — an unscraped image_url, a webhook payload without a thumbnail. The +// old driver swallowed those; coercing here keeps a missing field a NULL +// instead of turning it into a 500. +function bind(value: unknown): InValue { + return value === undefined ? null : (value as InValue); } -async function runSql(args: unknown[]): Promise { - if (!client) client = createClient(); - try { - return await (client.sql as (...a: unknown[]) => Promise)(...args); - } catch (err) { - if (!isDisconnect(err)) throw err; - try { - (client as unknown as { close?: () => void }).close?.(); - } catch { - /* ignore close failures on an already-dead socket */ - } - client = createClient(); - return await (client.sql as (...a: unknown[]) => Promise)(...args); - } +/** + * The database handle. Only `db.sql` is used anywhere in the app, so this + * exposes exactly that: a tagged template that binds every interpolated value + * as a parameter and resolves to the rows. + * + * libSQL rows are array-like *and* object-like, and serialize to plain named + * objects, so callers keep working unchanged — `rows.length`, destructuring a + * single COUNT row, and `NextResponse.json(rows)` all behave as before. + * + * Unlike the SQLite Cloud driver this replaces, there is no long-lived + * websocket to go stale, so no reconnect dance is needed: the HTTP client + * establishes a connection per request and a dropped one cannot poison the + * cached handle the way it once silently emptied /blog. + */ +export function getDb() { + return { + // The app assigns results straight to its own row types + // (`const stores: StoreWithCount[] = await db.sql...`), which is why this + // stays `any` rather than forcing a cast at all 77 call sites. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + sql: async (strings: TemplateStringsArray, ...values: unknown[]): Promise => { + const rs = await getClient().execute({ + sql: strings.join('?'), + args: values.map(bind), + }); + return rs.rows; + }, + }; } -// Returns the shared client with its `sql` tagged-template wrapped so a stale -// connection self-heals. All call sites use only `db.sql`, so this is drop-in. -export function getDb(): Database { - if (!client) client = createClient(); - return new Proxy(client, { - get(target, prop, receiver) { - if (prop === 'sql') { - return (...args: unknown[]) => runSql(args); - } - const value = Reflect.get(target, prop, receiver); - return typeof value === 'function' ? value.bind(target) : value; - }, - }); +// Turso scales an idle free database to zero and wakes it automatically on the +// next request, so a brief stall is normal rather than an outage. A group left +// idle for ten days is archived instead, and that state does need an explicit +// unarchive call — the shapes below are the ones seen for a database that is +// gone or unreachable rather than merely asleep. Callers use this to tell +// "c0upons is down" (transient, 503) apart from "c0upons is broken" (a real +// 500). +export function isDbPaused(err: unknown): boolean { + const msg = err instanceof Error ? err.message : String(err); + return /archived|not found|unavailable|SERVER_ERROR|502|503/i.test(msg); } diff --git a/apps/web/lib/schema.sql b/apps/web/lib/schema.sql index 3ec19c6..785f375 100644 --- a/apps/web/lib/schema.sql +++ b/apps/web/lib/schema.sql @@ -1,56 +1,92 @@ +-- Reference copy of the c0upons schema. +-- +-- scripts/migrate.mjs is what actually creates and evolves the database; this +-- file documents the result. It is dumped from a database built by that script, +-- so the two agree — an earlier copy of this file stopped at blog_posts and +-- omitted coupon_votes and bounties entirely, which made rebuilding from it +-- silently incomplete. Regenerate with `turso db shell ".schema"` after +-- changing the migration rather than hand-editing. + CREATE TABLE IF NOT EXISTS categories ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - slug TEXT NOT NULL UNIQUE + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + slug TEXT NOT NULL UNIQUE, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS stores ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - slug TEXT NOT NULL UNIQUE, - logo_url TEXT, - website TEXT, + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + slug TEXT NOT NULL UNIQUE, + logo_url TEXT, + website TEXT, category_id INTEGER REFERENCES categories(id), - created_at TEXT DEFAULT (datetime('now')) + created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS coupons ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - store_id INTEGER NOT NULL REFERENCES stores(id), - code TEXT, - title TEXT NOT NULL, - description TEXT, - discount TEXT, - discount_type TEXT, + id INTEGER PRIMARY KEY AUTOINCREMENT, + store_id INTEGER NOT NULL REFERENCES stores(id) ON DELETE CASCADE, + code TEXT, + title TEXT NOT NULL, + description TEXT, + discount TEXT, + discount_type TEXT, discount_value REAL, - expiry_date TEXT, - verified INTEGER DEFAULT 0, - votes INTEGER DEFAULT 0, - url TEXT, - image_url TEXT, - created_at TEXT DEFAULT (datetime('now')) + expiry_date TEXT, + url TEXT, + image_url TEXT, + votes INTEGER NOT NULL DEFAULT 0, + verified INTEGER NOT NULL DEFAULT 0, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -CREATE INDEX IF NOT EXISTS idx_coupons_store ON coupons(store_id); -CREATE INDEX IF NOT EXISTS idx_stores_slug ON stores(slug); -CREATE INDEX IF NOT EXISTS idx_categories_slug ON categories(slug); +CREATE TABLE IF NOT EXISTS coupon_votes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + coupon_id INTEGER NOT NULL REFERENCES coupons(id) ON DELETE CASCADE, + voter_did TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + UNIQUE(coupon_id, voter_did) +); CREATE TABLE IF NOT EXISTS blog_posts ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - slug TEXT NOT NULL UNIQUE, - title TEXT NOT NULL, - excerpt TEXT, - content TEXT NOT NULL DEFAULT '', - cover_image TEXT, + id INTEGER PRIMARY KEY AUTOINCREMENT, + slug TEXT NOT NULL UNIQUE, + title TEXT NOT NULL, + excerpt TEXT, + content TEXT NOT NULL DEFAULT '', + cover_image TEXT, thumbnail_image TEXT, - banner_image TEXT, - author TEXT, - status TEXT NOT NULL DEFAULT 'published', - source TEXT, - source_id TEXT, - published_at TEXT DEFAULT (datetime('now')), - updated_at TEXT DEFAULT (datetime('now')) + banner_image TEXT, + author TEXT, + status TEXT NOT NULL DEFAULT 'published', + source TEXT, + source_id TEXT, + published_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); +CREATE TABLE IF NOT EXISTS bounties ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + public_id TEXT, + creator_did TEXT NOT NULL, + store_id INTEGER REFERENCES stores(id), + store_name TEXT, + title TEXT NOT NULL, + description TEXT, + url TEXT, + reward_usd REAL NOT NULL, + status TEXT NOT NULL DEFAULT 'open', + payment_id TEXT, + coupon_id INTEGER REFERENCES coupons(id), + claimer_did TEXT, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX IF NOT EXISTS idx_coupons_store ON coupons(store_id); +CREATE INDEX IF NOT EXISTS idx_stores_slug ON stores(slug); +CREATE INDEX IF NOT EXISTS idx_categories_slug ON categories(slug); CREATE INDEX IF NOT EXISTS idx_blog_posts_status_published ON blog_posts(status, published_at); CREATE UNIQUE INDEX IF NOT EXISTS idx_blog_posts_source_id ON blog_posts(source, source_id); +CREATE UNIQUE INDEX IF NOT EXISTS idx_bounties_public_id ON bounties(public_id); diff --git a/apps/web/package.json b/apps/web/package.json index bb7f68b..2ae1c09 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -15,9 +15,9 @@ }, "dependencies": { "@anthropic-ai/sdk": "^0.104.1", + "@libsql/client": "^0.17.4", "@profullstack/stack": "^0.1.3", "@serwist/next": "^9.5.0", - "@sqlitecloud/drivers": "^1.0.880", "next": "16.2.7", "posthog-js": "^1.381.0", "react": "19.2.4", diff --git a/apps/web/public/llms.txt b/apps/web/public/llms.txt index cd6e7ed..9a4f20c 100644 --- a/apps/web/public/llms.txt +++ b/apps/web/public/llms.txt @@ -30,4 +30,4 @@ c0upons is a free, open-source coupon aggregator where anyone can browse deals, - **Community-driven:** Anyone can submit codes; votes surface the best ones. - **Open source:** MIT licensed, source on GitHub. - **API:** `GET /api/coupons`, `GET /api/stores`, `GET /api/search?q=query` -- **Stack:** Next.js 16, SQLite Cloud, Tailwind CSS v4, deployed on Railway. +- **Stack:** Next.js 16, Turso (libSQL), Tailwind CSS v4, deployed on Railway. diff --git a/apps/web/scripts/migrate.mjs b/apps/web/scripts/migrate.mjs index 3ba80b3..c3b8d64 100644 --- a/apps/web/scripts/migrate.mjs +++ b/apps/web/scripts/migrate.mjs @@ -2,9 +2,11 @@ * Database migration — creates tables and optionally seeds sample data. * Run with: pnpm db:migrate (from apps/web) * - * Requires SQLITECLOUD_URL in the repo root .env or as an env var. + * Requires TURSO_DATABASE_URL (and TURSO_AUTH_TOKEN for a remote database) in + * the repo root .env or as env vars. A `file:` URL runs it against a local + * SQLite file, which is how the schema is exercised in tests. */ -import { Database } from '@sqlitecloud/drivers'; +import { createClient } from '@libsql/client'; import { readFileSync } from 'fs'; import { resolve, dirname } from 'path'; import { fileURLToPath } from 'url'; @@ -31,13 +33,24 @@ try { } } catch { /* no root .env — fall through to existing env */ } -const url = process.env.SQLITECLOUD_URL; +const url = process.env.TURSO_DATABASE_URL; if (!url) { - console.error('SQLITECLOUD_URL not set'); + console.error('TURSO_DATABASE_URL not set'); process.exit(1); } -const db = new Database({ connectionstring: url, usewebsocket: true }); +// Mirrors lib/db.ts: expose `db.sql` as a tagged template so the migration +// statements below read the same as the app's queries. +const client = createClient({ url, authToken: process.env.TURSO_AUTH_TOKEN }); +const db = { + sql: async (strings, ...values) => { + const rs = await client.execute({ + sql: strings.join('?'), + args: values.map((v) => (v === undefined ? null : v)), + }); + return rs.rows; + }, +}; console.log('Running migrations...'); @@ -86,6 +99,13 @@ await addColumn(() => db.sql`ALTER TABLE coupons ADD COLUMN discount_type TEXT`) await addColumn(() => db.sql`ALTER TABLE coupons ADD COLUMN discount_value REAL`); await addColumn(() => db.sql`ALTER TABLE coupons ADD COLUMN image_url TEXT`); await addColumn(() => db.sql`ALTER TABLE coupons ADD COLUMN url TEXT`); +// These three indexes were declared in lib/schema.sql but never created here, +// so every database built by this script — production included — has been +// running without them. Every listing page joins coupons to stores and looks +// stores up by slug, so they are worth having. +await db.sql`CREATE INDEX IF NOT EXISTS idx_coupons_store ON coupons(store_id)`; +await db.sql`CREATE INDEX IF NOT EXISTS idx_stores_slug ON stores(slug)`; +await db.sql`CREATE INDEX IF NOT EXISTS idx_categories_slug ON categories(slug)`; console.log(' coupons'); await db.sql` diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86aa382..1d48652 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,15 +48,15 @@ importers: '@anthropic-ai/sdk': specifier: ^0.104.1 version: 0.104.1(zod@4.4.3) + '@libsql/client': + specifier: ^0.17.4 + version: 0.17.4 '@profullstack/stack': specifier: ^0.1.3 version: 0.1.3(next@16.2.7(@babel/core@7.29.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) '@serwist/next': specifier: ^9.5.0 version: 9.5.11(next@16.2.7(@babel/core@7.29.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(typescript@5.9.3) - '@sqlitecloud/drivers': - specifier: ^1.0.880 - version: 1.0.880 next: specifier: 16.2.7 version: 16.2.7(@babel/core@7.29.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -566,12 +566,72 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@libsql/client@0.17.4': + resolution: {integrity: sha512-lYayFWasDV78A+TjlEhr6ubb3odBV6OHjb+wdp8VQcyWWAEIjuwbCHaraEUS4m4yWoo0BvZo96It4VdzZRmRWw==} + + '@libsql/core@0.17.4': + resolution: {integrity: sha512-LqF9gIvnJ38nmAH1y/ChizHqDO/MO1wLgA96XrraulEEbqXxLjleSH92YWTolbuJKgPUmGu4aJk9W3UnAcxLOQ==} + + '@libsql/darwin-arm64@0.5.29': + resolution: {integrity: sha512-K+2RIB1OGFPYQbfay48GakLhqf3ArcbHqPFu7EZiaUcRgFcdw8RoltsMyvbj5ix2fY0HV3Q3Ioa/ByvQdaSM0A==} + cpu: [arm64] + os: [darwin] + + '@libsql/darwin-x64@0.5.29': + resolution: {integrity: sha512-OtT+KFHsKFy1R5FVadr8FJ2Bb1mghtXTyJkxv0trocq7NuHntSki1eUbxpO5ezJesDvBlqFjnWaYYY516QNLhQ==} + cpu: [x64] + os: [darwin] + + '@libsql/hrana-client@0.10.0': + resolution: {integrity: sha512-OoA4EMqRAC7kn7V2P6EQqRcpZf2W+AjsNIyCizBg339Tq/aMC7sRnzs3SklderhmQWAqEzvv8A2vhxVmWpkVvw==} + + '@libsql/isomorphic-ws@0.1.5': + resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} + + '@libsql/linux-arm-gnueabihf@0.5.29': + resolution: {integrity: sha512-CD4n4zj7SJTHso4nf5cuMoWoMSS7asn5hHygsDuhRl8jjjCTT3yE+xdUvI4J7zsyb53VO5ISh4cwwOtf6k2UhQ==} + cpu: [arm] + os: [linux] + + '@libsql/linux-arm-musleabihf@0.5.29': + resolution: {integrity: sha512-2Z9qBVpEJV7OeflzIR3+l5yAd4uTOLxklScYTwpZnkm2vDSGlC1PRlueLaufc4EFITkLKXK2MWBpexuNJfMVcg==} + cpu: [arm] + os: [linux] + + '@libsql/linux-arm64-gnu@0.5.29': + resolution: {integrity: sha512-gURBqaiXIGGwFNEaUj8Ldk7Hps4STtG+31aEidCk5evMMdtsdfL3HPCpvys+ZF/tkOs2MWlRWoSq7SOuCE9k3w==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-musl@0.5.29': + resolution: {integrity: sha512-fwgYZ0H8mUkyVqXZHF3mT/92iIh1N94Owi/f66cPVNsk9BdGKq5gVpoKO+7UxaNzuEH1roJp2QEwsCZMvBLpqg==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-x64-gnu@0.5.29': + resolution: {integrity: sha512-y14V0vY0nmMC6G0pHeJcEarcnGU2H6cm21ZceRkacWHvQAEhAG0latQkCtoS2njFOXiYIg+JYPfAoWKbi82rkg==} + cpu: [x64] + os: [linux] + + '@libsql/linux-x64-musl@0.5.29': + resolution: {integrity: sha512-gquqwA/39tH4pFl+J9n3SOMSymjX+6kZ3kWgY3b94nXFTwac9bnFNMffIomgvlFaC4ArVqMnOZD3nuJ3H3VO1w==} + cpu: [x64] + os: [linux] + + '@libsql/win32-x64-msvc@0.5.29': + resolution: {integrity: sha512-4/0CvEdhi6+KjMxMaVbFM2n2Z44escBRoEYpR+gZg64DdetzGnYm8mcNLcoySaDJZNaBd6wz5DNdgRmcI4hXcg==} + cpu: [x64] + os: [win32] + '@napi-rs/wasm-runtime@1.1.4': resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@neon-rs/load@0.0.4': + resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} + '@next/env@16.2.7': resolution: {integrity: sha512-tMJizPlj6ZYpBMMdK8S0LJufrP4QTdR6pcv9KQ/bVETPAmg0j1mlHE9G2c38UyGHxoBapgwuj7XjbGJ2RcDFOg==} @@ -729,27 +789,6 @@ packages: typescript: optional: true - '@socket.io/component-emitter@3.1.2': - resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - - '@sqlitecloud/drivers@1.0.880': - resolution: {integrity: sha512-UtO2+KQ/aEo3FOyB5SAiN+J746JI/ZI20qzfp1j2C+COqFRr7ewkFE5My9vRp3/45slmQbt0lJjL/BBI6+D8xw==} - engines: {node: '>=18.0'} - peerDependencies: - '@craftzdog/react-native-buffer': '*' - react-native-quick-base64: '*' - react-native-tcp-socket: '*' - react-native-url-polyfill: '*' - peerDependenciesMeta: - '@craftzdog/react-native-buffer': - optional: true - react-native-quick-base64: - optional: true - react-native-tcp-socket: - optional: true - react-native-url-polyfill: - optional: true - '@stablelib/base64@1.0.1': resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} @@ -903,6 +942,9 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@typescript-eslint/eslint-plugin@8.60.1': resolution: {integrity: sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1158,9 +1200,6 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.33: resolution: {integrity: sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==} engines: {node: '>=6.0.0'} @@ -1182,9 +1221,6 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1304,6 +1340,10 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -1345,13 +1385,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - engine.io-client@6.6.5: - resolution: {integrity: sha512-QCwxUDULPlXv8F6tqMMKx5dNkTe6OaBYRMPYeXKBlyOoKvAmE0ac6pW7fFhSscJ/5SI7666/U/B+MElbsrJlIg==} - - engine.io-parser@5.2.3: - resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} - engines: {node: '>=10.0.0'} - enhanced-resolve@5.22.2: resolution: {integrity: sha512-0rxICaFZ7NQho/sHely2bvOPRP0Eu2B0NZ9zM54YvRvWMn7jfz3DmnOZDR9LlXDdDcqntAVc6Hfy4gr/tdH/Ag==} engines: {node: '>=10.13.0'} @@ -1529,9 +1562,6 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - eventemitter3@5.0.4: - resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1698,9 +1728,6 @@ packages: idb@8.0.3: resolution: {integrity: sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg==} - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1854,6 +1881,9 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true + js-base64@3.9.2: + resolution: {integrity: sha512-6zayE8QlUdiweYI6cETD/XBSqFcoCUlufn/29PJR99r82x1yDnIprRca0YvAYpAW+ez0GuQkVBC6xG5QkD7OjA==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1912,6 +1942,11 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + libsql@0.5.29: + resolution: {integrity: sha512-8lMP8iMgiBzzoNbAPQ59qdVcj6UaE/Vnm+fiwX4doX4Narook0a4GPKWBEv+CR8a1OwbfkgL18uBfBjWdF0Fzg==} + cpu: [x64, arm64, wasm32, arm] + os: [darwin, linux, win32] + lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} @@ -2007,9 +2042,6 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lz4js@0.2.0: - resolution: {integrity: sha512-gY2Ia9Lm7Ep8qMiuGRhvUq0Q7qUereeldZPP1PMEJxPtEWHJLqw9pgX68oHajBH0nzJK4MaZEA/YNV3jT8u8Bg==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -2203,6 +2235,9 @@ packages: resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} engines: {node: ^14.13.1 || >=16.0.0} + promise-limit@2.7.0: + resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -2343,14 +2378,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - socket.io-client@4.8.3: - resolution: {integrity: sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==} - engines: {node: '>=10.0.0'} - - socket.io-parser@4.2.6: - resolution: {integrity: sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==} - engines: {node: '>=10.0.0'} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -2456,10 +2483,6 @@ packages: tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - tr46@5.1.1: - resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} - engines: {node: '>=18'} - ts-algebra@2.0.0: resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} @@ -2545,14 +2568,6 @@ packages: webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} - - whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} - whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} @@ -2581,8 +2596,8 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - ws@8.20.1: - resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -2593,10 +2608,6 @@ packages: utf-8-validate: optional: true - xmlhttprequest-ssl@2.1.2: - resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} - engines: {node: '>=0.4.0'} - yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -3001,6 +3012,64 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@libsql/client@0.17.4': + dependencies: + '@libsql/core': 0.17.4 + '@libsql/hrana-client': 0.10.0 + js-base64: 3.9.2 + libsql: 0.5.29 + promise-limit: 2.7.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/core@0.17.4': + dependencies: + js-base64: 3.9.2 + + '@libsql/darwin-arm64@0.5.29': + optional: true + + '@libsql/darwin-x64@0.5.29': + optional: true + + '@libsql/hrana-client@0.10.0': + dependencies: + '@libsql/isomorphic-ws': 0.1.5 + js-base64: 3.9.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/isomorphic-ws@0.1.5': + dependencies: + '@types/ws': 8.18.1 + ws: 8.21.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/linux-arm-gnueabihf@0.5.29': + optional: true + + '@libsql/linux-arm-musleabihf@0.5.29': + optional: true + + '@libsql/linux-arm64-gnu@0.5.29': + optional: true + + '@libsql/linux-arm64-musl@0.5.29': + optional: true + + '@libsql/linux-x64-gnu@0.5.29': + optional: true + + '@libsql/linux-x64-musl@0.5.29': + optional: true + + '@libsql/win32-x64-msvc@0.5.29': + optional: true + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -3008,6 +3077,8 @@ snapshots: '@tybys/wasm-util': 0.10.2 optional: true + '@neon-rs/load@0.0.4': {} + '@next/env@16.2.7': {} '@next/eslint-plugin-next@16.2.7': @@ -3131,21 +3202,6 @@ snapshots: transitivePeerDependencies: - browserslist - '@socket.io/component-emitter@3.1.2': {} - - '@sqlitecloud/drivers@1.0.880': - dependencies: - buffer: 6.0.3 - eventemitter3: 5.0.4 - lz4js: 0.2.0 - socket.io-client: 4.8.3 - socket.io-parser: 4.2.6 - whatwg-url: 14.2.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - '@stablelib/base64@1.0.1': {} '@swc/helpers@0.5.15': @@ -3268,6 +3324,10 @@ snapshots: '@types/trusted-types@2.0.7': {} + '@types/ws@8.18.1': + dependencies: + '@types/node': 22.19.19 + '@typescript-eslint/eslint-plugin@8.60.1(@typescript-eslint/parser@8.60.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -3535,8 +3595,6 @@ snapshots: balanced-match@4.0.4: {} - base64-js@1.5.1: {} - baseline-browser-mapping@2.10.33: {} brace-expansion@1.1.15: @@ -3560,11 +3618,6 @@ snapshots: node-releases: 2.0.47 update-browserslist-db: 1.2.3(browserslist@4.28.2) - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -3671,6 +3724,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + detect-libc@2.0.2: {} + detect-libc@2.1.2: {} doctrine@2.1.0: @@ -3713,20 +3768,6 @@ snapshots: emoji-regex@9.2.2: {} - engine.io-client@6.6.5: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3 - engine.io-parser: 5.2.3 - ws: 8.20.1 - xmlhttprequest-ssl: 2.1.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - engine.io-parser@5.2.3: {} - enhanced-resolve@5.22.2: dependencies: graceful-fs: 4.2.11 @@ -4075,8 +4116,6 @@ snapshots: esutils@2.0.3: {} - eventemitter3@5.0.4: {} - fast-deep-equal@3.1.3: {} fast-glob@3.3.1: @@ -4241,8 +4280,6 @@ snapshots: idb@8.0.3: {} - ieee754@1.2.1: {} - ignore@5.3.2: {} ignore@7.0.5: {} @@ -4395,6 +4432,8 @@ snapshots: jiti@2.7.0: {} + js-base64@3.9.2: {} + js-tokens@4.0.0: {} js-yaml@4.2.0: @@ -4448,6 +4487,21 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + libsql@0.5.29: + dependencies: + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 + optionalDependencies: + '@libsql/darwin-arm64': 0.5.29 + '@libsql/darwin-x64': 0.5.29 + '@libsql/linux-arm-gnueabihf': 0.5.29 + '@libsql/linux-arm-musleabihf': 0.5.29 + '@libsql/linux-arm64-gnu': 0.5.29 + '@libsql/linux-arm64-musl': 0.5.29 + '@libsql/linux-x64-gnu': 0.5.29 + '@libsql/linux-x64-musl': 0.5.29 + '@libsql/win32-x64-msvc': 0.5.29 + lightningcss-android-arm64@1.32.0: optional: true @@ -4520,8 +4574,6 @@ snapshots: dependencies: yallist: 3.1.1 - lz4js@0.2.0: {} - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -4725,6 +4777,8 @@ snapshots: pretty-bytes@6.1.1: {} + promise-limit@2.7.0: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -4926,24 +4980,6 @@ snapshots: signal-exit@4.1.0: {} - socket.io-client@4.8.3: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3 - engine.io-client: 6.6.5 - socket.io-parser: 4.2.6 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - socket.io-parser@4.2.6: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - source-map-js@1.2.1: {} source-map@0.8.0-beta.0: @@ -5060,10 +5096,6 @@ snapshots: dependencies: punycode: 2.3.1 - tr46@5.1.1: - dependencies: - punycode: 2.3.1 - ts-algebra@2.0.0: {} ts-api-utils@2.5.0(typescript@5.9.3): @@ -5198,13 +5230,6 @@ snapshots: webidl-conversions@4.0.2: {} - webidl-conversions@7.0.0: {} - - whatwg-url@14.2.0: - dependencies: - tr46: 5.1.1 - webidl-conversions: 7.0.0 - whatwg-url@7.1.0: dependencies: lodash.sortby: 4.7.0 @@ -5258,9 +5283,7 @@ snapshots: word-wrap@1.2.5: {} - ws@8.20.1: {} - - xmlhttprequest-ssl@2.1.2: {} + ws@8.21.3: {} yallist@3.1.1: {} diff --git a/turbo.json b/turbo.json index b6e2e75..1ad2fcc 100644 --- a/turbo.json +++ b/turbo.json @@ -10,7 +10,7 @@ "build": { "dependsOn": ["^build"], "outputs": [".next/**", "!.next/cache/**", "dist/**"], - "env": ["SQLITECLOUD_URL"] + "env": ["TURSO_DATABASE_URL", "TURSO_AUTH_TOKEN"] }, "lint": { "outputs": [] }, "typecheck": { "outputs": [] },