From 2f5e383a96466321f626ac1c6fbedec3ca22afdd Mon Sep 17 00:00:00 2001 From: James Montemagno Date: Mon, 3 Aug 2026 10:15:14 -0700 Subject: [PATCH 1/2] fix: replace libSQL with Node SQLite Use Node's built-in SQLite driver to avoid platform-native libSQL installs while preserving the Drizzle workshop workflow. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 577ec881-eb21-4233-b7ba-5a91e021e274 --- .devcontainer/devcontainer.json | 2 +- .github/agents/pr-readiness.md | 2 +- .github/copilot-instructions.md | 10 +- .github/instructions/astro.instructions.md | 4 +- .github/instructions/drizzle.instructions.md | 15 +- .../instructions/unit-tests.instructions.md | 10 +- .github/skills/quality-checks/SKILL.md | 14 +- .github/workflows/copilot-setup-steps.yml | 2 +- .gitignore | 1 - .npmrc | 1 - CONTRIBUTING.md | 4 +- README.md | 10 +- db/migrate.ts | 12 +- db/test-helpers.ts | 18 +- drizzle.config.ts | 2 +- eslint.config.js | 2 +- package-lock.json | 671 +++++++----------- package.json | 4 +- src/lib/db.ts | 90 ++- src/lib/games.ts | 4 +- 20 files changed, 399 insertions(+), 479 deletions(-) delete mode 100644 .npmrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d87db53..3af1c0f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,7 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node { - "name": "Tailspin Toys (Astro + Drizzle)", + "name": "Tailspin Toys (Astro + Drizzle + Node SQLite)", "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", "features": { "ghcr.io/schlich/devcontainer-features/playwright:0": {} diff --git a/.github/agents/pr-readiness.md b/.github/agents/pr-readiness.md index 3813eff..b11924e 100644 --- a/.github/agents/pr-readiness.md +++ b/.github/agents/pr-readiness.md @@ -62,7 +62,7 @@ If any of these are unclear, ask the user before proceeding. 1. Before writing, report the gaps to the user and confirm they want you to fill them. 2. Write the minimum tests needed to cover the gaps, following project conventions: - - Unit tests: `db/*.test.ts` and `src/**/*.test.ts` — Vitest, in-memory libSQL, type hints (see `.github/instructions/unit-tests.instructions.md`) + - Unit tests: `db/*.test.ts` and `src/**/*.test.ts` — Vitest, in-memory Node SQLite, type hints (see `.github/instructions/unit-tests.instructions.md`) - Frontend: `e2e-tests/*.spec.ts` — use role-based Playwright locators, `test.step`, no `waitForTimeout` (see `.github/instructions/playwright.instructions.md`) 3. Add `data-testid` attributes to any interactive elements that are missing them. 4. Do not rewrite existing tests — only add what is missing. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c5ddbed..4fc2812 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,6 +1,6 @@ # Tailspin Toys Crowd Funding Development Guidelines -This is a crowdfunding platform for games with a developer theme. The application is a single **Astro 7** site (fully prerendered/static output) styled with **Tailwind CSS v4**. Data is stored in a local SQLite database accessed at build time through **Drizzle ORM + libSQL**; pages query the database directly in frontmatter — there is no separate backend API or client-side UI framework. Please follow these guidelines when contributing: +This is a crowdfunding platform for games with a developer theme. The application is a single **Astro 7** site (fully prerendered/static output) styled with **Tailwind CSS v4**. Data is stored in a local SQLite database accessed at build time through **Drizzle ORM + Node.js's built-in SQLite driver**; pages query the database directly in frontmatter — there is no separate backend API or client-side UI framework. Please follow these guidelines when contributing: ## Agent notes @@ -37,7 +37,7 @@ This is a crowdfunding platform for games with a developer theme. The applicatio - Use TypeScript with explicit types for function parameters and return values, especially in the data layer (`db/`, `src/lib/`) - Frontend code (TypeScript, Astro) must pass ESLint checks (`npm run lint`) -### Data Layer Patterns (Drizzle + libSQL) +### Data Layer Patterns (Drizzle + Node SQLite) - Define tables in `db/schema.ts`; manage schema changes with drizzle-kit migrations - see `drizzle.instructions.md` - Keep data-access helpers in `src/lib/` with an **injectable `db`** argument so they're testable @@ -70,8 +70,8 @@ This is a crowdfunding platform for games with a developer theme. The applicatio - The project uses **npm scripts** for all development tasks — there is no `scripts/` directory. - **Skills take precedence.** Before running a command directly, check whether a skill covers the task (e.g. the `quality-checks` skill wraps tests and lint). If one applies, follow it. - Key npm scripts: - - `npm run dev` — start the Astro dev server (`predev` migrates + seeds the database) - - `npm run build` — build the static site (`prebuild` migrates + seeds the database) + - `npm run dev` — start the Astro dev server (`predev` migrates + seeds the local SQLite database) + - `npm run build` — build the static site (`prebuild` migrates + seeds the local SQLite database) - `npm run preview` — serve the built `dist/` output - `npm run lint` — ESLint - `npm run test:unit` — Vitest unit tests @@ -89,7 +89,7 @@ This is a crowdfunding platform for games with a developer theme. The applicatio The application lives at the repository root: - `db/`: Drizzle schema, migrations, transforms, seed, and `games.csv` -- `src/lib/`: database client (`db.ts`) and data-access helpers (`games.ts`) +- `src/lib/`: Node SQLite client (`db.ts`) and data-access helpers (`games.ts`) - `src/components/`: reusable `.astro` components - `src/layouts/`: Astro layout templates - `src/pages/`: Astro page routes (`index.astro` listing, `game/[id].astro`, `404.astro`, `about.astro`) diff --git a/.github/instructions/astro.instructions.md b/.github/instructions/astro.instructions.md index a60b3c8..43fbda8 100644 --- a/.github/instructions/astro.instructions.md +++ b/.github/instructions/astro.instructions.md @@ -7,7 +7,7 @@ applyTo: '**/*.astro' ## Astro Component Patterns -Astro handles everything in the UI: pages, layouts, components, routing, and content. The site is **fully prerendered** (`output: 'static'`) — there is no client-side UI framework and no separate API server. Pages read data **directly in frontmatter** at build time via the Drizzle/libSQL data-access helpers in `src/lib/`. +Astro handles everything in the UI: pages, layouts, components, routing, and content. The site is **fully prerendered** (`output: 'static'`) — there is no client-side UI framework and no separate API server. Pages read data **directly in frontmatter** at build time via the Drizzle/Node SQLite data-access helpers in `src/lib/`. ### Component Structure @@ -98,7 +98,7 @@ const game = await getGameById(getDatabase(), Number(id)); ## Data Access -- Build-time data comes from a local SQLite database via **Drizzle ORM + libSQL** (see [`drizzle.instructions.md`](drizzle.instructions.md)). +- Build-time data comes from a local SQLite database via **Drizzle ORM + Node SQLite** (see [`drizzle.instructions.md`](drizzle.instructions.md)). - Import `getDatabase()` from `src/lib/db.ts` and the typed helpers from `src/lib/games.ts`. - The database must be migrated and seeded before `astro build`; the `prebuild` npm script (`db:setup`) handles this. diff --git a/.github/instructions/drizzle.instructions.md b/.github/instructions/drizzle.instructions.md index 02fe6a6..48e19d8 100644 --- a/.github/instructions/drizzle.instructions.md +++ b/.github/instructions/drizzle.instructions.md @@ -1,11 +1,11 @@ --- -description: 'Drizzle ORM + libSQL data layer patterns for the Astro app' +description: 'Drizzle ORM + Node SQLite data layer patterns for the Astro app' applyTo: 'db/**/*.ts,src/lib/*.ts' --- -# Drizzle ORM + libSQL Instructions +# Drizzle ORM + Node SQLite Instructions -The app's data lives in a local SQLite database accessed through **Drizzle ORM** over a **libSQL** client (`@libsql/client`). It is consumed at **build time** from Astro page frontmatter — there is no runtime API server. Schema changes are managed with **drizzle-kit** migrations. +The app's data lives in a local SQLite database accessed through **Drizzle ORM** over Node.js's built-in `node:sqlite` driver. It is consumed at **build time** from Astro page frontmatter — there is no runtime API server. Schema changes are managed with **drizzle-kit** migrations. ## Layout @@ -14,8 +14,8 @@ The app's data lives in a local SQLite database accessed through **Drizzle ORM** - `db/seed.ts` — idempotent seeding from `db/games.csv` using the transforms. - `db/migrate.ts` — applies generated migrations. - `db/migrations/` — generated SQL migrations (do not hand-edit). -- `db/test-helpers.ts` — `createTestDatabase()` returns a migrated in-memory libSQL db for tests. -- `src/lib/db.ts` — `createDatabase(url)` / `getDatabase()` build the Drizzle client from `DATABASE_URL` (defaults to a local file under `.data/`). +- `db/test-helpers.ts` — `createTestDatabase()` returns a migrated in-memory Node SQLite db for tests. +- `src/lib/db.ts` — `createDatabase(url)` / `getDatabase()` build the Drizzle client from `DATABASE_URL` (defaults to the local `tailspin.db` file). - `src/lib/games.ts` — typed, **injectable-db** data-access helpers used by pages and tests. ## Schema Conventions @@ -63,7 +63,10 @@ Seed-derived values must be reproducible across builds. Derive star ratings from Unit-test transforms directly and helpers against `createTestDatabase()`. See [`unit-tests.instructions.md`](unit-tests.instructions.md). +## Node.js requirement + +Node.js 22.13 or later is required because the data layer uses the built-in `node:sqlite` module without an experimental flag. Do not introduce third-party SQLite drivers that ship platform-specific binaries. + ## Type checking The data layer (`db/**/*.ts`, `src/lib/*.ts`) is type-checked by `npm run typecheck`, which runs the native **TypeScript 7** compiler (`tsgo`, from `@typescript/native-preview`) against `tsconfig.tsgo.json`. Keep helpers exported with explicit parameter and return types so `tsgo` can verify them. Linting is unaffected — ESLint + `typescript-eslint` still run on the classic `typescript` package. - diff --git a/.github/instructions/unit-tests.instructions.md b/.github/instructions/unit-tests.instructions.md index 71b816b..d09c545 100644 --- a/.github/instructions/unit-tests.instructions.md +++ b/.github/instructions/unit-tests.instructions.md @@ -1,14 +1,14 @@ --- -description: 'Vitest unit test guidelines for the Astro + Drizzle/libSQL data layer' +description: 'Vitest unit test guidelines for the Astro + Drizzle/Node SQLite data layer' applyTo: '**/*.test.ts' --- -# Unit Testing Guidelines (Vitest + Drizzle/libSQL) +# Unit Testing Guidelines (Vitest + Drizzle/Node SQLite) Unit tests run with **Vitest** (`npm run test:unit`). They cover the two highest-value, framework-free layers: 1. **Pure transforms** (`db/transforms.ts`) — CSV parsing, description building, de-duplication, deterministic ratings. -2. **Data-access helpers** (`src/lib/games.ts`) — ordering, lookups — exercised against a real in-memory **libSQL** database. +2. **Data-access helpers** (`src/lib/games.ts`) — ordering, lookups — exercised against a real in-memory **Node SQLite** database. > [!IMPORTANT] > Keep tests independent of the Astro runtime. Helpers accept an **injectable `db`** argument; tests pass an in-memory database, pages pass the real client. Never start an Astro server to unit test data logic. @@ -43,7 +43,7 @@ describe('ratingFromTitle', () => { ## Testing Data-Access Helpers -- Build a fresh in-memory database per test with the shared helper `createTestDatabase()` (`db/test-helpers.ts`), which runs migrations on a `:memory:` libSQL client. +- Build a fresh in-memory database per test with the shared helper `createTestDatabase()` (`db/test-helpers.ts`), which runs migrations on a `:memory:` Node SQLite client. - Seed only the fixtures the test needs, then call the helper with that `db`. - Always assert the cheap thing first (counts, totals, ordering) before deep object shape. @@ -81,6 +81,6 @@ describe('getAllGames', () => { - Follow Arrange-Act-Assert. - One behaviour per `it`; avoid asserting unrelated things in a single case. -- Don't mock the database — an in-memory libSQL instance is fast and exercises real SQL/joins. +- Don't mock the database — an in-memory Node SQLite instance is fast and exercises real SQL/joins. - Keep fixtures minimal but representative of relationships (game → publisher, game → category). - If a schema change breaks tests, regenerate migrations with `npm run db:generate` and update fixtures. diff --git a/.github/skills/quality-checks/SKILL.md b/.github/skills/quality-checks/SKILL.md index ff05bee..0e5e38f 100644 --- a/.github/skills/quality-checks/SKILL.md +++ b/.github/skills/quality-checks/SKILL.md @@ -7,7 +7,7 @@ allowed-tools: # Quality Checks -This is a single Astro application (Astro 7 + Drizzle ORM/libSQL). All commands run from the repository root via npm scripts. +This is a single Astro application (Astro 7 + Drizzle ORM/Node SQLite). All commands run from the repository root via npm scripts. ## Quick Reference @@ -31,7 +31,7 @@ npm run test:unit ``` - Runs Vitest (`vitest run`) over `db/**/*.test.ts` and `src/**/*.test.ts`. -- Covers the pure seed/transform functions and the Drizzle data-access helpers against an in-memory libSQL database. +- Covers the pure seed/transform functions and the Drizzle data-access helpers against an in-memory Node SQLite database. ### Frontend E2E Tests @@ -74,7 +74,7 @@ npm ci npx playwright install --with-deps chromium # only needed for E2E ``` -- Ensure Node 20+ is available: `node --version`. +- Ensure Node 22.13+ is available: `node --version`. - Run `npx astro sync` if editor/type errors reference missing generated Astro types. --- @@ -89,8 +89,8 @@ The SQLite database must be migrated and seeded **before** `astro build`. The `p npm run db:setup # db:migrate + db:seed ``` -- The database lives at `.data/tailspin.db` (gitignored) and is regenerated from `db/games.csv`. -- To force a clean rebuild: `rm -rf .data dist && npm run build`. +- The database lives at `tailspin.db` (gitignored) and is regenerated from `db/games.csv`. +- To force a clean rebuild: `rm -f tailspin.db && rm -rf dist && npm run build`. --- @@ -129,7 +129,7 @@ npx playwright test e2e-tests/games.spec.ts **Symptom**: Assertion failures in `npm run test:unit`. 1. **Read the failing assertion** — Vitest prints expected vs received inline. -2. **In-memory database**: Helper tests build a fresh `:memory:` libSQL database, run migrations, and seed fixtures per test. If a schema change isn't reflected, regenerate migrations with `npm run db:generate`. +2. **In-memory database**: Helper tests build a fresh `:memory:` Node SQLite database, run migrations, and seed fixtures per test. If a schema change isn't reflected, regenerate migrations with `npm run db:generate`. 3. **Determinism**: Star ratings are derived from a stable hash of the title (`ratingFromTitle`) — never `Math.random`. A flaky rating assertion usually means non-deterministic data crept in. Run a single file: @@ -156,7 +156,7 @@ npx vitest run src/lib/games.test.ts **Symptom**: Tests pass locally but fail in CI (or vice versa). - **Node version mismatch**: CI uses the current Node LTS release. -- **Database state**: CI always builds from a clean seed. Locally, delete `.data/` and rebuild if you suspect stale data. +- **Database state**: CI always builds from a clean seed. Locally, delete `tailspin.db` and rebuild if you suspect stale data. - **Built vs dev**: CI tests the built `dist/` via `astro preview`. Reproduce locally with `npm run test:e2e` (which builds first) rather than against `astro dev`. --- diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 0d40171..0bf94a2 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -17,7 +17,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - # Frontend / app setup - Node.js (the whole app is now Astro + Drizzle/libSQL) + # Frontend / app setup - Node.js (the whole app is Astro + Drizzle/Node SQLite) - name: Set up Node.js uses: actions/setup-node@v6 with: diff --git a/.gitignore b/.gitignore index 306b75e..29c54a3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ dist/ node_modules/ # local SQLite database (regenerated from db/games.csv) -.data/ *.db # environment variables diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 8e5237f..0000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -@libsql:registry=https://registry.npmjs.org/ \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 17e519d..b4e13ff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ Please note that this project is released with a [Contributor Code of Conduct][c Before you can run and test the application locally, you'll need to install: -- **Node.js 20+** - [Download](https://nodejs.org/) | [Homebrew](https://formulae.brew.sh/formula/node) +- **Node.js 22.13+** - [Download](https://nodejs.org/) | [Homebrew](https://formulae.brew.sh/formula/node) - **Git** - [Download](https://git-scm.com/downloads) | [Homebrew](https://formulae.brew.sh/formula/git) ### Setting Up Your Development Environment @@ -49,7 +49,7 @@ Before you can run and test the application locally, you'll need to install: ## Making Changes -### Data Layer (Drizzle + libSQL) +### Data Layer (Drizzle + Node SQLite) - Define tables in `db/schema.ts`; generate a migration with `npm run db:generate` after schema changes - Use type hints for all function parameters and return values diff --git a/README.md b/README.md index 6df7190..3dcea83 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Tailspin Toys -Tailspin Toys is a crowdfunding platform for games with a developer theme. The project is a website for a fictional game crowd-funding company, built as a single [Astro](https://astro.build/) site (fully prerendered/static output) styled with [Tailwind CSS](https://tailwindcss.com/). Its data lives in a local SQLite database accessed through [Drizzle ORM](https://orm.drizzle.team/) over [libSQL](https://github.com/tursodatabase/libsql); pages query the database directly in frontmatter at build time, so there is no separate backend service. +Tailspin Toys is a crowdfunding platform for games with a developer theme. The project is a website for a fictional game crowd-funding company, built as a single [Astro](https://astro.build/) site (fully prerendered/static output) styled with [Tailwind CSS](https://tailwindcss.com/). Its data lives in a local SQLite database accessed through [Drizzle ORM](https://orm.drizzle.team/) and Node.js's built-in SQLite driver; pages query the database directly in frontmatter at build time, so there is no separate backend service. ## Architecture - **Astro 7** — pages, layouts, components, and routing. `output: 'static'`, so the whole site is prerendered to HTML at build time. -- **Drizzle ORM + libSQL** — the data layer. The schema lives in `db/schema.ts`; data is seeded from `db/games.csv`. Migrations are managed with `drizzle-kit`. +- **Drizzle ORM + Node SQLite** — the data layer. The schema lives in `db/schema.ts`; data is seeded from `db/games.csv`. Migrations are managed with `drizzle-kit`. - **Tailwind CSS v4** — styling via utility classes (dark theme). - **Vitest** — unit tests for the data layer and pure transforms. - **Playwright** — end-to-end tests run against the built static site. -The database is migrated and seeded automatically before `dev`/`build` (via the `predev`/`prebuild` npm scripts) and is written to `.data/` (gitignored). +The database is migrated and seeded automatically before `dev`/`build` (via the `predev`/`prebuild` npm scripts) and is written to the gitignored `tailspin.db` file. ## Using this template @@ -20,7 +20,7 @@ The workflow only runs on repositories created from the template (the `if: ${{ ! ## Getting started -Install dependencies once: +Install dependencies once with Node.js 22.13 or later: ```bash npm ci @@ -54,7 +54,7 @@ npm run db:setup # migrate + seed (run automatically by predev/prebuild) ``` > [!NOTE] -> Seeding is idempotent — it skips games that already exist (matched by title) rather than reconciling changed rows. CI always starts from a clean database, so it reflects `games.csv` exactly. Locally, if you edit or remove rows in `games.csv`, delete `.data/` and re-run `npm run db:setup` to fully regenerate. +> Seeding is idempotent — it skips games that already exist (matched by title) rather than reconciling changed rows. CI always starts from a clean database, so it reflects `games.csv` exactly. Locally, if you edit or remove rows in `games.csv`, delete `tailspin.db` and re-run `npm run db:setup` to fully regenerate. ## Running tests diff --git a/db/migrate.ts b/db/migrate.ts index 421b91a..ddf607d 100644 --- a/db/migrate.ts +++ b/db/migrate.ts @@ -1,13 +1,17 @@ -import { migrate } from 'drizzle-orm/libsql/migrator'; +import { migrate } from 'drizzle-orm/sqlite-proxy/migrator'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; -import { createDatabase } from '../src/lib/db'; +import { createDatabaseConnection, executeMigrationQueries } from '../src/lib/db'; const here = dirname(fileURLToPath(import.meta.url)); async function run(): Promise { - const db = createDatabase(); - await migrate(db, { migrationsFolder: join(here, 'migrations') }); + const { db, sqlite } = createDatabaseConnection(); + await migrate( + db, + async (queries: string[]): Promise => executeMigrationQueries(sqlite, queries), + { migrationsFolder: join(here, 'migrations') }, + ); console.log('Migrations applied.'); } diff --git a/db/test-helpers.ts b/db/test-helpers.ts index a964ee9..2ef6cfa 100644 --- a/db/test-helpers.ts +++ b/db/test-helpers.ts @@ -1,17 +1,17 @@ -import { drizzle } from 'drizzle-orm/libsql'; -import { createClient } from '@libsql/client'; -import { migrate } from 'drizzle-orm/libsql/migrator'; +import { migrate } from 'drizzle-orm/sqlite-proxy/migrator'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; -import * as schema from './schema'; -import type { Database } from '../src/lib/db'; +import { createDatabaseConnection, executeMigrationQueries, type Database } from '../src/lib/db'; const here = dirname(fileURLToPath(import.meta.url)); -/** Create a fresh in-memory libSQL database with the schema migrated in. */ +/** Create a fresh in-memory Node SQLite database with the schema migrated in. */ export async function createTestDatabase(): Promise { - const client = createClient({ url: ':memory:' }); - const db = drizzle(client, { schema }); - await migrate(db, { migrationsFolder: join(here, 'migrations') }); + const { db, sqlite } = createDatabaseConnection(':memory:'); + await migrate( + db, + async (queries: string[]): Promise => executeMigrationQueries(sqlite, queries), + { migrationsFolder: join(here, 'migrations') }, + ); return db; } diff --git a/drizzle.config.ts b/drizzle.config.ts index 218ea6c..5033a38 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -1,6 +1,6 @@ import { defineConfig } from 'drizzle-kit'; -const url = process.env.DATABASE_URL ?? 'file:./.data/tailspin.db'; +const url = process.env.DATABASE_URL ?? 'file:tailspin.db'; export default defineConfig({ dialect: 'sqlite', diff --git a/eslint.config.js b/eslint.config.js index 05999cc..51895c0 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -6,7 +6,7 @@ import globals from "globals"; export default [ // Global ignores { - ignores: ["dist/", "node_modules/", ".astro/", ".data/", "db/migrations/"], + ignores: ["dist/", "node_modules/", ".astro/", "db/migrations/"], }, // Base JavaScript/TypeScript recommended rules diff --git a/package-lock.json b/package-lock.json index 4dd4a4a..605707d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "0.0.1", "dependencies": { "@astrojs/check": "^0.9.9", - "@libsql/client": "^0.17.4", "@tailwindcss/vite": "^4.3.2", "astro": "^7.0.9", "drizzle-orm": "^0.45.2", @@ -30,6 +29,9 @@ "tsx": "^4.23.1", "typescript-eslint": "^8.64.0", "vitest": "^4.1.10" + }, + "engines": { + "node": ">=22.13" } }, "node_modules/@astrojs/check": { @@ -678,8 +680,8 @@ }, "node_modules/@esbuild-kit/core-utils": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", - "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", + "integrity": "sha1-GGtlmKUGbwQTRx18TUWCjjmbqWw=", "deprecated": "Merged into tsx: https://tsx.is", "dev": true, "license": "MIT", @@ -1064,8 +1066,8 @@ }, "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": { "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha1-Rwn1o0gBtDt5mrfW2C9yhKm3p6Y=", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1102,8 +1104,8 @@ }, "node_modules/@esbuild-kit/esm-loader": { "version": "2.6.5", - "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz", - "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz", + "integrity": "sha1-bu3uRgldfROx78OB4iEe0cYOZOo=", "deprecated": "Merged into tsx: https://tsx.is", "dev": true, "license": "MIT", @@ -1719,9 +1721,9 @@ } }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "version": "0.35.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", + "integrity": "sha1-iydAiEvFixJ/wwIEeaASlPoQlcs=", "cpu": [ "arm64" ], @@ -1731,19 +1733,19 @@ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" + "@img/sharp-libvips-darwin-arm64": "1.3.2" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "version": "0.35.3", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", + "integrity": "sha1-kt+RMg+vV8xUszEYV3DVqT1RAEk=", "cpu": [ "x64" ], @@ -1753,19 +1755,38 @@ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" + "@img/sharp-libvips-darwin-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.3", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", + "integrity": "sha1-SAGME3mo9QfWgdbNjb5D2XldyAk=", + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "version": "1.3.2", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", + "integrity": "sha1-IntB/8bJlhK86rpW+ZShkz13lXM=", "cpu": [ "arm64" ], @@ -1779,9 +1800,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "version": "1.3.2", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", + "integrity": "sha1-aUkD7EEMAJRc5bDCbayD1xhMi4Y=", "cpu": [ "x64" ], @@ -1795,12 +1816,15 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "version": "1.3.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", + "integrity": "sha1-5g4IjIBr3hrCi+ZItgw0ZfQcGKc=", "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1811,12 +1835,15 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "version": "1.3.2", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", + "integrity": "sha1-Sd3xVnKGZqId7tBxbzu3K7NRF54=", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1827,12 +1854,15 @@ } }, "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "version": "1.3.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", + "integrity": "sha1-vjFhqv1llBez4mN037vNLaK/tiw=", "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1843,12 +1873,15 @@ } }, "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "version": "1.3.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", + "integrity": "sha1-vwCKZ3nZvitWpN9nt1OUH3Z8lX0=", "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1859,12 +1892,15 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "version": "1.3.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", + "integrity": "sha1-lYOBS421iInIW62eXgt4JSV/85Q=", "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1875,12 +1911,15 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "version": "1.3.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", + "integrity": "sha1-q8mjEUSVtwW6ILfBVoue7NYq67s=", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1891,12 +1930,15 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "version": "1.3.2", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", + "integrity": "sha1-5Y+xSnh58V2ecKmChw84TzmoMqI=", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1907,12 +1949,15 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "version": "1.3.2", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", + "integrity": "sha1-VhFID8t0Zd1TFgRNtTrXqEPtSvg=", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1923,204 +1968,244 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "version": "0.35.3", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", + "integrity": "sha1-yNpQDEAWiTqJ1G6YMtCKBu73fyc=", "cpu": [ "arm" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" + "@img/sharp-libvips-linux-arm": "1.3.2" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "version": "0.35.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", + "integrity": "sha1-RLZYI+zJd9RYWzCAcP/zlHJW3gQ=", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" + "@img/sharp-libvips-linux-arm64": "1.3.2" } }, "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "version": "0.35.3", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", + "integrity": "sha1-6h19uBj1KvHh4FfoLVXyOy3jhkw=", "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" + "@img/sharp-libvips-linux-ppc64": "1.3.2" } }, "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "version": "0.35.3", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", + "integrity": "sha1-civXmUZYeRsC0QN+oJyly3gDDY0=", "cpu": [ "riscv64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" + "@img/sharp-libvips-linux-riscv64": "1.3.2" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "version": "0.35.3", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", + "integrity": "sha1-6ClIF9faSVVBpKhw9W5rXQ+GQ80=", "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" + "@img/sharp-libvips-linux-s390x": "1.3.2" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "version": "0.35.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", + "integrity": "sha1-mEPDLzmurEtg3WD540FlIKTk3kY=", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" + "@img/sharp-libvips-linux-x64": "1.3.2" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "version": "0.35.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", + "integrity": "sha1-nP7k7MPUGrmidOAZ3+e0BihAUQw=", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "version": "0.35.3", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", + "integrity": "sha1-IE0GeMjDsVMA2aJuy5wNzaEcpd4=", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + "@img/sharp-libvips-linuxmusl-x64": "1.3.2" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "version": "0.35.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", + "integrity": "sha1-QviXm9vhpUGi6bmdO1vgfmtxx8A=", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.1" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", + "integrity": "sha1-gjqqk9FNuEmZ1bXcln/1bPGWbZ8=", "cpu": [ "wasm32" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "license": "Apache-2.0", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.7.0" + "@img/sharp-wasm32": "0.35.3" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "version": "0.35.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", + "integrity": "sha1-81VNRcviRTKgrepzbsV2WPdKKRE=", "cpu": [ "arm64" ], @@ -2130,16 +2215,16 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "version": "0.35.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", + "integrity": "sha1-CUKyZDvLV+SEGf5BGd6EB4rgrHQ=", "cpu": [ "ia32" ], @@ -2149,16 +2234,16 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "^20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "version": "0.35.3", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", + "integrity": "sha1-iiXKzcdajCYHfAf7pR6AVqrkdPE=", "cpu": [ "x64" ], @@ -2168,7 +2253,7 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" @@ -2219,165 +2304,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@libsql/client": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@libsql/client/-/client-0.17.4.tgz", - "integrity": "sha512-lYayFWasDV78A+TjlEhr6ubb3odBV6OHjb+wdp8VQcyWWAEIjuwbCHaraEUS4m4yWoo0BvZo96It4VdzZRmRWw==", - "license": "MIT", - "dependencies": { - "@libsql/core": "^0.17.4", - "@libsql/hrana-client": "^0.10.0", - "js-base64": "^3.7.5", - "libsql": "^0.5.28", - "promise-limit": "^2.7.0" - } - }, - "node_modules/@libsql/core": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@libsql/core/-/core-0.17.4.tgz", - "integrity": "sha512-LqF9gIvnJ38nmAH1y/ChizHqDO/MO1wLgA96XrraulEEbqXxLjleSH92YWTolbuJKgPUmGu4aJk9W3UnAcxLOQ==", - "license": "MIT", - "dependencies": { - "js-base64": "^3.7.5" - } - }, - "node_modules/@libsql/darwin-arm64": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@libsql/darwin-arm64/-/darwin-arm64-0.5.29.tgz", - "integrity": "sha512-K+2RIB1OGFPYQbfay48GakLhqf3ArcbHqPFu7EZiaUcRgFcdw8RoltsMyvbj5ix2fY0HV3Q3Ioa/ByvQdaSM0A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@libsql/darwin-x64": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@libsql/darwin-x64/-/darwin-x64-0.5.29.tgz", - "integrity": "sha512-OtT+KFHsKFy1R5FVadr8FJ2Bb1mghtXTyJkxv0trocq7NuHntSki1eUbxpO5ezJesDvBlqFjnWaYYY516QNLhQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@libsql/hrana-client": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@libsql/hrana-client/-/hrana-client-0.10.0.tgz", - "integrity": "sha512-OoA4EMqRAC7kn7V2P6EQqRcpZf2W+AjsNIyCizBg339Tq/aMC7sRnzs3SklderhmQWAqEzvv8A2vhxVmWpkVvw==", - "license": "MIT", - "dependencies": { - "@libsql/isomorphic-ws": "^0.1.5", - "js-base64": "^3.7.5" - } - }, - "node_modules/@libsql/isomorphic-ws": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@libsql/isomorphic-ws/-/isomorphic-ws-0.1.5.tgz", - "integrity": "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==", - "license": "MIT", - "dependencies": { - "@types/ws": "^8.5.4", - "ws": "^8.13.0" - } - }, - "node_modules/@libsql/linux-arm-gnueabihf": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@libsql/linux-arm-gnueabihf/-/linux-arm-gnueabihf-0.5.29.tgz", - "integrity": "sha512-CD4n4zj7SJTHso4nf5cuMoWoMSS7asn5hHygsDuhRl8jjjCTT3yE+xdUvI4J7zsyb53VO5ISh4cwwOtf6k2UhQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@libsql/linux-arm-musleabihf": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@libsql/linux-arm-musleabihf/-/linux-arm-musleabihf-0.5.29.tgz", - "integrity": "sha512-2Z9qBVpEJV7OeflzIR3+l5yAd4uTOLxklScYTwpZnkm2vDSGlC1PRlueLaufc4EFITkLKXK2MWBpexuNJfMVcg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@libsql/linux-arm64-gnu": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@libsql/linux-arm64-gnu/-/linux-arm64-gnu-0.5.29.tgz", - "integrity": "sha512-gURBqaiXIGGwFNEaUj8Ldk7Hps4STtG+31aEidCk5evMMdtsdfL3HPCpvys+ZF/tkOs2MWlRWoSq7SOuCE9k3w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@libsql/linux-arm64-musl": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@libsql/linux-arm64-musl/-/linux-arm64-musl-0.5.29.tgz", - "integrity": "sha512-fwgYZ0H8mUkyVqXZHF3mT/92iIh1N94Owi/f66cPVNsk9BdGKq5gVpoKO+7UxaNzuEH1roJp2QEwsCZMvBLpqg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@libsql/linux-x64-gnu": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@libsql/linux-x64-gnu/-/linux-x64-gnu-0.5.29.tgz", - "integrity": "sha512-y14V0vY0nmMC6G0pHeJcEarcnGU2H6cm21ZceRkacWHvQAEhAG0latQkCtoS2njFOXiYIg+JYPfAoWKbi82rkg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@libsql/linux-x64-musl": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@libsql/linux-x64-musl/-/linux-x64-musl-0.5.29.tgz", - "integrity": "sha512-gquqwA/39tH4pFl+J9n3SOMSymjX+6kZ3kWgY3b94nXFTwac9bnFNMffIomgvlFaC4ArVqMnOZD3nuJ3H3VO1w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@libsql/win32-x64-msvc": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@libsql/win32-x64-msvc/-/win32-x64-msvc-0.5.29.tgz", - "integrity": "sha512-4/0CvEdhi6+KjMxMaVbFM2n2Z44escBRoEYpR+gZg64DdetzGnYm8mcNLcoySaDJZNaBd6wz5DNdgRmcI4hXcg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", @@ -2396,12 +2322,6 @@ "@emnapi/runtime": "^1.7.1" } }, - "node_modules/@neon-rs/load": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@neon-rs/load/-/load-0.0.4.tgz", - "integrity": "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==", - "license": "MIT" - }, "node_modules/@oslojs/encoding": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", @@ -3251,6 +3171,7 @@ "version": "26.1.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz", "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==", + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~8.3.0" @@ -3262,15 +3183,6 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.64.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.64.0.tgz", @@ -3976,9 +3888,9 @@ } }, "node_modules/astro": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/astro/-/astro-7.0.9.tgz", - "integrity": "sha512-WB5pA4LLQnmqjBh6EIu0z8aUV4q2/AoThgSZq57Rsp+oqqvPu7OwZ5eF+W4ku20TUTxIhiJW8dccuGvJPiW2UA==", + "version": "7.1.4", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/astro/-/astro-7.1.4.tgz", + "integrity": "sha1-KMuQ3yDPzT5DDS2Ahz6/6D4+eRI=", "license": "MIT", "dependencies": { "@astrojs/compiler-rs": "^0.3.1", @@ -3995,7 +3907,7 @@ "ci-info": "^4.4.0", "clsx": "^2.1.1", "common-ancestor-path": "^2.0.0", - "cookie": "^1.1.1", + "cookie": "^2.0.1", "devalue": "^5.8.1", "diff": "^8.0.3", "dset": "^3.1.4", @@ -4009,10 +3921,10 @@ "http-cache-semantics": "^4.2.0", "js-yaml": "^4.1.1", "jsonc-parser": "^3.3.1", - "magic-string": "^0.30.21", + "magic-string": "^1.0.0", "magicast": "^0.5.2", "mrmime": "^2.0.1", - "neotraverse": "^0.6.18", + "neotraverse": "^1.0.1", "obug": "^2.1.1", "p-limit": "^7.3.0", "p-queue": "^9.1.0", @@ -4104,6 +4016,15 @@ "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "license": "MIT" }, + "node_modules/astro/node_modules/magic-string": { + "version": "1.1.0", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/magic-string/-/magic-string-1.1.0.tgz", + "integrity": "sha1-VKhHCqvyoEuXAXfybAMIyr6nSj8=", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/astro/node_modules/yargs-parser": { "version": "22.0.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", @@ -4159,16 +4080,16 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "version": "5.0.8", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/brace-expansion/-/brace-expansion-5.0.8.tgz", + "integrity": "sha1-E1rQ2NgI6xjrXg7Joh86C5LvGM8=", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/buffer-from": { @@ -4398,12 +4319,12 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "version": "2.0.1", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha1-H8fpvd84+pVnzU11CCAIfNtdbpg=", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=22" }, "funding": { "type": "opencollective", @@ -4679,8 +4600,8 @@ }, "node_modules/drizzle-kit": { "version": "0.31.10", - "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.31.10.tgz", - "integrity": "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/drizzle-kit/-/drizzle-kit-0.31.10.tgz", + "integrity": "sha1-VWtLqez+CJQj3FM4Y076ns2a/Bo=", "dev": true, "license": "MIT", "dependencies": { @@ -5704,9 +5625,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", - "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "version": "3.1.4", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha1-Oz2vnOaPQflW3wtQUTLAz86ex68=", "funding": [ { "type": "github", @@ -6148,12 +6069,6 @@ "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/js-base64": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.8.0.tgz", - "integrity": "sha512-65kvbemyZhj+ExQt1PEFyBEjL5vAHysu1lJdW1AwhhChkO8ZBPizYk/m9GVrpbS2Je1hF+UYZ+6KywqtZV8mHw==", - "license": "BSD-3-Clause" - }, "node_modules/js-yaml": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", @@ -6235,47 +6150,6 @@ "node": ">= 0.8.0" } }, - "node_modules/libsql": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/libsql/-/libsql-0.5.29.tgz", - "integrity": "sha512-8lMP8iMgiBzzoNbAPQ59qdVcj6UaE/Vnm+fiwX4doX4Narook0a4GPKWBEv+CR8a1OwbfkgL18uBfBjWdF0Fzg==", - "cpu": [ - "x64", - "arm64", - "wasm32", - "arm" - ], - "license": "MIT", - "os": [ - "darwin", - "linux", - "win32" - ], - "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" - } - }, - "node_modules/libsql/node_modules/detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -6762,9 +6636,9 @@ "license": "MIT" }, "node_modules/neotraverse": { - "version": "0.6.18", - "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", - "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", + "version": "1.0.1", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/neotraverse/-/neotraverse-1.0.1.tgz", + "integrity": "sha1-fIm0P2UE74WSjHGPV4xoYhV20ZQ=", "license": "MIT", "engines": { "node": ">= 10" @@ -7161,12 +7035,6 @@ "node": ">=18.0.0" } }, - "node_modules/promise-limit": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/promise-limit/-/promise-limit-2.7.0.tgz", - "integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==", - "license": "ISC" - }, "node_modules/property-information": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", @@ -7356,48 +7224,53 @@ } }, "node_modules/sharp": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", - "hasInstallScript": true, + "version": "0.35.3", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/sharp/-/sharp-0.35.3.tgz", + "integrity": "sha1-Qe0hpGQGvhY+rNC+ezZLQvzyiF8=", "license": "Apache-2.0", "optional": true, "dependencies": { - "@img/colour": "^1.0.0", + "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", - "semver": "^7.7.3" + "semver": "^7.8.5" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5", - "@img/sharp-darwin-x64": "0.34.5", - "@img/sharp-libvips-darwin-arm64": "1.2.4", - "@img/sharp-libvips-darwin-x64": "1.2.4", - "@img/sharp-libvips-linux-arm": "1.2.4", - "@img/sharp-libvips-linux-arm64": "1.2.4", - "@img/sharp-libvips-linux-ppc64": "1.2.4", - "@img/sharp-libvips-linux-riscv64": "1.2.4", - "@img/sharp-libvips-linux-s390x": "1.2.4", - "@img/sharp-libvips-linux-x64": "1.2.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", - "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5", - "@img/sharp-linux-arm64": "0.34.5", - "@img/sharp-linux-ppc64": "0.34.5", - "@img/sharp-linux-riscv64": "0.34.5", - "@img/sharp-linux-s390x": "0.34.5", - "@img/sharp-linux-x64": "0.34.5", - "@img/sharp-linuxmusl-arm64": "0.34.5", - "@img/sharp-linuxmusl-x64": "0.34.5", - "@img/sharp-wasm32": "0.34.5", - "@img/sharp-win32-arm64": "0.34.5", - "@img/sharp-win32-ia32": "0.34.5", - "@img/sharp-win32-x64": "0.34.5" + "@img/sharp-darwin-arm64": "0.35.3", + "@img/sharp-darwin-x64": "0.35.3", + "@img/sharp-freebsd-wasm32": "0.35.3", + "@img/sharp-libvips-darwin-arm64": "1.3.2", + "@img/sharp-libvips-darwin-x64": "1.3.2", + "@img/sharp-libvips-linux-arm": "1.3.2", + "@img/sharp-libvips-linux-arm64": "1.3.2", + "@img/sharp-libvips-linux-ppc64": "1.3.2", + "@img/sharp-libvips-linux-riscv64": "1.3.2", + "@img/sharp-libvips-linux-s390x": "1.3.2", + "@img/sharp-libvips-linux-x64": "1.3.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", + "@img/sharp-libvips-linuxmusl-x64": "1.3.2", + "@img/sharp-linux-arm": "0.35.3", + "@img/sharp-linux-arm64": "0.35.3", + "@img/sharp-linux-ppc64": "0.35.3", + "@img/sharp-linux-riscv64": "0.35.3", + "@img/sharp-linux-s390x": "0.35.3", + "@img/sharp-linux-x64": "0.35.3", + "@img/sharp-linuxmusl-arm64": "0.35.3", + "@img/sharp-linuxmusl-x64": "0.35.3", + "@img/sharp-webcontainers-wasm32": "0.35.3", + "@img/sharp-win32-arm64": "0.35.3", + "@img/sharp-win32-ia32": "0.35.3", + "@img/sharp-win32-x64": "0.35.3" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/shebang-command": { @@ -7536,9 +7409,9 @@ } }, "node_modules/svgo": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", - "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", + "version": "4.0.2", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/svgo/-/svgo-4.0.2.tgz", + "integrity": "sha1-piJG8KnWccAxTQTzzBX3ixvQZn8=", "license": "MIT", "dependencies": { "commander": "^11.1.0", @@ -7796,6 +7669,7 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "devOptional": true, "license": "MIT" }, "node_modules/unified": { @@ -8600,27 +8474,6 @@ "node": ">=0.10.0" } }, - "node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/xxhash-wasm": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", diff --git a/package.json b/package.json index d3949b9..8f25716 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,9 @@ "name": "tailspin-toys", "type": "module", "version": "0.0.1", + "engines": { + "node": ">=22.13" + }, "scripts": { "dev": "astro dev", "build": "astro build", @@ -23,7 +26,6 @@ }, "dependencies": { "@astrojs/check": "^0.9.9", - "@libsql/client": "^0.17.4", "@tailwindcss/vite": "^4.3.2", "astro": "^7.0.9", "drizzle-orm": "^0.45.2", diff --git a/src/lib/db.ts b/src/lib/db.ts index d8ef500..3d84716 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -1,31 +1,91 @@ -import { drizzle, type LibSQLDatabase } from 'drizzle-orm/libsql'; -import { createClient } from '@libsql/client'; +import { DatabaseSync, type SQLInputValue } from 'node:sqlite'; import { mkdirSync } from 'node:fs'; import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { drizzle } from 'drizzle-orm/sqlite-proxy'; +import type { AsyncRemoteCallback, SqliteRemoteDatabase } from 'drizzle-orm/sqlite-proxy'; import * as schema from '../../db/schema'; -export type Database = LibSQLDatabase; +export type Database = SqliteRemoteDatabase; -/** Default local libSQL file used for dev/build when DATABASE_URL is unset. */ -const DEFAULT_DATABASE_URL = 'file:./.data/tailspin.db'; +export interface DatabaseConnection { + db: Database; + sqlite: DatabaseSync; +} + +/** Default local SQLite file used for dev/build when DATABASE_URL is unset. */ +const DEFAULT_DATABASE_URL = 'file:tailspin.db'; let cachedDb: Database | undefined; -/** Ensure the parent directory exists for a local `file:` libSQL URL. */ -function ensureLocalDir(url: string): void { - if (url.startsWith('file:')) { - const filePath = url.slice('file:'.length); - if (filePath && filePath !== ':memory:') { - mkdirSync(dirname(filePath), { recursive: true }); +/** Resolve a local SQLite URL to the path expected by Node's built-in driver. */ +function databasePath(url: string): string { + if (url === ':memory:') { + return url; + } + + if (!url.startsWith('file:')) { + throw new Error('DATABASE_URL must be a local file: URL or :memory:.'); + } + + const filePath = url.startsWith('file://') ? fileURLToPath(url) : url.slice('file:'.length); + if (!filePath) { + throw new Error('DATABASE_URL must include a database file path.'); + } + + mkdirSync(dirname(filePath), { recursive: true }); + return filePath; +} + +/** Bridge Drizzle's async SQLite adapter to Node's synchronous built-in driver. */ +function createRemoteCallback(sqlite: DatabaseSync): AsyncRemoteCallback { + return async (sql: string, params: SQLInputValue[], method: 'run' | 'all' | 'values' | 'get') => { + const statement = sqlite.prepare(sql); + + switch (method) { + case 'run': + statement.run(...params); + return { rows: [] }; + case 'all': + return { rows: statement.all(...params).map((row) => Object.values(row)) }; + case 'values': + return { rows: statement.all(...params).map((row) => Object.values(row)) }; + case 'get': { + const row = statement.get(...params); + // Drizzle's proxy type requires an array, but its get mapper accepts no row. + return { rows: row === undefined ? undefined! : Object.values(row) }; + } + } + }; +} + +/** Run generated migration statements atomically through Node's SQLite driver. */ +export function executeMigrationQueries(sqlite: DatabaseSync, queries: string[]): void { + sqlite.exec('BEGIN'); + try { + for (const query of queries) { + sqlite.exec(query); } + sqlite.exec('COMMIT'); + } catch (error) { + sqlite.exec('ROLLBACK'); + throw error; } } -/** Create a Drizzle client for the given libSQL connection URL. */ +/** Create a Drizzle client for the given local SQLite connection URL. */ export function createDatabase(url: string = process.env.DATABASE_URL ?? DEFAULT_DATABASE_URL): Database { - ensureLocalDir(url); - const client = createClient({ url }); - return drizzle(client, { schema }); + return createDatabaseConnection(url).db; +} + +/** Create the Drizzle client and its Node SQLite connection for migration workflows. */ +export function createDatabaseConnection( + url: string = process.env.DATABASE_URL ?? DEFAULT_DATABASE_URL, +): DatabaseConnection { + const sqlite = new DatabaseSync(databasePath(url)); + sqlite.exec('PRAGMA short_column_names = OFF; PRAGMA full_column_names = ON;'); + const db = drizzle(createRemoteCallback(sqlite), { schema }); + return { db, sqlite }; } /** Shared singleton database client used by pages at build time. */ diff --git a/src/lib/games.ts b/src/lib/games.ts index 65faaad..4ed218e 100644 --- a/src/lib/games.ts +++ b/src/lib/games.ts @@ -64,6 +64,6 @@ export async function getAllGameIds(db: Database): Promise { /** A single game by id, or null when it does not exist. */ export async function getGameById(db: Database, id: number): Promise { - const rows = await baseGamesQuery(db).where(eq(games.id, id)).limit(1); - return rows.length > 0 ? mapGame(rows[0]) : null; + const row = await baseGamesQuery(db).where(eq(games.id, id)).get(); + return row ? mapGame(row) : null; } From f97e257346238f18b179a4ef03967f83dc77a7af Mon Sep 17 00:00:00 2001 From: James Montemagno Date: Mon, 3 Aug 2026 10:47:05 -0700 Subject: [PATCH 2/2] fix: clarify SQLite proxy missing-row type Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 577ec881-eb21-4233-b7ba-5a91e021e274 --- src/lib/db.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/db.ts b/src/lib/db.ts index 3d84716..a574876 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -53,7 +53,7 @@ function createRemoteCallback(sqlite: DatabaseSync): AsyncRemoteCallback { case 'get': { const row = statement.get(...params); // Drizzle's proxy type requires an array, but its get mapper accepts no row. - return { rows: row === undefined ? undefined! : Object.values(row) }; + return { rows: row === undefined ? (undefined as unknown as never[]) : Object.values(row) }; } } };