diff --git a/.env.example b/.env.example index 3b5359da..bf53eb0e 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,6 @@ # When cloning the repository, copy this file as .env # For getting started, you don't need to change any values -CATDAT_DB_URL=file:databases/catdat/catdat.db -CATDAT_DB_AUTH_TOKEN= - APP_DB_URL=file:databases/app/app.db APP_DB_AUTH_TOKEN= diff --git a/.github/workflows/_deploy-reusable.yaml b/.github/workflows/_deploy-reusable.yaml index ccd234c6..de74859f 100644 --- a/.github/workflows/_deploy-reusable.yaml +++ b/.github/workflows/_deploy-reusable.yaml @@ -6,14 +6,7 @@ on: is_prod: required: true type: boolean - skip_db: - required: true - type: boolean secrets: - CATDAT_DB_URL: - required: true - CATDAT_DB_AUTH_TOKEN: - required: true APP_DB_URL: required: true APP_DB_AUTH_TOKEN: @@ -62,30 +55,14 @@ jobs: - name: Install Dependencies run: pnpm i - - name: Generate SvelteKit config - run: pnpm svelte-kit sync - - - name: Create snapshot of local database as static asset - env: - CATDAT_DB_URL: file:databases/catdat/catdat.db - APP_DB_URL: file:databases/app/app.db - run: | - pnpm db:update - pnpm db:snapshot - - - name: Update production database - if: ${{ !inputs.skip_db }} + - name: Build database env: - CATDAT_DB_URL: ${{ secrets.CATDAT_DB_URL }} - CATDAT_DB_AUTH_TOKEN: ${{ secrets.CATDAT_DB_AUTH_TOKEN }} APP_DB_URL: ${{ secrets.APP_DB_URL }} APP_DB_AUTH_TOKEN: ${{ secrets.APP_DB_AUTH_TOKEN }} run: pnpm db:update - name: Build app env: - CATDAT_DB_URL: ${{ secrets.CATDAT_DB_URL }} - CATDAT_DB_AUTH_TOKEN: ${{ secrets.CATDAT_DB_AUTH_TOKEN }} APP_DB_URL: ${{ secrets.APP_DB_URL }} APP_DB_AUTH_TOKEN: ${{ secrets.APP_DB_AUTH_TOKEN }} GITHUB_PRIVATE_KEY: ${{ secrets._GITHUB_PRIVATE_KEY }} diff --git a/.github/workflows/deploy-preview-skip-db.yaml b/.github/workflows/deploy-preview-skip-db.yaml deleted file mode 100644 index 61f7c6ce..00000000 --- a/.github/workflows/deploy-preview-skip-db.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: preview deployment (without db update) -on: - workflow_dispatch: - -jobs: - call-deploy: - uses: ./.github/workflows/_deploy-reusable.yaml - permissions: - contents: write - with: - is_prod: false - skip_db: true - secrets: - CATDAT_DB_URL: ${{ secrets.CATDAT_DB_PREVIEW_URL }} - CATDAT_DB_AUTH_TOKEN: ${{ secrets.CATDAT_DB_PREVIEW_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - NETLIFY_ACCESS_TOKEN: ${{ secrets.NETLIFY_ACCESS_TOKEN }} - APP_DB_URL: ${{ secrets.APP_DB_URL }} - APP_DB_AUTH_TOKEN: ${{ secrets.APP_DB_AUTH_TOKEN }} - _GITHUB_PRIVATE_KEY: ${{ secrets._GITHUB_PRIVATE_KEY }} - REDIS_URL: ${{ secrets.REDIS_URL }} - ADMIN_PAGE_PASSWORD: ${{ secrets.ADMIN_PAGE_PASSWORD }} - EMAIL_ADDRESS: ${{ secrets.EMAIL_ADDRESS }} - EMAIL_PASSWORD: ${{ secrets.EMAIL_PASSWORD }} - ENABLE_EMAILS: ${{ secrets.ENABLE_EMAILS }} - APPROVAL_EMAIL: ${{ secrets.APPROVAL_EMAIL }} diff --git a/.github/workflows/deploy-preview.yaml b/.github/workflows/deploy-preview.yaml index e5328900..6e1cdafe 100644 --- a/.github/workflows/deploy-preview.yaml +++ b/.github/workflows/deploy-preview.yaml @@ -9,18 +9,4 @@ jobs: contents: write with: is_prod: false - skip_db: false - secrets: - CATDAT_DB_URL: ${{ secrets.CATDAT_DB_PREVIEW_URL }} - CATDAT_DB_AUTH_TOKEN: ${{ secrets.CATDAT_DB_PREVIEW_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - NETLIFY_ACCESS_TOKEN: ${{ secrets.NETLIFY_ACCESS_TOKEN }} - APP_DB_URL: ${{ secrets.APP_DB_URL }} - APP_DB_AUTH_TOKEN: ${{ secrets.APP_DB_AUTH_TOKEN }} - _GITHUB_PRIVATE_KEY: ${{ secrets._GITHUB_PRIVATE_KEY }} - REDIS_URL: ${{ secrets.REDIS_URL }} - ADMIN_PAGE_PASSWORD: ${{ secrets.ADMIN_PAGE_PASSWORD }} - EMAIL_ADDRESS: ${{ secrets.EMAIL_ADDRESS }} - EMAIL_PASSWORD: ${{ secrets.EMAIL_PASSWORD }} - ENABLE_EMAILS: ${{ secrets.ENABLE_EMAILS }} - APPROVAL_EMAIL: ${{ secrets.APPROVAL_EMAIL }} + secrets: inherit diff --git a/.github/workflows/deploy-prod-skip-db.yaml b/.github/workflows/deploy-prod-skip-db.yaml deleted file mode 100644 index 3297ce65..00000000 --- a/.github/workflows/deploy-prod-skip-db.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: production deployment (without db update) -on: - workflow_dispatch: - -jobs: - call-deploy: - uses: ./.github/workflows/_deploy-reusable.yaml - permissions: - contents: write - with: - is_prod: true - skip_db: true - secrets: - CATDAT_DB_URL: ${{ secrets.CATDAT_DB_URL }} - CATDAT_DB_AUTH_TOKEN: ${{ secrets.CATDAT_DB_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - NETLIFY_ACCESS_TOKEN: ${{ secrets.NETLIFY_ACCESS_TOKEN }} - APP_DB_URL: ${{ secrets.APP_DB_URL }} - APP_DB_AUTH_TOKEN: ${{ secrets.APP_DB_AUTH_TOKEN }} - _GITHUB_PRIVATE_KEY: ${{ secrets._GITHUB_PRIVATE_KEY }} - REDIS_URL: ${{ secrets.REDIS_URL }} - ADMIN_PAGE_PASSWORD: ${{ secrets.ADMIN_PAGE_PASSWORD }} - EMAIL_ADDRESS: ${{ secrets.EMAIL_ADDRESS }} - EMAIL_PASSWORD: ${{ secrets.EMAIL_PASSWORD }} - ENABLE_EMAILS: ${{ secrets.ENABLE_EMAILS }} - APPROVAL_EMAIL: ${{ secrets.APPROVAL_EMAIL }} diff --git a/.github/workflows/deploy-prod.yaml b/.github/workflows/deploy-prod.yaml index 2d6ad2a5..7ea58620 100644 --- a/.github/workflows/deploy-prod.yaml +++ b/.github/workflows/deploy-prod.yaml @@ -9,18 +9,4 @@ jobs: contents: write with: is_prod: true - skip_db: false - secrets: - CATDAT_DB_URL: ${{ secrets.CATDAT_DB_URL }} - CATDAT_DB_AUTH_TOKEN: ${{ secrets.CATDAT_DB_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - NETLIFY_ACCESS_TOKEN: ${{ secrets.NETLIFY_ACCESS_TOKEN }} - APP_DB_URL: ${{ secrets.APP_DB_URL }} - APP_DB_AUTH_TOKEN: ${{ secrets.APP_DB_AUTH_TOKEN }} - _GITHUB_PRIVATE_KEY: ${{ secrets._GITHUB_PRIVATE_KEY }} - REDIS_URL: ${{ secrets.REDIS_URL }} - ADMIN_PAGE_PASSWORD: ${{ secrets.ADMIN_PAGE_PASSWORD }} - EMAIL_ADDRESS: ${{ secrets.EMAIL_ADDRESS }} - EMAIL_PASSWORD: ${{ secrets.EMAIL_PASSWORD }} - ENABLE_EMAILS: ${{ secrets.ENABLE_EMAILS }} - APPROVAL_EMAIL: ${{ secrets.APPROVAL_EMAIL }} + secrets: inherit diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 53ab4f64..212dd243 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -29,11 +29,5 @@ jobs: - name: Install Dependencies run: pnpm i - - name: Generate SvelteKit config - run: pnpm svelte-kit sync - - name: Update and Test database - env: - CATDAT_DB_URL: file:databases/catdat/catdat.db - APP_DB_URL: file:databases/app/app.db - run: pnpm db:update + run: pnpm db:update:catdat diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aea6fca6..386b19c3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,7 +73,7 @@ to continuously run this update when a file in the subfolder [/databases/catdat/ ### Troubleshooting -- If the local database is corrupted, delete the `catdat.db` file and recreate it using `pnpm db:update`. +- If the local database is corrupted, recreate it using `pnpm db:update`. - If the `pnpm db:update` command fails, examine the error message to determine the cause. It could be due to malformed SQL, a contradictory property, or a failing test in the `pnpm db:test` script (which also runs as part of the update command), as explained below. ### Tests for Data Quality diff --git a/DATABASE.md b/DATABASE.md index 822ff10a..a51ccbae 100644 --- a/DATABASE.md +++ b/DATABASE.md @@ -42,11 +42,11 @@ For functors there are similar tables, such as: - `functor_implications` - `functor_property_assignments` -## Migrations vs. Data +## Schema vs. Data -Migrations update the database structure: tables, views, indexes, and triggers. They are defined in SQL files located in the subfolder [/databases/catdat/migrations](/databases/catdat/migrations/). The command `pnpm db:migrate` applies any new migrations. +The schema defines the structure of the database: tables, views, indexes, and triggers. It is specified in several SQL files located in the subfolder [/databases/catdat/schema](/databases/catdat/schema/). The command `pnpm db:setup` deletes the old database file (if it exists) and creates a new one using this schema. -Database entries (categories, properties, implications, etc.) are defined via SQL files in the subfolder [/databases/catdat/data](/databases/catdat/data). The command `pnpm db:seed` replaces the current database by clearing all existing data and inserting the entries defined in these SQL files. +Database entries (categories, properties, implications, etc.) are defined in SQL files located in the subfolder [/databases/catdat/data](/databases/catdat/data/). The command `pnpm db:seed` replaces the current contents of the database by clearing all existing data and inserting the entries defined in these SQL files. ## Derived Data @@ -60,7 +60,7 @@ The command `pnpm db:test` executes some tests and verifies that the data behave ## One command for everything -Use `pnpm db:update` to run all the commands in sequence: `pnpm db:migrate`, `pnpm db:seed`,`pnpm db:deduce`, and `pnpm db:test`. +Use `pnpm db:update` to run all the commands in sequence: `pnpm db:setup`, `pnpm db:seed`,`pnpm db:deduce`, and `pnpm db:test`. Use `pnpm db:watch` to run this command automatically every time a file in the subfolder [/databases/catdat/data](/databases/catdat/data) changes. This is useful in particular during development. diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index d2c10780..25ac196d 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -1,39 +1,31 @@ # Deployment -This page is only relevant for the maintainer(s) of this project. - -## Hosting - -The application is deployed on [Netlify](https://netlify.com). The database is hosted on [Turso](https://turso.tech). +This page is only relevant to the maintainer(s) of this project. - [GitHub repository](https://github.com/ScriptRaccoon/catdat) - [Netlify project](https://app.netlify.com/sites/catdat/overview) ## Prerendering -Most pages are prerendered for performance reasons. This implies that the database is consumed at build time to generate static HTML pages. The only non-prerendered pages are the search and comparison pages, since they involve a dynamic list of properties and categories. +Most pages are prerendered for performance reasons. This implies that the database is consumed at build time to generate static HTML pages. The only non-prerendered pages are the search and comparison pages, since they involve dynamic lists of properties and categories. + +## Databases -## Preview Database +The CatDat SQLite database `catdat.db` is deployed as a file alongside the web application to Netlify and is located at `/var/task/databases/catdat/catdat.db` after deployment. The file system on Netlify is ephemeral, so this only works because the database is read-only during the runtime of the application. -Since deployment requires running `pnpm db:update`, which temporarily clears all tables in the database, we maintain a separate remote database `catdat-preview` on Turso as a copy of the production database `catdat`. This prevents temporary disruptions and data inconsistencies in production. +However, the SQLite database `app.db` (used for user submissions and page visits) requires writes and is hosted remotely on [Turso](https://turso.tech). ## Deployment Process Follow these steps to deploy to production: -1. **Preview Deployment.** On [GitHub's actions page](https://github.com/ScriptRaccoon/CatDat/actions), manually trigger the preview pipeline [deploy-preview.yaml](.github/workflows/deploy-preview.yaml). - -It updates the remote preview database (`catdat-preview`) via `pnpm db:update`, builds the application, and creates a [deployment preview](https://docs.netlify.com/deploy/deploy-types/deploy-previews/) on Netlify. The production database and application remain unchanged in this step. - -2. **Promote to Production.** If the deployment preview looks correct, promote it to production in [Netlify's Deploys UI](https://app.netlify.com/projects/catdat/deploys). - -The updated application goes live and uses the preview database. +1. **Preview Deployment.** On [GitHub's Actions page](https://github.com/ScriptRaccoon/CatDat/actions), manually trigger the preview pipeline [deploy-preview.yaml](.github/workflows/deploy-preview.yaml). -3. **Production Deployment.** On [GitHub's actions page](https://github.com/ScriptRaccoon/CatDat/actions), manually trigger the pipeline [deploy-prod.yaml](.github/workflows/deploy-prod.yaml). + It creates the database via `pnpm db:update`, builds the application, and creates a [deployment preview](https://docs.netlify.com/deploy/deploy-types/deploy-previews/) on Netlify. For testing purposes, this step can also be used on branches other than `main`. -This pipeline updates the remote production database (`catdat`) via `pnpm db:update` (hence, consolidates it with the preview database `catdat-preview`), builds the application, and deploys it on Netlify. The previous deployment preview is no longer live. +2. **Production Deployment.** If the deployment preview looks correct, on [GitHub's Actions page](https://github.com/ScriptRaccoon/CatDat/actions), manually trigger the pipeline [deploy-prod.yaml](.github/workflows/deploy-prod.yaml). -In case only the application, not the database has been updated since the last production deployment, the pipeline [deploy-prod-skip-db](.github/workflows/deploy-prod-skip-db.yaml) can be used. The preview deployment is not required. + This pipeline creates the database via `pnpm db:update`, builds the application, and deploys it on Netlify. The previous deployment preview is no longer live. Moreover, a tag is created on GitHub. ## Domains diff --git a/README.md b/README.md index 57a903c0..2d930930 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Built with modern web technologies: - Language: [TypeScript](https://www.typescriptlang.org) - Framework: [SvelteKit](https://svelte.dev/docs/kit/introduction) -- Database: [SQLite](https://sqlite.org/) / [Turso](https://turso.tech) +- Database: [SQLite](https://sqlite.org/) - Deployment: [Netlify](https://netlify.com) - Math Rendering: [katex](https://www.npmjs.com/package/katex) diff --git a/databases/app/scripts/migrate.ts b/databases/app/scripts/setup.ts similarity index 94% rename from databases/app/scripts/migrate.ts rename to databases/app/scripts/setup.ts index 8e91efd2..596b8fa1 100644 --- a/databases/app/scripts/migrate.ts +++ b/databases/app/scripts/setup.ts @@ -13,13 +13,13 @@ const db = createClient({ authToken: APP_DB_AUTH_TOKEN, }) -migrate() +setup() /** * Creates the tables in the app database. */ -async function migrate() { - console.info('\n--- Migrate App database ---') +async function setup() { + console.info('\n--- Setup App database ---') await create_visits_table() await create_submissions_table() } diff --git a/databases/catdat/migrations/014_order_assignments.sql b/databases/catdat/migrations/014_order_assignments.sql deleted file mode 100644 index d15ca95f..00000000 --- a/databases/catdat/migrations/014_order_assignments.sql +++ /dev/null @@ -1,35 +0,0 @@ -DROP TABLE category_property_assignments; - -CREATE TABLE category_property_assignments ( - id INTEGER PRIMARY KEY, - category_id TEXT NOT NULL, - property_id TEXT NOT NULL, - is_satisfied INTEGER NOT NULL - CHECK (is_satisfied in (TRUE, FALSE)), - reason TEXT NOT NULL CHECK (length(reason) > 0), - is_deduced INTEGER NOT NULL DEFAULT FALSE - CHECK (is_deduced in (TRUE, FALSE)), - UNIQUE (category_id, property_id), - FOREIGN KEY (category_id) REFERENCES categories (id) ON DELETE CASCADE, - FOREIGN KEY (property_id) REFERENCES category_properties (id) ON DELETE CASCADE -); - -CREATE INDEX idx_property_category ON category_property_assignments (property_id); - -DROP TABLE functor_property_assignments; - -CREATE TABLE functor_property_assignments ( - id INTEGER PRIMARY KEY, - functor_id TEXT NOT NULL, - property_id TEXT NOT NULL, - is_satisfied INTEGER NOT NULL - CHECK (is_satisfied IN (TRUE, FALSE)), - reason TEXT NOT NULL CHECK (length(reason) > 0), - is_deduced INTEGER NOT NULL DEFAULT FALSE - CHECK (is_deduced in (TRUE, FALSE)), - UNIQUE (functor_id, property_id), - FOREIGN KEY (functor_id) REFERENCES functors (id) ON DELETE CASCADE, - FOREIGN KEY (property_id) REFERENCES functor_properties (id) ON DELETE CASCADE -); - -CREATE INDEX idx_property_functor ON functor_property_assignments (property_id); \ No newline at end of file diff --git a/databases/catdat/migrations/001_categories.sql b/databases/catdat/schema/001_categories.sql similarity index 100% rename from databases/catdat/migrations/001_categories.sql rename to databases/catdat/schema/001_categories.sql diff --git a/databases/catdat/migrations/002_tags.sql b/databases/catdat/schema/002_tags.sql similarity index 100% rename from databases/catdat/migrations/002_tags.sql rename to databases/catdat/schema/002_tags.sql diff --git a/databases/catdat/migrations/003_relations.sql b/databases/catdat/schema/003_relations.sql similarity index 100% rename from databases/catdat/migrations/003_relations.sql rename to databases/catdat/schema/003_relations.sql diff --git a/databases/catdat/migrations/004_category-properties.sql b/databases/catdat/schema/004_category-properties.sql similarity index 94% rename from databases/catdat/migrations/004_category-properties.sql rename to databases/catdat/schema/004_category-properties.sql index be511bd7..5b8731d0 100644 --- a/databases/catdat/migrations/004_category-properties.sql +++ b/databases/catdat/schema/004_category-properties.sql @@ -20,6 +20,7 @@ CREATE TABLE related_category_properties ( ); CREATE TABLE category_property_assignments ( + id INTEGER PRIMARY KEY, category_id TEXT NOT NULL, property_id TEXT NOT NULL, is_satisfied INTEGER NOT NULL @@ -27,8 +28,7 @@ CREATE TABLE category_property_assignments ( reason TEXT NOT NULL CHECK (length(reason) > 0), is_deduced INTEGER NOT NULL DEFAULT FALSE CHECK (is_deduced in (TRUE, FALSE)), - position INTEGER NOT NULL DEFAULT 0, - PRIMARY KEY (category_id, property_id), + UNIQUE (category_id, property_id), FOREIGN KEY (category_id) REFERENCES categories (id) ON DELETE CASCADE, FOREIGN KEY (property_id) REFERENCES category_properties (id) ON DELETE CASCADE ); diff --git a/databases/catdat/migrations/005_category-implications.sql b/databases/catdat/schema/005_category-implications.sql similarity index 100% rename from databases/catdat/migrations/005_category-implications.sql rename to databases/catdat/schema/005_category-implications.sql diff --git a/databases/catdat/migrations/006_category-implications-view.sql b/databases/catdat/schema/006_category-implications-view.sql similarity index 100% rename from databases/catdat/migrations/006_category-implications-view.sql rename to databases/catdat/schema/006_category-implications-view.sql diff --git a/databases/catdat/migrations/007_special_objects.sql b/databases/catdat/schema/007_special_objects.sql similarity index 100% rename from databases/catdat/migrations/007_special_objects.sql rename to databases/catdat/schema/007_special_objects.sql diff --git a/databases/catdat/migrations/008_special-morphisms.sql b/databases/catdat/schema/008_special-morphisms.sql similarity index 100% rename from databases/catdat/migrations/008_special-morphisms.sql rename to databases/catdat/schema/008_special-morphisms.sql diff --git a/databases/catdat/migrations/009_functors.sql b/databases/catdat/schema/009_functors.sql similarity index 100% rename from databases/catdat/migrations/009_functors.sql rename to databases/catdat/schema/009_functors.sql diff --git a/databases/catdat/migrations/010_functor-properties.sql b/databases/catdat/schema/010_functor-properties.sql similarity index 93% rename from databases/catdat/migrations/010_functor-properties.sql rename to databases/catdat/schema/010_functor-properties.sql index 7bafe679..256030aa 100644 --- a/databases/catdat/migrations/010_functor-properties.sql +++ b/databases/catdat/schema/010_functor-properties.sql @@ -12,6 +12,7 @@ CREATE TABLE functor_properties ( CREATE UNIQUE INDEX functor_properties_lower_id_unique ON functor_properties (lower(id)); CREATE TABLE functor_property_assignments ( + id INTEGER PRIMARY KEY, functor_id TEXT NOT NULL, property_id TEXT NOT NULL, is_satisfied INTEGER NOT NULL @@ -19,8 +20,7 @@ CREATE TABLE functor_property_assignments ( reason TEXT NOT NULL CHECK (length(reason) > 0), is_deduced INTEGER NOT NULL DEFAULT FALSE CHECK (is_deduced in (TRUE, FALSE)), - position INTEGER NOT NULL DEFAULT 0, - PRIMARY KEY (functor_id, property_id), + UNIQUE (functor_id, property_id), FOREIGN KEY (functor_id) REFERENCES functors (id) ON DELETE CASCADE, FOREIGN KEY (property_id) REFERENCES functor_properties (id) ON DELETE CASCADE ); diff --git a/databases/catdat/migrations/011_functor-implications.sql b/databases/catdat/schema/011_functor-implications.sql similarity index 100% rename from databases/catdat/migrations/011_functor-implications.sql rename to databases/catdat/schema/011_functor-implications.sql diff --git a/databases/catdat/migrations/012_functor-implications-view.sql b/databases/catdat/schema/012_functor-implications-view.sql similarity index 100% rename from databases/catdat/migrations/012_functor-implications-view.sql rename to databases/catdat/schema/012_functor-implications-view.sql diff --git a/databases/catdat/migrations/013_lemmas.sql b/databases/catdat/schema/013_lemmas.sql similarity index 100% rename from databases/catdat/migrations/013_lemmas.sql rename to databases/catdat/schema/013_lemmas.sql diff --git a/databases/catdat/migrations/015_property_comments.sql b/databases/catdat/schema/014_property_comments.sql similarity index 100% rename from databases/catdat/migrations/015_property_comments.sql rename to databases/catdat/schema/014_property_comments.sql diff --git a/databases/catdat/scripts/deduce-category-implications.ts b/databases/catdat/scripts/deduce-category-implications.ts index 4117c1e3..15413693 100644 --- a/databases/catdat/scripts/deduce-category-implications.ts +++ b/databases/catdat/scripts/deduce-category-implications.ts @@ -1,21 +1,21 @@ -import type { Client } from '@libsql/client' import { are_equal_sets } from './shared' +import { type Database } from 'better-sqlite3' /** * Deduces implications from given ones. */ -export async function deduce_category_implications(db: Client) { +export function deduce_category_implications(db: Database) { console.info('\n--- Deduce category implications ---') - await clear_deduced_category_implications(db) - await create_dualized_category_implications(db) - await create_self_dual_category_implications(db) + clear_deduced_category_implications(db) + create_dualized_category_implications(db) + create_self_dual_category_implications(db) } /** * Clears all deduced implications. This is done as a first step. */ -async function clear_deduced_category_implications(db: Client) { - await db.execute(`DELETE FROM category_implications WHERE is_deduced = TRUE`) +function clear_deduced_category_implications(db: Database) { + db.prepare(`DELETE FROM category_implications WHERE is_deduced = TRUE`).run() } /** @@ -23,29 +23,8 @@ async function clear_deduced_category_implications(db: Client) { * (in case they have a dual). For example, if P ===> Q holds, * then P^op ===> Q^op holds as well. */ -async function create_dualized_category_implications(db: Client) { - const res = await db.execute(` - SELECT - v.id, - v.assumptions, - v.conclusions, - v.is_equivalence, - v.reason, - ( - SELECT json_group_array(p.dual_property_id) - FROM json_each(v.assumptions) a - JOIN category_properties p ON p.id = a.value - ) AS dual_assumptions, - ( - SELECT json_group_array(p.dual_property_id) - FROM json_each(v.conclusions) c - JOIN category_properties p ON p.id = c.value - ) AS dual_conclusions - FROM category_implications_view v - WHERE v.is_deduced = FALSE - `) - - const implications = res.rows as unknown as { +function create_dualized_category_implications(db: Database) { + type FullImplication = { id: string assumptions: string conclusions: string @@ -53,7 +32,30 @@ async function create_dualized_category_implications(db: Client) { dual_conclusions: string is_equivalence: number reason: string - }[] + } + + const implications = db + .prepare( + `SELECT + v.id, + v.assumptions, + v.conclusions, + v.is_equivalence, + v.reason, + ( + SELECT json_group_array(p.dual_property_id) + FROM json_each(v.assumptions) a + JOIN category_properties p ON p.id = a.value + ) AS dual_assumptions, + ( + SELECT json_group_array(p.dual_property_id) + FROM json_each(v.conclusions) c + JOIN category_properties p ON p.id = c.value + ) AS dual_conclusions + FROM category_implications_view v + WHERE v.is_deduced = FALSE`, + ) + .all() as FullImplication[] const dualizable_implications = implications.filter((impl) => { const has_null = @@ -72,10 +74,10 @@ async function create_dualized_category_implications(db: Client) { ) }) - await db.batch( - dualizable_implications.map((impl) => ({ - sql: ` - INSERT INTO category_implications_view ( + const insert_duals = db.transaction(() => { + for (const impl of dualizable_implications) { + db.prepare( + `INSERT INTO category_implications_view ( id, assumptions, conclusions, @@ -83,20 +85,19 @@ async function create_dualized_category_implications(db: Client) { reason, is_deduced, dualized_from - ) VALUES (?, ?, ?, ?, ?, ?, ?)`, - args: [ + ) VALUES (?, ?, ?, ?, ?, TRUE, ?)`, + ).run( `dual_${impl.id}`, impl.dual_assumptions, impl.dual_conclusions, impl.is_equivalence, 'This follows from the dual implication.', - true, impl.id, - ], - })), - 'write', - ) + ) + } + }) + insert_duals() console.info(`Deduced ${dualizable_implications.length} implications by duality`) } @@ -104,32 +105,34 @@ async function create_dualized_category_implications(db: Client) { * Creates all trivial implications of the form * self-dual + P ===> P^op */ -async function create_self_dual_category_implications(db: Client) { - const { rows } = await db.execute(` - INSERT INTO category_implications_view ( - id, - assumptions, - conclusions, - is_equivalence, - reason, - is_deduced - ) - SELECT - 'self-dual_' || p.id, - json_array('self-dual', p.id), - json_array(p.dual_property_id), - FALSE, - 'This holds by self-duality.', - TRUE - FROM - category_properties p - WHERE - p.dual_property_id IS NOT NULL - AND p.id != 'self-dual' - AND p.id != p.dual_property_id - AND p.invariant_under_equivalences = TRUE - RETURNING id - `) +function create_self_dual_category_implications(db: Database) { + const rows = db + .prepare( + `INSERT INTO category_implications_view ( + id, + assumptions, + conclusions, + is_equivalence, + reason, + is_deduced + ) + SELECT + 'self-dual_' || p.id, + json_array('self-dual', p.id), + json_array(p.dual_property_id), + FALSE, + 'This holds by self-duality.', + TRUE + FROM + category_properties p + WHERE + p.dual_property_id IS NOT NULL + AND p.id != 'self-dual' + AND p.id != p.dual_property_id + AND p.invariant_under_equivalences = TRUE + RETURNING id`, + ) + .all() console.info(`Deduced ${rows.length} implications by self-duality`) } diff --git a/databases/catdat/scripts/deduce-category-properties.ts b/databases/catdat/scripts/deduce-category-properties.ts index e8757771..34f26604 100644 --- a/databases/catdat/scripts/deduce-category-properties.ts +++ b/databases/catdat/scripts/deduce-category-properties.ts @@ -1,4 +1,4 @@ -import { type Transaction, type Client, LibsqlError } from '@libsql/client' +import { SqliteError, type Database } from 'better-sqlite3' import { get_assumption_string, get_conclusion_string, @@ -24,30 +24,28 @@ type CategoryPropertyMeta = { * Deduce properties of categories from given ones * by using the list of implications. */ -export async function deduce_category_properties(db: Client) { +export function deduce_category_properties(db: Database) { console.info('\n--- Deduce category properties ---') - const tx = await db.transaction() + const implications = get_normalized_category_implications(db) + const categories = get_categories(db) + const properties_dict = get_properties_dict(db) - try { - const implications = await get_normalized_category_implications(tx) - const categories = await get_categories(tx) - const properties_dict = await get_properties_dict(tx) + const deduction = db.transaction(() => { + delete_deduced_category_properties(db) - await delete_deduced_category_properties(tx) - - const decided_properties = await get_all_decided_properties(tx, categories) + const decided_properties = get_all_decided_properties(db, categories) for (const category of categories) { - await deduce_satisfied_category_properties( - tx, + deduce_satisfied_category_properties( + db, category.id, implications, decided_properties[category.id].satisfied, properties_dict, ) - await deduce_unsatisfied_category_properties( - tx, + deduce_unsatisfied_category_properties( + db, category.id, implications, decided_properties[category.id].satisfied, @@ -64,8 +62,8 @@ export async function deduce_category_properties(db: Client) { continue } - await deduce_dual_category_properties( - tx, + deduce_dual_category_properties( + db, category, decided_properties[category.id].satisfied, decided_properties[category.id].unsatisfied, @@ -74,16 +72,16 @@ export async function deduce_category_properties(db: Client) { properties_dict, ) - await deduce_satisfied_category_properties( - tx, + deduce_satisfied_category_properties( + db, category.id, implications, decided_properties[category.id].satisfied, properties_dict, { check_conflicts: false }, ) - await deduce_unsatisfied_category_properties( - tx, + deduce_unsatisfied_category_properties( + db, category.id, implications, decided_properties[category.id].satisfied, @@ -92,13 +90,9 @@ export async function deduce_category_properties(db: Client) { { check_conflicts: false }, ) } + }) - await tx.commit() - } catch (err) { - console.error(err) - await tx.rollback() - process.exit(1) - } + deduction() } /** @@ -115,19 +109,19 @@ export async function deduce_category_properties(db: Client) { * * P_1 + ... + P_n ----> Q */ -async function get_normalized_category_implications( - tx: Transaction, -): Promise { - const res = await tx.execute(` - SELECT - v.id, - v.assumptions, - v.conclusions, - v.is_equivalence - FROM category_implications_view v - `) - - const all_implications_db = res.rows as unknown as { +function get_normalized_category_implications( + db: Database, +): NormalizedCategoryImplication[] { + const all_implications_db = db + .prepare( + `SELECT + v.id, + v.assumptions, + v.conclusions, + v.is_equivalence + FROM category_implications_view v`, + ) + .all() as { id: string assumptions: string conclusions: string @@ -165,31 +159,33 @@ async function get_normalized_category_implications( /** * Returns the list of categories saved in the database. */ -async function get_categories(tx: Transaction) { - const res = await tx.execute(` - SELECT id, name, dual_category_id - FROM categories ORDER BY lower(name) - `) - return res.rows as unknown as CategoryMeta[] +function get_categories(db: Database) { + return db + .prepare( + `SELECT id, name, dual_category_id + FROM categories ORDER BY lower(name)`, + ) + .all() as CategoryMeta[] } /** * Returns a dictionary of properties saved in the database. */ -async function get_properties_dict(tx: Transaction) { - const res = await tx.execute(` - SELECT - p.id, p.dual_property_id, p.relation, - r.negation, r.conditional - FROM category_properties p - INNER JOIN relations r ON r.relation = p.relation - ORDER BY lower(p.id) - `) - const rows = res.rows as unknown as CategoryPropertyMeta[] +function get_properties_dict(db: Database) { + const properties = db + .prepare( + `SELECT + p.id, p.dual_property_id, p.relation, + r.negation, r.conditional + FROM category_properties p + INNER JOIN relations r ON r.relation = p.relation + ORDER BY lower(p.id)`, + ) + .all() as CategoryPropertyMeta[] const dict: Record = {} - for (const p of rows) dict[p.id] = p + for (const p of properties) dict[p.id] = p return dict } @@ -198,28 +194,21 @@ async function get_properties_dict(tx: Transaction) { * Clears all the deduced properties. * This runs before the deduction starts. */ -async function delete_deduced_category_properties(tx: Transaction) { - await tx.execute(` - DELETE FROM category_property_assignments - WHERE is_deduced = TRUE - `) +function delete_deduced_category_properties(db: Database) { + db.prepare(`DELETE FROM category_property_assignments WHERE is_deduced = TRUE`).run() } /** * Returns a dictionary with all properties that are satisfied or unsatisfied, * grouped by category and value. */ -async function get_all_decided_properties(tx: Transaction, categories: { id: string }[]) { - const res = await tx.execute(` - SELECT property_id, category_id, is_satisfied - FROM category_property_assignments - `) - - const rows = res.rows as unknown as { - property_id: string - category_id: string - is_satisfied: boolean - }[] +function get_all_decided_properties(db: Database, categories: { id: string }[]) { + const rows = db + .prepare( + `SELECT property_id, category_id, is_satisfied + FROM category_property_assignments`, + ) + .all() as { property_id: string; category_id: string; is_satisfied: boolean }[] const grouped: Record; unsatisfied: Set }> = {} @@ -230,11 +219,7 @@ async function get_all_decided_properties(tx: Transaction, categories: { id: str for (const row of rows) { const { property_id, category_id, is_satisfied } = row - if (is_satisfied) { - grouped[category_id].satisfied.add(property_id) - } else { - grouped[category_id].unsatisfied.add(property_id) - } + grouped[category_id][is_satisfied ? 'satisfied' : 'unsatisfied'].add(property_id) } return grouped @@ -244,8 +229,8 @@ async function get_all_decided_properties(tx: Transaction, categories: { id: str * Deduce satisfied properties for a given category from given ones * by using the list of normalized implications. */ -async function deduce_satisfied_category_properties( - tx: Transaction, +function deduce_satisfied_category_properties( + db: Database, category_id: string, implications: NormalizedCategoryImplication[], satisfied_properties: Set, @@ -298,9 +283,9 @@ async function deduce_satisfied_category_properties( ` try { - await tx.execute({ sql: insert_sql, args: values }) + db.prepare(insert_sql).run(values) } catch (err) { - if (err instanceof LibsqlError) { + if (err instanceof SqliteError) { if (err.code.startsWith('SQLITE_CONSTRAINT')) { console.error( `❌ Failed to complete deduction of satisfied properties for ${category_id} because of a conflict. The likely cause is a contradiction between its assigned properties.`, @@ -323,8 +308,8 @@ async function deduce_satisfied_category_properties( * Deduce unsatisfied properties for a given category from given ones * by using the satisfied properties and the list of normalized implications. */ -async function deduce_unsatisfied_category_properties( - tx: Transaction, +function deduce_unsatisfied_category_properties( + db: Database, category_id: string, implications: NormalizedCategoryImplication[], satisfied_properties: Set, @@ -408,9 +393,9 @@ async function deduce_unsatisfied_category_properties( ` try { - await tx.execute({ sql: insert_query, args: values }) + db.prepare(insert_query).run(values) } catch (err) { - if (err instanceof LibsqlError) { + if (err instanceof SqliteError) { if (err.code.startsWith('SQLITE_CONSTRAINT')) { console.error( `❌ Failed to complete deduction of unsatisfied properties for ${category_id} because of a conflict. The likely cause is a contradiction between its assigned properties.`, @@ -433,8 +418,8 @@ async function deduce_unsatisfied_category_properties( * Assign dual properties to dual categories: * If C has property P, then C^op has property P^op (if defined). */ -async function deduce_dual_category_properties( - tx: Transaction, +function deduce_dual_category_properties( + db: Database, category: CategoryMeta, satisfied: Set, unsatisfied: Set, @@ -474,7 +459,7 @@ async function deduce_dual_category_properties( (category_id, property_id, is_satisfied, reason, is_deduced) VALUES ${value_fragments.join(',\n')}` - await tx.execute({ sql: insert_query, args: values }) + db.prepare(insert_query).run(values) console.info( `Deduced ${new_satisfied.size} satisfied properties by duality for ${category.id}`, @@ -499,7 +484,7 @@ async function deduce_dual_category_properties( (category_id, property_id, is_satisfied, reason, is_deduced) VALUES ${value_fragments.join(',\n')}` - await tx.execute({ sql: insert_query, args: values }) + db.prepare(insert_query).run(values) console.info( `Deduced ${new_unsatisfied.size} unsatisfied properties by duality for ${category.id}`, diff --git a/databases/catdat/scripts/deduce-functor-implications.ts b/databases/catdat/scripts/deduce-functor-implications.ts index d67b0980..7d8f986a 100644 --- a/databases/catdat/scripts/deduce-functor-implications.ts +++ b/databases/catdat/scripts/deduce-functor-implications.ts @@ -1,4 +1,5 @@ -import type { Client } from '@libsql/client' +import { type Database } from 'better-sqlite3' + import { are_equal_sets } from './shared' // TODO: remove code duplication with category implication deduction script @@ -6,17 +7,17 @@ import { are_equal_sets } from './shared' /** * Deduces functor implications from given ones. */ -export async function deduce_functor_implications(db: Client) { +export function deduce_functor_implications(db: Database) { console.info('\n--- Deduce functor implications ---') - await clear_deduced_functor_implications(db) - await create_dualized_functor_implications(db) + clear_deduced_functor_implications(db) + create_dualized_functor_implications(db) } /** * Clears all deduced functor implications. This is done as a first step. */ -async function clear_deduced_functor_implications(db: Client) { - await db.execute(`DELETE FROM functor_implications WHERE is_deduced = TRUE`) +function clear_deduced_functor_implications(db: Database) { + db.prepare(`DELETE FROM functor_implications WHERE is_deduced = TRUE`).run() } /** @@ -25,39 +26,8 @@ async function clear_deduced_functor_implications(db: Client) { * then P^op ===> Q^op holds as well. The assumptions of source and target * categories (if any) need to be dualized as well. */ -async function create_dualized_functor_implications(db: Client) { - const res = await db.execute(` - SELECT - v.id, - v.assumptions, - v.conclusions, - v.is_equivalence, - v.reason, - ( - SELECT json_group_array(p.dual_property_id) - FROM json_each(v.assumptions) a - JOIN functor_properties p ON p.id = a.value - ) AS dual_assumptions, - ( - SELECT json_group_array(p.dual_property_id) - FROM json_each(v.source_assumptions) sa - JOIN category_properties p ON p.id = sa.value - ) AS dual_source_assumptions, - ( - SELECT json_group_array(p.dual_property_id) - FROM json_each(v.target_assumptions) ta - JOIN category_properties p ON p.id = ta.value - ) AS dual_target_assumptions, - ( - SELECT json_group_array(p.dual_property_id) - FROM json_each(v.conclusions) c - JOIN functor_properties p ON p.id = c.value - ) AS dual_conclusions - FROM functor_implications_view v - WHERE v.is_deduced = FALSE - `) - - const implications = res.rows as unknown as { +function create_dualized_functor_implications(db: Database) { + type FullImplication = { id: string assumptions: string conclusions: string @@ -67,7 +37,40 @@ async function create_dualized_functor_implications(db: Client) { dual_conclusions: string is_equivalence: number reason: string - }[] + } + + const implications = db + .prepare( + `SELECT + v.id, + v.assumptions, + v.conclusions, + v.is_equivalence, + v.reason, + ( + SELECT json_group_array(p.dual_property_id) + FROM json_each(v.assumptions) a + JOIN functor_properties p ON p.id = a.value + ) AS dual_assumptions, + ( + SELECT json_group_array(p.dual_property_id) + FROM json_each(v.source_assumptions) sa + JOIN category_properties p ON p.id = sa.value + ) AS dual_source_assumptions, + ( + SELECT json_group_array(p.dual_property_id) + FROM json_each(v.target_assumptions) ta + JOIN category_properties p ON p.id = ta.value + ) AS dual_target_assumptions, + ( + SELECT json_group_array(p.dual_property_id) + FROM json_each(v.conclusions) c + JOIN functor_properties p ON p.id = c.value + ) AS dual_conclusions + FROM functor_implications_view v + WHERE v.is_deduced = FALSE`, + ) + .all() as FullImplication[] const dualizable_implications = implications.filter((impl) => { const has_null = @@ -89,21 +92,21 @@ async function create_dualized_functor_implications(db: Client) { ) }) - await db.batch( - dualizable_implications.map((impl) => ({ - sql: ` - INSERT INTO functor_implications_view ( - id, - assumptions, - source_assumptions, - target_assumptions, - conclusions, - is_equivalence, - reason, - dualized_from, - is_deduced - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, TRUE)`, - args: [ + const insert_duals = db.transaction(() => { + for (const impl of dualizable_implications) { + db.prepare( + `INSERT INTO functor_implications_view ( + id, + assumptions, + source_assumptions, + target_assumptions, + conclusions, + is_equivalence, + reason, + dualized_from, + is_deduced + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, TRUE)`, + ).run( `dual_${impl.id}`, impl.dual_assumptions, impl.dual_source_assumptions, @@ -112,10 +115,10 @@ async function create_dualized_functor_implications(db: Client) { impl.is_equivalence, 'This follows from the dual implication.', impl.id, - ], - })), - 'write', - ) + ) + } + }) + insert_duals() console.info(`Deduced ${dualizable_implications.length} implications by duality`) } diff --git a/databases/catdat/scripts/deduce-functor-properties.ts b/databases/catdat/scripts/deduce-functor-properties.ts index ef0c4c5a..3a729bca 100644 --- a/databases/catdat/scripts/deduce-functor-properties.ts +++ b/databases/catdat/scripts/deduce-functor-properties.ts @@ -1,4 +1,4 @@ -import type { Transaction, Client } from '@libsql/client' +import { type Database } from 'better-sqlite3' import { get_assumption_string, get_conclusion_string, @@ -32,39 +32,33 @@ type FunctorPropertyMeta = { * Deduce properties of functors from given ones * by using the list of functor implications. */ -export async function deduce_functor_properties(db: Client) { +export function deduce_functor_properties(db: Database) { console.info('\n--- Deduce functor properties ---') - const tx = await db.transaction() - try { - const implications = await get_normalized_functor_implications(tx) + const implications = get_normalized_functor_implications(db) + const functors = get_functors(db) + const properties_dict = get_functor_properties_dict(db) - const functors = await get_functors(tx) - const properties_dict = await get_functor_properties_dict(tx) - - await delete_deduced_functor_properties(tx) + const deduction = db.transaction(() => { + delete_deduced_functor_properties(db) for (const functor of functors) { - await deduce_satisfied_functor_properties( - tx, + deduce_satisfied_functor_properties( + db, functor, implications, properties_dict, ) - await deduce_unsatisfied_functor_properties( - tx, + deduce_unsatisfied_functor_properties( + db, functor, implications, properties_dict, ) } + }) - await tx.commit() - } catch (err) { - console.error(err) - await tx.rollback() - process.exit(1) - } + deduction() } /** @@ -81,21 +75,21 @@ export async function deduce_functor_properties(db: Client) { * * P_1 + ... + P_n ----> Q */ -async function get_normalized_functor_implications( - tx: Transaction, -): Promise { - const res = await tx.execute(` - SELECT - v.id, - v.assumptions, - v.source_assumptions, - v.target_assumptions, - v.conclusions, - v.is_equivalence - FROM functor_implications_view v - `) - - const all_implications_db = res.rows as unknown as { +function get_normalized_functor_implications( + db: Database, +): NormalizedFunctorImplication[] { + const all_implications_db = db + .prepare( + `SELECT + v.id, + v.assumptions, + v.source_assumptions, + v.target_assumptions, + v.conclusions, + v.is_equivalence + FROM functor_implications_view v`, + ) + .all() as { id: string assumptions: string source_assumptions: string @@ -142,32 +136,38 @@ async function get_normalized_functor_implications( * Returns the list of functors saved in the database along with * the satisfied properties of their source and target category. */ -async function get_functors(tx: Transaction) { - const res = await tx.execute(` - SELECT - id, - name, - source, - target, - ( - SELECT json_group_array(property_id) FROM ( - SELECT property_id - FROM category_property_assignments - WHERE category_id = source AND is_satisfied = TRUE - ) - ) as source_props, - ( - SELECT json_group_array(property_id) FROM ( - SELECT property_id - FROM category_property_assignments - WHERE category_id = target AND is_satisfied = TRUE - ) - ) as target_props - FROM functors - ORDER BY lower(name) - `) - - return res.rows.map((row) => ({ +function get_functors(db: Database) { + const rows = db + .prepare( + `SELECT + id, name, source, target, + ( + SELECT json_group_array(property_id) FROM ( + SELECT property_id + FROM category_property_assignments + WHERE category_id = source AND is_satisfied = TRUE + ) + ) as source_props, + ( + SELECT json_group_array(property_id) FROM ( + SELECT property_id + FROM category_property_assignments + WHERE category_id = target AND is_satisfied = TRUE + ) + ) as target_props + FROM functors + ORDER BY lower(name)`, + ) + .all() as { + id: string + name: string + source: string + target: string + source_props: string + target_props: string + }[] + + return rows.map((row) => ({ id: row.id, name: row.name, source: row.source, @@ -180,20 +180,21 @@ async function get_functors(tx: Transaction) { /** * Returns a dictionary of functor properties saved in the database. */ -async function get_functor_properties_dict(tx: Transaction) { - const res = await tx.execute(` - SELECT - p.id, p.dual_property_id, p.relation, - r.negation, r.conditional - FROM functor_properties p - INNER JOIN relations r ON r.relation = p.relation - ORDER BY lower(p.id) - `) - const rows = res.rows as unknown as FunctorPropertyMeta[] +function get_functor_properties_dict(db: Database) { + const properties = db + .prepare( + `SELECT + p.id, p.dual_property_id, p.relation, + r.negation, r.conditional + FROM functor_properties p + INNER JOIN relations r ON r.relation = p.relation + ORDER BY lower(p.id)`, + ) + .all() as FunctorPropertyMeta[] const dict: Record = {} - for (const p of rows) dict[p.id] = p + for (const p of properties) dict[p.id] = p return dict } @@ -202,42 +203,41 @@ async function get_functor_properties_dict(tx: Transaction) { * Clears all the deduced functor properties. * This runs before the deduction starts. */ -async function delete_deduced_functor_properties(tx: Transaction) { - await tx.execute('DELETE FROM functor_property_assignments WHERE is_deduced = TRUE') +function delete_deduced_functor_properties(db: Database) { + db.prepare('DELETE FROM functor_property_assignments WHERE is_deduced = TRUE').run() } /** * Returns the list of properties that are satisfied or unsatisfied * for a given functor. */ -async function get_decided_functor_properties( - tx: Transaction, +function get_decided_functor_properties( + db: Database, functor_id: string, value: boolean, ) { - const res = await tx.execute({ - sql: ` - SELECT property_id + const rows = db + .prepare( + `SELECT property_id FROM functor_property_assignments - WHERE functor_id = ? AND is_satisfied = ? - `, - args: [functor_id, value], - }) + WHERE functor_id = ? AND is_satisfied = ?`, + ) + .all(functor_id, value ? 1 : 0) as { property_id: string }[] - return new Set(res.rows.map((row) => row.property_id) as string[]) + return new Set(rows.map((row) => row.property_id) as string[]) } /** * Deduce satisfied properties for a given functor from given ones * by using the list of normalized implications. */ -async function deduce_satisfied_functor_properties( - tx: Transaction, +function deduce_satisfied_functor_properties( + db: Database, functor: FunctorMeta, implications: NormalizedFunctorImplication[], properties_dict: Record, ) { - const satisfied_props = await get_decided_functor_properties(tx, functor.id, true) + const satisfied_props = get_decided_functor_properties(db, functor.id, true) const deduced_satisfied_props: string[] = [] const reasons: Record = {} @@ -283,7 +283,7 @@ async function deduce_satisfied_functor_properties( ${value_fragments.join(',\n')} ` - await tx.execute({ sql: insert_sql, args: values }) + db.prepare(insert_sql).run(values) } console.info( @@ -295,14 +295,14 @@ async function deduce_satisfied_functor_properties( * Deduce unsatisfied properties for a given functor from given ones * by using the satisfied properties and the list of normalized implications. */ -async function deduce_unsatisfied_functor_properties( - tx: Transaction, +function deduce_unsatisfied_functor_properties( + db: Database, functor: FunctorMeta, implications: NormalizedFunctorImplication[], properties_dict: Record, ) { - const satisfied_props = await get_decided_functor_properties(tx, functor.id, true) - const unsatisfied_props = await get_decided_functor_properties(tx, functor.id, false) + const satisfied_props = get_decided_functor_properties(db, functor.id, true) + const unsatisfied_props = get_decided_functor_properties(db, functor.id, false) const deduced_unsatisfied_props: string[] = [] const reasons: Record = {} @@ -371,7 +371,7 @@ async function deduce_unsatisfied_functor_properties( VALUES ${value_fragments.join(',\n')}` - await tx.execute({ sql: insert_query, args: values }) + db.prepare(insert_query).run(values) } console.info( diff --git a/databases/catdat/scripts/deduce-special-morphisms.ts b/databases/catdat/scripts/deduce-special-morphisms.ts index 1a10db61..81ec617c 100644 --- a/databases/catdat/scripts/deduce-special-morphisms.ts +++ b/databases/catdat/scripts/deduce-special-morphisms.ts @@ -1,20 +1,22 @@ -import type { Client } from '@libsql/client' +import { type Database } from 'better-sqlite3' // TODO: deduce further morphisms, // e.g. isomorphisms = bijective morphisms in algebraic categories, // e.g. regular monomorphisms = same as monomorphisms in mono-regular categories -export async function deduce_special_morphisms(db: Client) { +export function deduce_special_morphisms(db: Database) { console.info('\n--- Deduce special morphisms ---') - await deduce_special_morphisms_of_dual_categories(db) + deduce_special_morphisms_of_dual_categories(db) } /** * Deduce special morphisms in dual categories. * For example, monomorphisms in C describe epimorphisms in C^op. */ -async function deduce_special_morphisms_of_dual_categories(db: Client) { - const res = await db.execute(` +function deduce_special_morphisms_of_dual_categories(db: Database) { + const res = db + .prepare( + ` INSERT INTO special_morphisms (category_id, type, description, reason) SELECT c.dual_category_id, @@ -26,7 +28,9 @@ async function deduce_special_morphisms_of_dual_categories(db: Client) { INNER JOIN special_morphism_types t ON t.type = m.type WHERE c.dual_category_id IS NOT NULL ON CONFLICT DO NOTHING - `) + `, + ) + .run() - console.info(`Deduced ${res.rowsAffected} special morphisms by duality`) + console.info(`Deduced ${res.changes} special morphisms by duality`) } diff --git a/databases/catdat/scripts/deduce-special-objects.ts b/databases/catdat/scripts/deduce-special-objects.ts index 19bb0970..52ff5d2e 100644 --- a/databases/catdat/scripts/deduce-special-objects.ts +++ b/databases/catdat/scripts/deduce-special-objects.ts @@ -1,27 +1,29 @@ -import type { Client } from '@libsql/client' +import { type Database } from 'better-sqlite3' -export async function deduce_special_objects(db: Client) { +export function deduce_special_objects(db: Database) { console.info('\n--- Deduce special objects ---') - await deduce_special_objects_of_dual_categories(db) + deduce_special_objects_of_dual_categories(db) } /** * Deduce special objects in dual categories. * For example, initial objects in C describe the terminal objects in C^op. */ -async function deduce_special_objects_of_dual_categories(db: Client) { - const res = await db.execute(` - INSERT INTO special_objects (category_id, type, description) - SELECT - c.dual_category_id, - t.dual, - o.description - FROM categories c - INNER JOIN special_objects o ON o.category_id = c.id - INNER JOIN special_object_types t ON t.type = o.type - WHERE c.dual_category_id IS NOT NULL - ON CONFLICT DO NOTHING - `) +async function deduce_special_objects_of_dual_categories(db: Database) { + const res = db + .prepare( + `INSERT INTO special_objects (category_id, type, description) + SELECT + c.dual_category_id, + t.dual, + o.description + FROM categories c + INNER JOIN special_objects o ON o.category_id = c.id + INNER JOIN special_object_types t ON t.type = o.type + WHERE c.dual_category_id IS NOT NULL + ON CONFLICT DO NOTHING`, + ) + .run() - console.info(`Deduced ${res.rowsAffected} special objects by duality`) + console.info(`Deduced ${res.changes} special objects by duality`) } diff --git a/databases/catdat/scripts/deduce.ts b/databases/catdat/scripts/deduce.ts index ce3d846e..5242bffc 100644 --- a/databases/catdat/scripts/deduce.ts +++ b/databases/catdat/scripts/deduce.ts @@ -9,19 +9,19 @@ import { get_client } from './shared' /** * Makes deductions for categories and functors. */ -async function deduce() { +function deduce() { const db = get_client() - await db.execute('PRAGMA foreign_keys = ON') + db.pragma('foreign_keys = ON') - await deduce_category_implications(db) - await deduce_category_properties(db) + deduce_category_implications(db) + deduce_category_properties(db) - await deduce_special_objects(db) - await deduce_special_morphisms(db) + deduce_special_objects(db) + deduce_special_morphisms(db) - await deduce_functor_implications(db) - await deduce_functor_properties(db) + deduce_functor_implications(db) + deduce_functor_properties(db) } -await deduce() +deduce() diff --git a/databases/catdat/scripts/migrate.ts b/databases/catdat/scripts/migrate.ts deleted file mode 100644 index 084259c6..00000000 --- a/databases/catdat/scripts/migrate.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { type Client } from '@libsql/client' -import fs from 'node:fs/promises' -import path from 'node:path' -import dotenv from 'dotenv' -import { get_client } from './shared' - -dotenv.config({ quiet: true }) - -await migrate() - -/** - * Creates the tables, indexes, triggers, and views. - */ -async function migrate() { - console.info('\n--- Migrate CatDat database ---') - const db = get_client() - await db.execute('PRAGMA foreign_keys = ON') - await create_migrations_table(db) - await apply_migrations(db) -} - -/** - * Creates the migration table that records - * which migrations have already been applied. - */ -async function create_migrations_table(db: Client) { - await db.execute(` - CREATE TABLE IF NOT EXISTS migrations ( - file TEXT PRIMARY KEY, - applied_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP - ) - `) -} - -/** - * Applies all migrations that have not been applied yet. - */ -async function apply_migrations(db: Client) { - const { rows } = await db.execute('SELECT file FROM migrations') - const applied_migrations = new Set(rows.map((row) => row.file) as string[]) - - const migrations_folder = path.join( - process.cwd(), - 'databases', - 'catdat', - 'migrations', - ) - const unsorted_files = await fs.readdir(migrations_folder, 'utf8') - const files = unsorted_files.filter((f) => f.endsWith('.sql')).sort() - - const invalid_file = files.find((file) => !file.match(/^\d{3}_/)) - if (invalid_file) throw new Error(`Invalid file name: ${invalid_file}`) - - const all_done = files.every((file) => applied_migrations.has(file)) - - if (all_done) { - console.info('No migrations need to be applied') - process.exit(0) - } - - for (const file of files) { - if (applied_migrations.has(file)) continue - - const sql = await fs.readFile(path.join(migrations_folder, file), 'utf8') - - const tx = await db.transaction() - try { - await tx.executeMultiple(sql) - await tx.execute({ - sql: 'INSERT INTO migrations (file) VALUES (?)', - args: [file], - }) - await tx.commit() - console.info(`Applied migration: ${file}`) - } catch (err) { - console.error(`Failed migration: ${file}`, err) - await tx.rollback() - process.exit(1) - } - } - - console.info('Applied all migrations') -} diff --git a/databases/catdat/scripts/seed.ts b/databases/catdat/scripts/seed.ts index 13ea2724..cdfc6af7 100644 --- a/databases/catdat/scripts/seed.ts +++ b/databases/catdat/scripts/seed.ts @@ -1,16 +1,17 @@ -import fs from 'node:fs/promises' +import fs from 'node:fs' import path from 'node:path' import { get_client } from './shared' /** * Seeds the data recorded in SQL files into the database. */ -async function seed() { +function seed() { console.info('\n--- Seed CatDat database ---') const db = get_client() const data_folder = path.join(process.cwd(), 'databases', 'catdat', 'data') - const subfolders = (await fs.readdir(data_folder, { withFileTypes: true })) + const subfolders = fs + .readdirSync(data_folder, { withFileTypes: true }) .filter((f) => f.isDirectory()) .map((f) => f.name) .sort() @@ -18,39 +19,39 @@ async function seed() { const invalid_folder = subfolders.find((f) => !f.match(/^\d{3}_/)) if (invalid_folder) throw new Error(`Invalid folder name: ${invalid_folder}`) - const tx = await db.transaction() - - try { + const process_files = db.transaction(() => { for (const folder of subfolders) { const folder_path = path.join(data_folder, folder) - const files = (await fs.readdir(folder_path, { withFileTypes: true })) - .filter((f) => f.isFile() && f.name.endsWith('.sql')) - .map((f) => path.join(folder_path, f.name)) + + const files = fs + .readdirSync(folder_path, 'utf8') + .filter((file) => file.endsWith('.sql')) .sort() - for (const file of files) { - const base = path.basename(file) - const is_valid = base?.match(/^[A-Za-z0-9_.,\-()]+$/) - if (!is_valid) { - throw new Error(`Invalid file name: ${base}`) - } + const invalid_file = files.find( + (file) => !file.match(/^[A-Za-z0-9_.,\-()]+$/), + ) + if (invalid_file) throw new Error(`Invalid file name: ${invalid_file}`) - console.info(`Seed: ${base}`) + for (const file of files) { + console.info(`Seed: ${file}`) try { - const sql = await fs.readFile(file, 'utf8') - await tx.executeMultiple(sql) + const sql = fs.readFileSync(path.join(folder_path, file), 'utf8') + db.exec(sql) } catch (err) { - throw new Error(`Seed failed in ${base}: ${String(err)}`) + throw new Error(`Seed failed in ${file}: ${String(err)}`) } } } - await tx.commit() + }) + + try { + process_files() } catch (err) { - await tx.rollback() console.error(err) process.exit(1) } } -await seed() +seed() diff --git a/databases/catdat/scripts/setup.ts b/databases/catdat/scripts/setup.ts new file mode 100644 index 00000000..46a6a6b2 --- /dev/null +++ b/databases/catdat/scripts/setup.ts @@ -0,0 +1,40 @@ +import fs from 'node:fs' +import path from 'node:path' +import { get_client } from './shared' + +setup() + +/** + * Creates the tables, indexes, triggers, and views. + */ +function setup() { + console.info('\n--- Setup CatDat database ---') + + const db = get_client() + db.pragma('foreign_keys = ON') + + const schema_folder = path.join(process.cwd(), 'databases', 'catdat', 'schema') + + const files = fs + .readdirSync(schema_folder, 'utf8') + .filter((file) => file.endsWith('.sql')) + .sort() + + const invalid_file = files.find((file) => !file.match(/^\d{3}_/)) + if (invalid_file) throw new Error(`Invalid file name: ${invalid_file}`) + + for (const file of files) { + const sql = fs.readFileSync(path.join(schema_folder, file), 'utf8') + + console.info(`Apply: ${file}`) + + try { + db.exec(sql) + } catch (err) { + console.error(`Failed to apply file: ${file}`, String(err)) + process.exit(1) + } + } + + console.info('Setup complete') +} diff --git a/databases/catdat/scripts/shared.ts b/databases/catdat/scripts/shared.ts index 04c998ed..f25d973b 100644 --- a/databases/catdat/scripts/shared.ts +++ b/databases/catdat/scripts/shared.ts @@ -1,7 +1,5 @@ -import { createClient } from '@libsql/client' -import dotenv from 'dotenv' - -dotenv.config({ quiet: true }) +import Database from 'better-sqlite3' +import { join } from 'node:path' export function are_equal_sets(a: Set, b: Set) { return a.size === b.size && [...a].every((el) => b.has(el)) @@ -15,12 +13,8 @@ export function is_subset(a: Set, b: Set, exception?: T) { } export function get_client() { - const CATDAT_DB_URL = process.env.CATDAT_DB_URL - const CATDAT_DB_AUTH_TOKEN = process.env.CATDAT_DB_AUTH_TOKEN - - if (!CATDAT_DB_URL) throw new Error('No CATDAT_DB_URL found') - - return createClient({ url: CATDAT_DB_URL, authToken: CATDAT_DB_AUTH_TOKEN }) + const db_path = join(process.cwd(), 'databases', 'catdat', 'catdat.db') + return new Database(db_path, { readonly: false }) } type NormalizedImplication = { diff --git a/databases/catdat/scripts/test.ts b/databases/catdat/scripts/test.ts index 07b778dd..150f8314 100644 --- a/databases/catdat/scripts/test.ts +++ b/databases/catdat/scripts/test.ts @@ -12,19 +12,19 @@ import { get_client } from './shared' const db = get_client() -await execute_tests() +execute_tests() /** * The main test function verifying that the data behaves as expected. */ -async function execute_tests() { +function execute_tests() { console.info('\n--- Test database ---') try { - await test_mutual_category_duals() - await test_mutual_property_duals() - await test_decided_categories() - await test_properties_of_trivial_category() - await test_properties_of_selected_categories() + test_mutual_category_duals() + test_mutual_property_duals() + test_decided_categories() + test_properties_of_trivial_category() + test_properties_of_selected_categories() } catch (err) { if (err instanceof Error) { console.error(err.message) @@ -38,14 +38,12 @@ async function execute_tests() { /** * Tests for all category properties p,q that if p is dual to q, then q is dual to p. */ -async function test_mutual_property_duals() { - const res = await db.execute('SELECT id, dual_property_id FROM category_properties') +function test_mutual_property_duals() { const dict: Record = {} - const properties = res.rows as unknown as { - id: string - dual_property_id: string | null - }[] + const properties = db + .prepare('SELECT id, dual_property_id FROM category_properties') + .all() as { id: string; dual_property_id: string | null }[] for (const { id, dual_property_id } of properties) { dict[id] = dual_property_id @@ -64,14 +62,12 @@ async function test_mutual_property_duals() { /** * Tests for all categories C,D that if C is dual to D, then D is dual to C. */ -async function test_mutual_category_duals() { - const res = await db.execute('SELECT id, dual_category_id FROM categories') +function test_mutual_category_duals() { const dict: Record = {} - const categories = res.rows as unknown as { - id: string - dual_category_id: string | null - }[] + const categories = db + .prepare('SELECT id, dual_category_id FROM categories') + .all() as { id: string; dual_category_id: string | null }[] for (const { id, dual_category_id } of categories) { dict[id] = dual_category_id @@ -91,9 +87,9 @@ async function test_mutual_category_duals() { * Tests if for a specified list of categories all properties have been decided. * If this test fails, property assignments or implications are missing. */ -async function test_decided_categories() { +function test_decided_categories() { for (const category_id of decided_categories) { - await test_decided_category(category_id) + test_decided_category(category_id) } } @@ -101,20 +97,18 @@ async function test_decided_categories() { * Tests for a given category if all properties have been decided, * i.e. are either satisfied or unsatisfied. */ -async function test_decided_category(category_id: string) { - const res = await db.execute( - ` - SELECT p.id FROM category_properties p - WHERE NOT EXISTS +function test_decided_category(category_id: string) { + const res = db + .prepare( + `SELECT p.id FROM category_properties p WHERE NOT EXISTS ( SELECT 1 FROM category_property_assignments WHERE category_id = ? AND property_id = p.id - ) - `, - [category_id], - ) + )`, + ) + .all(category_id) as { id: string }[] - const unknown_properties = res.rows.map((row) => row.id) + const unknown_properties = res.map((row) => row.id) if (unknown_properties.length > 0) { throw new Error( @@ -129,14 +123,17 @@ async function test_decided_category(category_id: string) { * Tests that the trivial category has no unsatisfied property. * This enforces that all properties in the database are "positive". */ -async function test_properties_of_trivial_category() { - const res = await db.execute(` - SELECT property_id FROM category_property_assignments - WHERE category_id = '1' AND is_satisfied = FALSE - `) - if (res.rows.length > 0) { +function test_properties_of_trivial_category() { + const rows = db + .prepare( + `SELECT property_id FROM category_property_assignments + WHERE category_id = '1' AND is_satisfied = FALSE`, + ) + .all() + + if (rows.length > 0) { throw new Error( - `❌ The trivial category has ${res.rows.length} unsatisfied properties, but it should have 0.`, + `❌ The trivial category has ${rows.length} unsatisfied properties, but it should have 0.`, ) } @@ -148,7 +145,7 @@ async function test_properties_of_trivial_category() { * All of their properties in the database have to match those in the * respective JSON files in the subfolder "expected-data". */ -async function test_properties_of_selected_categories() { +function test_properties_of_selected_categories() { const expected = { Set: Set_expected, Ab: Ab_expected, @@ -156,26 +153,21 @@ async function test_properties_of_selected_categories() { } as Record> for (const cat in expected) { - await test_selected_category(cat, expected[cat]) + test_selected_category(cat, expected[cat]) } } /** * Tests if a selected category has the expected properties. */ -async function test_selected_category( - category_id: string, - expected: Record, -) { - const res = await db.execute( - ` - SELECT property_id AS id, is_satisfied - FROM category_property_assignments - WHERE category_id = ?`, - [category_id], - ) - - const properties = res.rows as unknown as { id: string; is_satisfied: number }[] +function test_selected_category(category_id: string, expected: Record) { + const properties = db + .prepare( + `SELECT property_id AS id, is_satisfied + FROM category_property_assignments + WHERE category_id = ?`, + ) + .all(category_id) as { id: string; is_satisfied: number }[] for (const { id, is_satisfied } of properties) { const ok = Boolean(is_satisfied) === expected[id] diff --git a/netlify.toml b/netlify.toml index a325ef53..44b5be08 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,3 +1,6 @@ [build] command = "pnpm run build" - publish = "build" \ No newline at end of file + publish = "build" + +[functions] + included_files = ["databases/catdat/catdat.db"] \ No newline at end of file diff --git a/package.json b/package.json index a2dbcca4..2c8f9e2f 100644 --- a/package.json +++ b/package.json @@ -16,22 +16,26 @@ "prepare": "husky", "db:shell": "sqlite3 databases/catdat/catdat.db", "db:kill": "rm -rf databases/catdat/catdat.db", - "db:migrate": "tsx databases/catdat/scripts/migrate.ts && tsx databases/app/scripts/migrate.ts", + "db:setup:catdat": "pnpm db:kill && tsx databases/catdat/scripts/setup.ts", + "db:setup": "pnpm db:kill && tsx databases/catdat/scripts/setup.ts && tsx databases/app/scripts/setup.ts", "db:seed": "tsx databases/catdat/scripts/seed.ts", "db:deduce": "tsx databases/catdat/scripts/deduce.ts", "db:test": "tsx databases/catdat/scripts/test.ts", - "db:update": "pnpm db:migrate && pnpm db:seed && pnpm db:deduce && pnpm db:test", + "db:snapshot": "cp databases/catdat/catdat.db static/databases/catdat-snapshot.db", + "db:update": "pnpm db:setup && pnpm db:seed && pnpm db:deduce && pnpm db:test && pnpm db:snapshot", "db:watch": "tsx databases/catdat/scripts/watch.ts", - "db:snapshot": "cp databases/catdat/catdat.db static/databases/catdat-snapshot.db" + "db:update:catdat": "pnpm db:setup:catdat && pnpm db:seed && pnpm db:deduce && pnpm db:test && pnpm db:snapshot" }, "devDependencies": { "@sveltejs/adapter-netlify": "^6.0.4", "@sveltejs/kit": "^2.57.1", "@sveltejs/vite-plugin-svelte": "^7.0.0", + "@types/better-sqlite3": "^7.6.13", "@types/katex": "^0.16.8", "@types/markdown-it": "^14.1.2", "@types/node": "^25.5.0", "@types/nodemailer": "^8.0.0", + "better-sqlite3": "^12.9.0", "chokidar": "^5.0.0", "dotenv": "^17.3.1", "husky": "^9.1.7", @@ -44,7 +48,7 @@ "vite": "^8.0.3" }, "engines": { - "node": ">=22.13.0" + "node": ">=24.14.0" }, "dependencies": { "@fortawesome/free-regular-svg-icons": "^7.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a6a92e1f..2621079d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,7 +20,7 @@ importers: version: 7.2.0 '@libsql/client': specifier: ^0.17.2 - version: 0.17.2 + version: 0.17.3 '@octokit/app': specifier: ^16.1.2 version: 16.1.2 @@ -32,29 +32,32 @@ importers: version: 5.10.1 katex: specifier: ^0.16.44 - version: 0.16.44 + version: 0.16.45 markdown-it: specifier: ^14.1.1 version: 14.1.1 nodemailer: specifier: ^8.0.5 - version: 8.0.5 + version: 8.0.7 sql-template-tag: specifier: ^5.2.1 version: 5.2.1 svelte-fa: specifier: ^4.0.4 - version: 4.0.4(svelte@5.55.1) + version: 4.0.4(svelte@5.55.5) devDependencies: '@sveltejs/adapter-netlify': specifier: ^6.0.4 - version: 6.0.4(@sveltejs/kit@2.57.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)(typescript@5.9.3)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))) + version: 6.0.4(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)))(svelte@5.55.5)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0))) '@sveltejs/kit': specifier: ^2.57.1 - version: 2.57.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)(typescript@5.9.3)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)))(svelte@5.55.5)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)) '@sveltejs/vite-plugin-svelte': specifier: ^7.0.0 - version: 7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)) + '@types/better-sqlite3': + specifier: ^7.6.13 + version: 7.6.13 '@types/katex': specifier: ^0.16.8 version: 0.16.8 @@ -63,31 +66,34 @@ importers: version: 14.1.2 '@types/node': specifier: ^25.5.0 - version: 25.5.0 + version: 25.6.0 '@types/nodemailer': specifier: ^8.0.0 version: 8.0.0 + better-sqlite3: + specifier: ^12.9.0 + version: 12.9.0 chokidar: specifier: ^5.0.0 version: 5.0.0 dotenv: specifier: ^17.3.1 - version: 17.3.1 + version: 17.4.2 husky: specifier: ^9.1.7 version: 9.1.7 prettier: specifier: ^3.8.1 - version: 3.8.1 + version: 3.8.3 prettier-plugin-svelte: specifier: ^3.5.1 - version: 3.5.1(prettier@3.8.1)(svelte@5.55.1) + version: 3.5.1(prettier@3.8.3)(svelte@5.55.5) svelte: specifier: ^5.55.1 - version: 5.55.1 + version: 5.55.5 svelte-check: specifier: ^4.4.6 - version: 4.4.6(picomatch@4.0.4)(svelte@5.55.1)(typescript@5.9.3) + version: 4.4.6(picomatch@4.0.4)(svelte@5.55.5)(typescript@5.9.3) tsx: specifier: ^4.21.0 version: 4.21.0 @@ -96,18 +102,18 @@ importers: version: 5.9.3 vite: specifier: '>=8.0.5' - version: 8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) + version: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0) packages: - '@emnapi/core@1.9.0': - resolution: {integrity: sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@emnapi/runtime@1.9.1': - resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/wasi-threads@1.2.0': - resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} @@ -115,8 +121,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.27.4': - resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -127,8 +133,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.27.4': - resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -139,8 +145,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.27.4': - resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -151,8 +157,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.27.4': - resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -163,8 +169,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.27.4': - resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -175,8 +181,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.27.4': - resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -187,8 +193,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.27.4': - resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -199,8 +205,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.4': - resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -211,8 +217,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.27.4': - resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -223,8 +229,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.27.4': - resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -235,8 +241,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.27.4': - resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -247,8 +253,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.27.4': - resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -259,8 +265,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.27.4': - resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -271,8 +277,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.27.4': - resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -283,8 +289,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.27.4': - resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -295,8 +301,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.27.4': - resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -307,8 +313,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.27.4': - resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -319,8 +325,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.27.4': - resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -331,8 +337,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.4': - resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -343,8 +349,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.27.4': - resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -355,8 +361,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.4': - resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -367,8 +373,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.27.4': - resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -379,8 +385,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.27.4': - resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -391,8 +397,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.27.4': - resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -403,8 +409,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.27.4': - resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -415,8 +421,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.27.4': - resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -455,11 +461,11 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@libsql/client@0.17.2': - resolution: {integrity: sha512-0aw0S3iQMHvOxfRt5j1atoCCPMT3gjsB2PS8/uxSM1DcDn39xqz6RlgSMxtP8I3JsxIXAFuw7S41baLEw0Zi+Q==} + '@libsql/client@0.17.3': + resolution: {integrity: sha512-HXk9wiAoJbKFbyBH4O+aEhN6ir5ERXuXvwE5OD2eR4/5RUa3Pw/8L9zrnVdU+iNJitRvisPWaIwmhkO3bH7giA==} - '@libsql/core@0.17.2': - resolution: {integrity: sha512-L8qv12HZ/jRBcETVR3rscP0uHNxh+K3EABSde6scCw7zfOdiLqO3MAkJaeE1WovPsjXzsN/JBoZED4+7EZVT3g==} + '@libsql/core@0.17.3': + resolution: {integrity: sha512-2UjK1i7JBkMduJo4WdvvBxMMvVJ31pArBZNONyz/GCJJAH+1UHat2X6vn10S/WpY5fKzIT98WqYFl2vzWRLOfg==} '@libsql/darwin-arm64@0.5.29': resolution: {integrity: sha512-K+2RIB1OGFPYQbfay48GakLhqf3ArcbHqPFu7EZiaUcRgFcdw8RoltsMyvbj5ix2fY0HV3Q3Ioa/ByvQdaSM0A==} @@ -471,8 +477,8 @@ packages: cpu: [x64] os: [darwin] - '@libsql/hrana-client@0.9.0': - resolution: {integrity: sha512-pxQ1986AuWfPX4oXzBvLwBnfgKDE5OMhAdR/5cZmRaB4Ygz5MecQybvwZupnRz341r2CtFmbk/BhSu7k2Lm+Jw==} + '@libsql/hrana-client@0.10.0': + resolution: {integrity: sha512-OoA4EMqRAC7kn7V2P6EQqRcpZf2W+AjsNIyCizBg339Tq/aMC7sRnzs3SklderhmQWAqEzvv8A2vhxVmWpkVvw==} '@libsql/isomorphic-ws@0.1.5': resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} @@ -512,8 +518,8 @@ packages: cpu: [x64] os: [win32] - '@napi-rs/wasm-runtime@1.1.2': - resolution: {integrity: sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==} + '@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 @@ -604,113 +610,109 @@ packages: resolution: {integrity: sha512-da6KbdNCV5sr1/txD896V+6W0iamFWrvVl8cHkBSPT+YlvmT3DwXa4jxZnQc+gnuTEqSWbBeoSZYTayXH9wXcw==} engines: {node: '>= 20'} - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} - engines: {node: '>=8.0.0'} - - '@oxc-project/types@0.122.0': - resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} + '@oxc-project/types@0.127.0': + resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@rolldown/binding-android-arm64@1.0.0-rc.12': - resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} + '@rolldown/binding-android-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.12': - resolution: {integrity: sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.12': - resolution: {integrity: sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==} + '@rolldown/binding-darwin-x64@1.0.0-rc.17': + resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.12': - resolution: {integrity: sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': + resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': - resolution: {integrity: sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': + resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': - resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': + resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==} + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==} + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': - resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': + resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': - resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': - resolution: {integrity: sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==} - engines: {node: '>=14.0.0'} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': + resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': - resolution: {integrity: sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': + resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': - resolution: {integrity: sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': + resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-rc.12': - resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==} + '@rolldown/pluginutils@1.0.0-rc.17': + resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -725,8 +727,8 @@ packages: peerDependencies: '@sveltejs/kit': ^2.31.0 - '@sveltejs/kit@2.57.1': - resolution: {integrity: sha512-VRdSbB96cI1EnRh09CqmnQqP/YJvET5buj8S6k7CxaJqBJD4bw4fRKDjcarAj/eX9k2eHifQfDH8NtOh+ZxxPw==} + '@sveltejs/kit@2.58.0': + resolution: {integrity: sha512-kT9GCN8yJTkCK1W+Gi/bvGooWAM7y7WXP+yd+rf6QOIjyoK1ERPrMwSufXJUNu2pMWIqruhFvmz+LbOqsEmKmA==} engines: {node: '>=18.13'} hasBin: true peerDependencies: @@ -754,6 +756,9 @@ packages: '@types/aws-lambda@8.10.161': resolution: {integrity: sha512-rUYdp+MQwSFocxIOcSsYSF3YYYC/uUpMbCY/mbO21vGqfrEYvNSoPyKYDj6RhXXpPfS0KstW9RwG3qXh9sL7FQ==} + '@types/better-sqlite3@7.6.13': + resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} + '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} @@ -772,8 +777,8 @@ packages: '@types/mdurl@2.0.0': resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} - '@types/node@25.5.0': - resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} '@types/nodemailer@8.0.0': resolution: {integrity: sha512-fyf8jWULsCo0d0BuoQ75i6IeoHs47qcqxWc7yUdUcV0pOZGjUTTOvwdG1PRXUDqN/8A64yQdQdnA2pZgcdi+cA==} @@ -784,10 +789,6 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/types@8.58.0': - resolution: {integrity: sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} @@ -804,9 +805,25 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} + better-sqlite3@12.9.0: + resolution: {integrity: sha512-wqUv4Gm3toFpHDQmaKD4QhZm3g1DjUBI0yzS4UBl6lElUmXFYdTQmmEDpAFa5o8FiFiymURypEnfVHzILKaxqQ==} + engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -815,6 +832,9 @@ packages: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -831,13 +851,6 @@ packages: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} - cross-fetch@4.1.0: - resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==} - - data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -847,6 +860,14 @@ packages: supports-color: optional: true + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -863,13 +884,16 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - devalue@5.6.4: - resolution: {integrity: sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==} + devalue@5.7.1: + resolution: {integrity: sha512-MUbZ586EgQqdRnC4yDrlod3BEdyvE4TapGYHMW2CiaW+KkkFmWEFqBUaLltEZCGi0iFXCEjRF0OjF0DV2QHjOA==} - dotenv@17.3.1: - resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -882,16 +906,25 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.27.4: - resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} hasBin: true esm-env@1.2.2: resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} - esrap@2.2.4: - resolution: {integrity: sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==} + esrap@2.2.5: + resolution: {integrity: sha512-/yLB1538mag+dn0wsePTe8C0rDIjUOaJpMs2McodSzmM2msWcZsBSdRtg6HOBt0A/r82BN+Md3pgwSc/uWt2Ig==} + peerDependencies: + '@typescript-eslint/types': ^8.2.0 + peerDependenciesMeta: + '@typescript-eslint/types': + optional: true + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} @@ -905,27 +938,37 @@ packages: picomatch: optional: true - fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - get-tsconfig@4.13.7: - resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} hasBin: true + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + ioredis@5.10.1: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} @@ -933,18 +976,14 @@ packages: is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} - hasBin: true - js-base64@3.7.8: resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} json-with-bigint@3.5.8: resolution: {integrity: sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw==} - katex@0.16.44: - resolution: {integrity: sha512-EkxoDTk8ufHqHlf9QxGwcxeLkWRR3iOuYfRpfORgYfqc8s13bgb+YtRY59NK5ZpRaCwq1kqA6a5lpX8C/eLphQ==} + katex@0.16.45: + resolution: {integrity: sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==} hasBin: true kleur@4.1.5: @@ -1052,6 +1091,16 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -1068,31 +1117,23 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - deprecated: Use your platform's native DOMException instead + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-abi@3.89.0: + resolution: {integrity: sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==} + engines: {node: '>=10'} - nodemailer@8.0.5: - resolution: {integrity: sha512-0PF8Yb1yZuQfQbq+5/pZJrtF6WQcjTd5/S4JOHs9PGFxuTqoB/icwuB44pOdURHJbRKX1PPoJZtY7R4VUoCC8w==} + nodemailer@8.0.7: + resolution: {integrity: sha512-pkjE4mkBzQjdJT4/UmlKl3pX0rC9fZmjh7c6C9o7lv66Ac6w9WCnzPzhbPNxwZAzlF4mdq4CSWB5+FbK6FWCow==} engines: {node: '>=6.0.0'} obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1100,28 +1141,45 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + postcss@8.5.12: + resolution: {integrity: sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==} engines: {node: ^10 || ^12 || >=14} + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. + hasBin: true + prettier-plugin-svelte@3.5.1: resolution: {integrity: sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg==} peerDependencies: prettier: ^3.0.0 svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} hasBin: true promise-limit@2.7.0: resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -1141,8 +1199,8 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - rolldown@1.0.0-rc.12: - resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} + rolldown@1.0.0-rc.17: + resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -1150,9 +1208,23 @@ packages: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + set-cookie-parser@3.1.0: resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + sirv@3.0.2: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} @@ -1168,6 +1240,13 @@ packages: standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + svelte-check@4.4.6: resolution: {integrity: sha512-kP1zG81EWaFe9ZyTv4ZXv44Csi6Pkdpb7S3oj6m+K2ec/IcDg/a8LsFsnVLqm2nxtkSwsd5xPj/qFkTBgXHXjg==} engines: {node: '>= 18.0.0'} @@ -1181,12 +1260,19 @@ packages: peerDependencies: svelte: ^4.0.0 || ^5.0.0 - svelte@5.55.1: - resolution: {integrity: sha512-QjvU7EFemf6mRzdMGlAFttMWtAAVXrax61SZYHdkD6yoVGQ89VeyKfZD4H1JrV1WLmJBxWhFch9H6ig/87VGjw==} + svelte@5.55.5: + resolution: {integrity: sha512-2uCs/LZ9us+AktdzYJM8OcxQ8qnPS1kpaO7syGT/MgO+6Qr1Ybl+TqPq+97u7PHqmmMlye5ZkoyXONy5mjjAbw==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} toad-cache@3.7.0: @@ -1197,9 +1283,6 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -1208,6 +1291,9 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -1216,8 +1302,8 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} universal-github-app-jwt@2.2.2: resolution: {integrity: sha512-dcmbeSrOdTnsjGjUfAlqNDJrhxXizjAz94ija9Qw8YkZ1uu0d+GoZzyH+Jb9tIIqvGsadUfwg+22k5aDqqwzbw==} @@ -1225,8 +1311,11 @@ packages: universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} - vite@8.0.5: - resolution: {integrity: sha512-nmu43Qvq9UopTRfMx2jOYW5l16pb3iDC1JH6yMuPkpVbzK0k+L7dfsEDH4jRgYFmsg0sTAqkojoZgzLMlwHsCQ==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite@8.0.10: + resolution: {integrity: sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -1276,15 +1365,8 @@ packages: vite: optional: true - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} ws@8.20.0: resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} @@ -1298,28 +1380,23 @@ packages: utf-8-validate: optional: true - yaml@2.8.3: - resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} - engines: {node: '>= 14.6'} - hasBin: true - zimmerframe@1.1.4: resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} snapshots: - '@emnapi/core@1.9.0': + '@emnapi/core@1.10.0': dependencies: - '@emnapi/wasi-threads': 1.2.0 + '@emnapi/wasi-threads': 1.2.1 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.9.1': + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.2.0': + '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 optional: true @@ -1327,157 +1404,157 @@ snapshots: '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/aix-ppc64@0.27.4': + '@esbuild/aix-ppc64@0.27.7': optional: true '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm64@0.27.4': + '@esbuild/android-arm64@0.27.7': optional: true '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-arm@0.27.4': + '@esbuild/android-arm@0.27.7': optional: true '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/android-x64@0.27.4': + '@esbuild/android-x64@0.27.7': optional: true '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.27.4': + '@esbuild/darwin-arm64@0.27.7': optional: true '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/darwin-x64@0.27.4': + '@esbuild/darwin-x64@0.27.7': optional: true '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.27.4': + '@esbuild/freebsd-arm64@0.27.7': optional: true '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.27.4': + '@esbuild/freebsd-x64@0.27.7': optional: true '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm64@0.27.4': + '@esbuild/linux-arm64@0.27.7': optional: true '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-arm@0.27.4': + '@esbuild/linux-arm@0.27.7': optional: true '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-ia32@0.27.4': + '@esbuild/linux-ia32@0.27.7': optional: true '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-loong64@0.27.4': + '@esbuild/linux-loong64@0.27.7': optional: true '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-mips64el@0.27.4': + '@esbuild/linux-mips64el@0.27.7': optional: true '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.27.4': + '@esbuild/linux-ppc64@0.27.7': optional: true '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.27.4': + '@esbuild/linux-riscv64@0.27.7': optional: true '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-s390x@0.27.4': + '@esbuild/linux-s390x@0.27.7': optional: true '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/linux-x64@0.27.4': + '@esbuild/linux-x64@0.27.7': optional: true '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-arm64@0.27.4': + '@esbuild/netbsd-arm64@0.27.7': optional: true '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.27.4': + '@esbuild/netbsd-x64@0.27.7': optional: true '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.27.4': + '@esbuild/openbsd-arm64@0.27.7': optional: true '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.27.4': + '@esbuild/openbsd-x64@0.27.7': optional: true '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/openharmony-arm64@0.27.4': + '@esbuild/openharmony-arm64@0.27.7': optional: true '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/sunos-x64@0.27.4': + '@esbuild/sunos-x64@0.27.7': optional: true '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-arm64@0.27.4': + '@esbuild/win32-arm64@0.27.7': optional: true '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-ia32@0.27.4': + '@esbuild/win32-ia32@0.27.7': optional: true '@esbuild/win32-x64@0.25.12': optional: true - '@esbuild/win32-x64@0.27.4': + '@esbuild/win32-x64@0.27.7': optional: true '@fortawesome/fontawesome-common-types@7.2.0': {} @@ -1513,19 +1590,18 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@libsql/client@0.17.2': + '@libsql/client@0.17.3': dependencies: - '@libsql/core': 0.17.2 - '@libsql/hrana-client': 0.9.0 + '@libsql/core': 0.17.3 + '@libsql/hrana-client': 0.10.0 js-base64: 3.7.8 libsql: 0.5.29 promise-limit: 2.7.0 transitivePeerDependencies: - bufferutil - - encoding - utf-8-validate - '@libsql/core@0.17.2': + '@libsql/core@0.17.3': dependencies: js-base64: 3.7.8 @@ -1535,15 +1611,12 @@ snapshots: '@libsql/darwin-x64@0.5.29': optional: true - '@libsql/hrana-client@0.9.0': + '@libsql/hrana-client@0.10.0': dependencies: '@libsql/isomorphic-ws': 0.1.5 - cross-fetch: 4.1.0 js-base64: 3.7.8 - node-fetch: 3.3.2 transitivePeerDependencies: - bufferutil - - encoding - utf-8-validate '@libsql/isomorphic-ws@0.1.5': @@ -1575,10 +1648,10 @@ snapshots: '@libsql/win32-x64-msvc@0.5.29': optional: true - '@napi-rs/wasm-runtime@1.1.2(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)': + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@emnapi/core': 1.9.0 - '@emnapi/runtime': 1.9.1 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 '@tybys/wasm-util': 0.10.1 optional: true @@ -1710,64 +1783,60 @@ snapshots: '@octokit/request-error': 7.1.0 '@octokit/webhooks-methods': 6.0.0 - '@opentelemetry/api@1.9.0': - optional: true - - '@oxc-project/types@0.122.0': {} + '@oxc-project/types@0.127.0': {} '@polka/url@1.0.0-next.29': {} - '@rolldown/binding-android-arm64@1.0.0-rc.12': + '@rolldown/binding-android-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.12': + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.12': + '@rolldown/binding-darwin-x64@1.0.0-rc.17': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.12': + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.12(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': dependencies: - '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': optional: true - '@rolldown/pluginutils@1.0.0-rc.12': {} + '@rolldown/pluginutils@1.0.0-rc.17': {} '@standard-schema/spec@1.1.0': {} @@ -1775,41 +1844,40 @@ snapshots: dependencies: acorn: 8.16.0 - '@sveltejs/adapter-netlify@6.0.4(@sveltejs/kit@2.57.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)(typescript@5.9.3)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)))': + '@sveltejs/adapter-netlify@6.0.4(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)))(svelte@5.55.5)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)))': dependencies: '@iarna/toml': 2.2.5 - '@sveltejs/kit': 2.57.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)(typescript@5.9.3)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + '@sveltejs/kit': 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)))(svelte@5.55.5)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)) esbuild: 0.25.12 - '@sveltejs/kit@2.57.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.55.1)(typescript@5.9.3)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': + '@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)))(svelte@5.55.5)(typescript@5.9.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0))': dependencies: '@standard-schema/spec': 1.1.0 '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@sveltejs/vite-plugin-svelte': 7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + '@sveltejs/vite-plugin-svelte': 7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)) '@types/cookie': 0.6.0 acorn: 8.16.0 cookie: 1.1.1 - devalue: 5.6.4 + devalue: 5.7.1 esm-env: 1.2.2 kleur: 4.1.5 magic-string: 0.30.21 mrmime: 2.0.1 set-cookie-parser: 3.1.0 sirv: 3.0.2 - svelte: 5.55.1 - vite: 8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) + svelte: 5.55.5 + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0) optionalDependencies: - '@opentelemetry/api': 1.9.0 typescript: 5.9.3 - '@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.1)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': + '@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0))': dependencies: deepmerge: 4.3.1 magic-string: 0.30.21 obug: 2.1.1 - svelte: 5.55.1 - vite: 8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) - vitefu: 1.1.3(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + svelte: 5.55.5 + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0) + vitefu: 1.1.3(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)) '@tybys/wasm-util@0.10.1': dependencies: @@ -1818,6 +1886,10 @@ snapshots: '@types/aws-lambda@8.10.161': {} + '@types/better-sqlite3@7.6.13': + dependencies: + '@types/node': 25.6.0 + '@types/cookie@0.6.0': {} '@types/estree@1.0.8': {} @@ -1833,21 +1905,19 @@ snapshots: '@types/mdurl@2.0.0': {} - '@types/node@25.5.0': + '@types/node@25.6.0': dependencies: - undici-types: 7.18.2 + undici-types: 7.19.2 '@types/nodemailer@8.0.0': dependencies: - '@types/node': 25.5.0 + '@types/node': 25.6.0 '@types/trusted-types@2.0.7': {} '@types/ws@8.18.1': dependencies: - '@types/node': 25.5.0 - - '@typescript-eslint/types@8.58.0': {} + '@types/node': 25.6.0 acorn@8.16.0: {} @@ -1857,8 +1927,30 @@ snapshots: axobject-query@4.1.0: {} + base64-js@1.5.1: {} + before-after-hook@4.0.0: {} + better-sqlite3@12.9.0: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.3 + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -1867,6 +1959,8 @@ snapshots: dependencies: readdirp: 5.0.0 + chownr@1.1.4: {} + clsx@2.1.1: {} cluster-key-slot@1.1.2: {} @@ -1875,18 +1969,16 @@ snapshots: cookie@1.1.1: {} - cross-fetch@4.1.0: - dependencies: - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - - data-uri-to-buffer@4.0.1: {} - debug@4.4.3: dependencies: ms: 2.1.3 + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + deepmerge@4.3.1: {} denque@2.1.0: {} @@ -1895,9 +1987,13 @@ snapshots: detect-libc@2.1.2: {} - devalue@5.6.4: {} + devalue@5.7.1: {} - dotenv@17.3.1: {} + dotenv@17.4.2: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 entities@4.5.0: {} @@ -1932,41 +2028,42 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 - esbuild@0.27.4: + esbuild@0.27.7: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.4 - '@esbuild/android-arm': 0.27.4 - '@esbuild/android-arm64': 0.27.4 - '@esbuild/android-x64': 0.27.4 - '@esbuild/darwin-arm64': 0.27.4 - '@esbuild/darwin-x64': 0.27.4 - '@esbuild/freebsd-arm64': 0.27.4 - '@esbuild/freebsd-x64': 0.27.4 - '@esbuild/linux-arm': 0.27.4 - '@esbuild/linux-arm64': 0.27.4 - '@esbuild/linux-ia32': 0.27.4 - '@esbuild/linux-loong64': 0.27.4 - '@esbuild/linux-mips64el': 0.27.4 - '@esbuild/linux-ppc64': 0.27.4 - '@esbuild/linux-riscv64': 0.27.4 - '@esbuild/linux-s390x': 0.27.4 - '@esbuild/linux-x64': 0.27.4 - '@esbuild/netbsd-arm64': 0.27.4 - '@esbuild/netbsd-x64': 0.27.4 - '@esbuild/openbsd-arm64': 0.27.4 - '@esbuild/openbsd-x64': 0.27.4 - '@esbuild/openharmony-arm64': 0.27.4 - '@esbuild/sunos-x64': 0.27.4 - '@esbuild/win32-arm64': 0.27.4 - '@esbuild/win32-ia32': 0.27.4 - '@esbuild/win32-x64': 0.27.4 + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 esm-env@1.2.2: {} - esrap@2.2.4: + esrap@2.2.5: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - '@typescript-eslint/types': 8.58.0 + + expand-template@2.0.3: {} fast-content-type-parse@3.0.0: {} @@ -1974,24 +2071,27 @@ snapshots: optionalDependencies: picomatch: 4.0.4 - fetch-blob@3.2.0: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 + file-uri-to-path@1.0.0: {} - formdata-polyfill@4.0.10: - dependencies: - fetch-blob: 3.2.0 + fs-constants@1.0.0: {} fsevents@2.3.3: optional: true - get-tsconfig@4.13.7: + get-tsconfig@4.14.0: dependencies: resolve-pkg-maps: 1.0.0 + github-from-package@0.0.0: {} + husky@9.1.7: {} + ieee754@1.2.1: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + ioredis@5.10.1: dependencies: '@ioredis/commands': 1.5.1 @@ -2010,14 +2110,11 @@ snapshots: dependencies: '@types/estree': 1.0.8 - jiti@2.6.1: - optional: true - js-base64@3.7.8: {} json-with-bigint@3.5.8: {} - katex@0.16.44: + katex@0.16.45: dependencies: commander: 8.3.0 @@ -2112,6 +2209,12 @@ snapshots: mdurl@2.0.0: {} + mimic-response@3.1.0: {} + + minimist@1.2.8: {} + + mkdirp-classic@0.5.3: {} + mri@1.2.0: {} mrmime@2.0.1: {} @@ -2120,43 +2223,74 @@ snapshots: nanoid@3.3.11: {} - node-domexception@1.0.0: {} - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 + napi-build-utils@2.0.0: {} - node-fetch@3.3.2: + node-abi@3.89.0: dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 + semver: 7.7.4 - nodemailer@8.0.5: {} + nodemailer@8.0.7: {} obug@2.1.1: {} + once@1.4.0: + dependencies: + wrappy: 1.0.2 + picocolors@1.1.1: {} picomatch@4.0.4: {} - postcss@8.5.8: + postcss@8.5.12: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 - prettier-plugin-svelte@3.5.1(prettier@3.8.1)(svelte@5.55.1): + prebuild-install@7.1.3: dependencies: - prettier: 3.8.1 - svelte: 5.55.1 + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.89.0 + pump: 3.0.4 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 - prettier@3.8.1: {} + prettier-plugin-svelte@3.5.1(prettier@3.8.3)(svelte@5.55.5): + dependencies: + prettier: 3.8.3 + svelte: 5.55.5 + + prettier@3.8.3: {} promise-limit@2.7.0: {} + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + punycode.js@2.3.1: {} + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + readdirp@4.1.2: {} readdirp@5.0.0: {} @@ -2169,36 +2303,45 @@ snapshots: resolve-pkg-maps@1.0.0: {} - rolldown@1.0.0-rc.12(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1): + rolldown@1.0.0-rc.17: dependencies: - '@oxc-project/types': 0.122.0 - '@rolldown/pluginutils': 1.0.0-rc.12 + '@oxc-project/types': 0.127.0 + '@rolldown/pluginutils': 1.0.0-rc.17 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.12 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.12 - '@rolldown/binding-darwin-x64': 1.0.0-rc.12 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.12 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.12 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.12 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.12 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.12 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.12(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1) - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.12 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.12 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' + '@rolldown/binding-android-arm64': 1.0.0-rc.17 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.17 + '@rolldown/binding-darwin-x64': 1.0.0-rc.17 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.17 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.17 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.17 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.17 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.17 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.17 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 sade@1.8.1: dependencies: mri: 1.2.0 + safe-buffer@5.2.1: {} + + semver@7.7.4: {} + set-cookie-parser@3.1.0: {} + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + sirv@3.0.2: dependencies: '@polka/url': 1.0.0-next.29 @@ -2211,23 +2354,29 @@ snapshots: standard-as-callback@2.1.0: {} - svelte-check@4.4.6(picomatch@4.0.4)(svelte@5.55.1)(typescript@5.9.3): + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-json-comments@2.0.1: {} + + svelte-check@4.4.6(picomatch@4.0.4)(svelte@5.55.5)(typescript@5.9.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 chokidar: 4.0.3 fdir: 6.5.0(picomatch@4.0.4) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.55.1 + svelte: 5.55.5 typescript: 5.9.3 transitivePeerDependencies: - picomatch - svelte-fa@4.0.4(svelte@5.55.1): + svelte-fa@4.0.4(svelte@5.55.5): dependencies: - svelte: 5.55.1 + svelte: 5.55.5 - svelte@5.55.1: + svelte@5.55.5: dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 @@ -2238,15 +2387,32 @@ snapshots: aria-query: 5.3.1 axobject-query: 4.1.0 clsx: 2.1.1 - devalue: 5.6.4 + devalue: 5.7.1 esm-env: 1.2.2 - esrap: 2.2.4 + esrap: 2.2.5 is-reference: 3.0.3 locate-character: 3.0.0 magic-string: 0.30.21 zimmerframe: 1.1.4 + transitivePeerDependencies: + - '@typescript-eslint/types' + + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.4 + tar-stream: 2.2.0 - tinyglobby@0.2.15: + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 @@ -2255,62 +2421,51 @@ snapshots: totalist@3.0.1: {} - tr46@0.0.3: {} - tslib@2.8.1: optional: true tsx@4.21.0: dependencies: - esbuild: 0.27.4 - get-tsconfig: 4.13.7 + esbuild: 0.27.7 + get-tsconfig: 4.14.0 optionalDependencies: fsevents: 2.3.3 + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + typescript@5.9.3: {} uc.micro@2.1.0: {} - undici-types@7.18.2: {} + undici-types@7.19.2: {} universal-github-app-jwt@2.2.2: {} universal-user-agent@7.0.3: {} - vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3): + util-deprecate@1.0.2: {} + + vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.8 - rolldown: 1.0.0-rc.12(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1) - tinyglobby: 0.2.15 + postcss: 8.5.12 + rolldown: 1.0.0-rc.17 + tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 25.5.0 - esbuild: 0.27.4 + '@types/node': 25.6.0 + esbuild: 0.27.7 fsevents: 2.3.3 - jiti: 2.6.1 tsx: 4.21.0 - yaml: 2.8.3 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - vitefu@1.1.3(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)): + vitefu@1.1.3(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0)): optionalDependencies: - vite: 8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) - - web-streams-polyfill@3.3.3: {} + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(tsx@4.21.0) - webidl-conversions@3.0.1: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 + wrappy@1.0.2: {} ws@8.20.0: {} - yaml@2.8.3: - optional: true - zimmerframe@1.1.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index fad3e1cb..c28df9b5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,6 @@ +onlyBuiltDependencies: + - better-sqlite3 + - esbuild overrides: cookie@<0.7.0: '>=0.7.0' vite@>=8.0.0 <=8.0.4: '>=8.0.5' diff --git a/src/lib/server/consistency.ts b/src/lib/server/consistency.ts index 96a14ff1..dabfe31b 100644 --- a/src/lib/server/consistency.ts +++ b/src/lib/server/consistency.ts @@ -3,15 +3,15 @@ import { query } from '$lib/server/db.catdat' type AtomicImplication = { assumptions: string[]; conclusion: string } -export async function check_consistency( +export function check_consistency( satisfied_properties: Set, unsatisfied_properties: Set, -): Promise<{ consistent: boolean } | null> { +): { consistent: boolean } | null { for (const p of satisfied_properties) { if (unsatisfied_properties.has(p)) return { consistent: false } } - const implications = await get_atomic_implications() + const implications = get_atomic_implications() if (!implications) return null return check_consistency_worker( @@ -50,8 +50,8 @@ function check_consistency_worker( return { consistent: true } } -async function get_atomic_implications(): Promise { - const { rows: implications, err } = await query<{ +function get_atomic_implications(): AtomicImplication[] | null { + const { rows: implications, err } = query<{ assumptions: string conclusions: string is_equivalence: number @@ -88,18 +88,18 @@ async function get_atomic_implications(): Promise { return atomic_implications } -export async function get_missing_combinations() { - const implications = await get_atomic_implications() +export function get_missing_combinations() { + const implications = get_atomic_implications() if (!implications) return null - const { rows: properties, err } = await query<{ + const { rows: properties, err } = query<{ id: string dual_property_id: string | null }>(sql`SELECT id, dual_property_id FROM category_properties ORDER BY lower(id)`) if (err) return null - const { rows: existing, err: err_existing } = await query<{ + const { rows: existing, err: err_existing } = query<{ p: string q: string }>(sql` diff --git a/src/lib/server/db.app.ts b/src/lib/server/db.app.ts index b69d769a..73d01905 100644 --- a/src/lib/server/db.app.ts +++ b/src/lib/server/db.app.ts @@ -2,12 +2,16 @@ import { createClient, type LibsqlError } from '@libsql/client' import type { Arrayed } from '$lib/commons/types' import { APP_DB_AUTH_TOKEN, APP_DB_URL } from '$env/static/private' -const db_visits = createClient({ +/** + * Database client used only for the CatDat web application, + * in particular for user submissions and page visits. + */ +const db_app = createClient({ url: APP_DB_URL, authToken: APP_DB_AUTH_TOKEN, }) -db_visits.execute('PRAGMA foreign_keys = ON') +db_app.execute('PRAGMA foreign_keys = ON') /** * Small wrapper around db.execute to handle errors, @@ -15,7 +19,7 @@ db_visits.execute('PRAGMA foreign_keys = ON') */ export async function query_app(stmt: { sql: string; values: any[] }) { try { - const { rows } = await db_visits.execute(stmt.sql, stmt.values) + const { rows } = await db_app.execute(stmt.sql, stmt.values) return { rows: rows as T[], err: null } } catch (err) { console.error(err) @@ -31,7 +35,7 @@ export async function batch_app( queries: { sql: string; values: any[] }[], ) { try { - const results = await db_visits.batch( + const results = await db_app.batch( queries.map((query) => ({ sql: query.sql, args: query.values, diff --git a/src/lib/server/db.catdat.ts b/src/lib/server/db.catdat.ts index 745b846c..60d97dc9 100644 --- a/src/lib/server/db.catdat.ts +++ b/src/lib/server/db.catdat.ts @@ -1,43 +1,49 @@ -import { createClient, type LibsqlError } from '@libsql/client' import type { Arrayed } from '$lib/commons/types' -import { CATDAT_DB_AUTH_TOKEN, CATDAT_DB_URL } from '$env/static/private' +import Database, { SqliteError } from 'better-sqlite3' +import { join } from 'node:path' -const db = createClient({ - url: CATDAT_DB_URL, - authToken: CATDAT_DB_AUTH_TOKEN, -}) +const db_path = join(process.cwd(), 'databases', 'catdat', 'catdat.db') -db.execute('PRAGMA foreign_keys = ON') +/** + * Database client for the CatDat database holding all mathematical knowledge + */ +const db = new Database(db_path, { readonly: true, fileMustExist: true }) /** - * Small wrapper around db.execute to handle errors, + * Small wrapper around db.prepare.all to handle errors, * use sql templates, and specify the type of the result. */ -export async function query(stmt: { sql: string; values: any[] }) { +export function query(stmt: { sql: string; values: any[] }) { try { - const { rows } = await db.execute(stmt.sql, stmt.values) + const rows = db.prepare(stmt.sql).all(...stmt.values) return { rows: rows as T[], err: null } } catch (err) { console.error(err) - return { rows: null, err: err as LibsqlError } + return { rows: null, err: err as SqliteError } } } /** - * Small wrapper around db.batch to handle errors + * Small wrapper around db.transaction to handle errors * use sql templates, and specify the type of the result. */ -export async function batch(queries: { sql: string; values: any[] }[]) { +export function batch(queries: { sql: string; values: any[] }[]) { try { - const results = await db.batch( - queries.map((query) => ({ - sql: query.sql, - args: query.values, - })), - ) - return { results: results.map(({ rows }) => rows) as Arrayed, err: null } + const run_batch = db.transaction(() => { + const results = [] + + for (const query of queries) { + const result = db.prepare(query.sql).all(...query.values) + results.push(result) + } + + return results + }) + + const results = run_batch() as Arrayed + return { results, err: null } } catch (err) { console.error(err) - return { results: null, err: err as LibsqlError } + return { rows: null, err: err as SqliteError } } } diff --git a/src/lib/server/search.ts b/src/lib/server/search.ts index c5aa1f47..69ed721f 100644 --- a/src/lib/server/search.ts +++ b/src/lib/server/search.ts @@ -11,7 +11,7 @@ type NamedObject = { name: string } -export async function search_handler(event: RequestEvent, type: 'category' | 'functor') { +export function search_handler(event: RequestEvent, type: 'category' | 'functor') { const satisfied_query = event.url.searchParams.get('satisfied') const unsatisfied_query = event.url.searchParams.get('unsatisfied') @@ -19,7 +19,7 @@ export async function search_handler(event: RequestEvent, type: 'category' | 'fu error(400, 'No properties selected') } - const { rows: all_properties_objects, err: err_all } = await query<{ + const { rows: all_properties_objects, err: err_all } = query<{ id: string dual_property_id: string | null }>(get_property_query(type)) @@ -71,7 +71,7 @@ export async function search_handler(event: RequestEvent, type: 'category' | 'fu // TODO: implement this for functors as well if (type === 'category') { - const check = await check_consistency( + const check = check_consistency( new Set(satisfied_properties), new Set(unsatisfied_properties), ) @@ -106,7 +106,7 @@ export async function search_handler(event: RequestEvent, type: 'category' | 'fu type, ) - const { rows: found_objects, err } = await query({ + const { rows: found_objects, err } = query({ sql: search_query, values: [ ...all_selected_properties, diff --git a/src/routes/categories/+page.server.ts b/src/routes/categories/+page.server.ts index a7f2e813..405db49a 100644 --- a/src/routes/categories/+page.server.ts +++ b/src/routes/categories/+page.server.ts @@ -4,7 +4,7 @@ import { error } from '@sveltejs/kit' import sql from 'sql-template-tag' export const load = async () => { - const { results, err } = await batch<[CategoryShort, TagObject]>([ + const { results, err } = batch<[CategoryShort, TagObject]>([ sql`SELECT id, name FROM categories ORDER BY lower(name)`, sql`SELECT tag FROM tags ORDER BY position`, ]) diff --git a/src/routes/categories/[tag]/+page.server.ts b/src/routes/categories/[tag]/+page.server.ts index e44e1e91..4183f529 100644 --- a/src/routes/categories/[tag]/+page.server.ts +++ b/src/routes/categories/[tag]/+page.server.ts @@ -5,7 +5,7 @@ import sql from 'sql-template-tag' import type { EntryGenerator } from './$types' export const entries: EntryGenerator = async () => { - const { rows, err } = await query(sql`SELECT tag FROM tags`) + const { rows, err } = query(sql`SELECT tag FROM tags`) if (err) throw new Error('Database error: Failed to load tags') return rows } @@ -13,7 +13,7 @@ export const entries: EntryGenerator = async () => { export const load = async (event) => { const tag = event.params.tag - const { rows: categories, err } = await query(sql` + const { rows: categories, err } = query(sql` SELECT c.id, c.name FROM categories c LEFT JOIN category_tag_assignments t ON c.id = t.category_id WHERE t.tag = ${tag} diff --git a/src/routes/category-comparison/+page.server.ts b/src/routes/category-comparison/+page.server.ts index 5348ae9e..db74d8dd 100644 --- a/src/routes/category-comparison/+page.server.ts +++ b/src/routes/category-comparison/+page.server.ts @@ -4,7 +4,7 @@ import { query } from '$lib/server/db.catdat' import { error } from '@sveltejs/kit' export const load = async () => { - const { rows: categories, err } = await query(sql` + const { rows: categories, err } = query(sql` SELECT id, name FROM categories ORDER BY lower(name) `) diff --git a/src/routes/category-comparison/[...ids]/+page.server.ts b/src/routes/category-comparison/[...ids]/+page.server.ts index f1b51d57..2c002f9f 100644 --- a/src/routes/category-comparison/[...ids]/+page.server.ts +++ b/src/routes/category-comparison/[...ids]/+page.server.ts @@ -19,7 +19,7 @@ export const load = async (event) => { const placeholders = compared_ids.map(() => '?').join(', ') - const { rows, err: err_cat } = await query<{ + const { rows, err: err_cat } = query<{ id: string name: string notation: string @@ -70,7 +70,7 @@ export const load = async (event) => { ${join_fragments.join('\n')} ORDER BY lower(p.id)` - const { rows: comparison_objects, err } = await query>({ + const { rows: comparison_objects, err } = query>({ sql: stmt, values, }) diff --git a/src/routes/category-implication/[id]/+page.server.ts b/src/routes/category-implication/[id]/+page.server.ts index b56ba118..25833370 100644 --- a/src/routes/category-implication/[id]/+page.server.ts +++ b/src/routes/category-implication/[id]/+page.server.ts @@ -8,7 +8,7 @@ import sql from 'sql-template-tag' export const load = async (event) => { const id = event.params.id - const { rows, err } = await query(sql` + const { rows, err } = query(sql` SELECT id, is_equivalence, diff --git a/src/routes/category-implications/+page.server.ts b/src/routes/category-implications/+page.server.ts index 6b3ff97a..fca4f7cf 100644 --- a/src/routes/category-implications/+page.server.ts +++ b/src/routes/category-implications/+page.server.ts @@ -6,7 +6,7 @@ import type { ImplicationDB, ImplicationDisplay } from '$lib/commons/types' import { display_implication } from '$lib/server/utils' export const load = async () => { - const { rows, err } = await query(sql` + const { rows, err } = query(sql` SELECT id, is_equivalence, diff --git a/src/routes/category-properties/+page.server.ts b/src/routes/category-properties/+page.server.ts index b1a9d2a5..bca6f99f 100644 --- a/src/routes/category-properties/+page.server.ts +++ b/src/routes/category-properties/+page.server.ts @@ -4,7 +4,7 @@ import { error } from '@sveltejs/kit' import sql from 'sql-template-tag' export const load = async () => { - const { rows: properties, err } = await query< + const { rows: properties, err } = query< PropertyShort & { dual_property_id?: string } >(sql` SELECT id, relation, dual_property_id FROM category_properties diff --git a/src/routes/category-property/[id]/+page.server.ts b/src/routes/category-property/[id]/+page.server.ts index a2f9b24a..5cd6461c 100644 --- a/src/routes/category-property/[id]/+page.server.ts +++ b/src/routes/category-property/[id]/+page.server.ts @@ -10,7 +10,7 @@ import { display_implication, display_property } from '$lib/server/utils' export const load = async (event) => { const id = decode_property_ID(event.params.id) - const { results, err } = await batch< + const { results, err } = batch< [ PropertyDB, { id: string }, diff --git a/src/routes/category-search/+page.server.ts b/src/routes/category-search/+page.server.ts index ae58730a..c9319ad0 100644 --- a/src/routes/category-search/+page.server.ts +++ b/src/routes/category-search/+page.server.ts @@ -3,7 +3,7 @@ import { error } from '@sveltejs/kit' import sql from 'sql-template-tag' export const load = async () => { - const { rows, err } = await query<{ id: string }>( + const { rows, err } = query<{ id: string }>( sql`SELECT id FROM category_properties ORDER BY lower(id)`, ) diff --git a/src/routes/category-search/results/+page.server.ts b/src/routes/category-search/results/+page.server.ts index a14d1fda..9dd8f578 100644 --- a/src/routes/category-search/results/+page.server.ts +++ b/src/routes/category-search/results/+page.server.ts @@ -3,5 +3,5 @@ import { search_handler } from '$lib/server/search' export const prerender = false export const load = async (event) => { - return await search_handler(event, 'category') + return search_handler(event, 'category') } diff --git a/src/routes/category/[id]/+page.server.ts b/src/routes/category/[id]/+page.server.ts index 0e82de06..b78550b7 100644 --- a/src/routes/category/[id]/+page.server.ts +++ b/src/routes/category/[id]/+page.server.ts @@ -18,7 +18,7 @@ import type { export const load = async (event) => { const id = event.params.id - const { results, err } = await batch< + const { results, err } = batch< [ CategoryDisplay, RelatedCategory, diff --git a/src/routes/functor-implication/[id]/+page.server.ts b/src/routes/functor-implication/[id]/+page.server.ts index 2c60d251..4fffd789 100644 --- a/src/routes/functor-implication/[id]/+page.server.ts +++ b/src/routes/functor-implication/[id]/+page.server.ts @@ -10,7 +10,7 @@ export const prerender = true export const load = async (event) => { const id = event.params.id - const { rows, err } = await query(sql` + const { rows, err } = query(sql` SELECT id, is_equivalence, diff --git a/src/routes/functor-implications/+page.server.ts b/src/routes/functor-implications/+page.server.ts index 97d8a28a..9831c299 100644 --- a/src/routes/functor-implications/+page.server.ts +++ b/src/routes/functor-implications/+page.server.ts @@ -8,7 +8,7 @@ import { display_functor_implication } from '$lib/server/utils' export const prerender = true export const load = async () => { - const { rows, err } = await query(sql` + const { rows, err } = query(sql` SELECT id, is_equivalence, diff --git a/src/routes/functor-properties/+page.server.ts b/src/routes/functor-properties/+page.server.ts index 8ef7cee9..b2a3e315 100644 --- a/src/routes/functor-properties/+page.server.ts +++ b/src/routes/functor-properties/+page.server.ts @@ -6,7 +6,7 @@ import sql from 'sql-template-tag' // TODO: remove code duplication with category properties list page export const load = async () => { - const { rows: properties, err } = await query< + const { rows: properties, err } = query< PropertyShort & { dual_property_id?: string } >(sql` SELECT id, relation, dual_property_id FROM functor_properties diff --git a/src/routes/functor-property/[id]/+page.server.ts b/src/routes/functor-property/[id]/+page.server.ts index 94889261..7e285656 100644 --- a/src/routes/functor-property/[id]/+page.server.ts +++ b/src/routes/functor-property/[id]/+page.server.ts @@ -14,7 +14,7 @@ import sql from 'sql-template-tag' export const load = async (event) => { const id = decode_property_ID(event.params.id) - const { results, err } = await batch< + const { results, err } = batch< [ FunctorPropertyDB, FunctorImplicationDB, diff --git a/src/routes/functor-search/+page.server.ts b/src/routes/functor-search/+page.server.ts index d1d5ee53..54a2e558 100644 --- a/src/routes/functor-search/+page.server.ts +++ b/src/routes/functor-search/+page.server.ts @@ -3,7 +3,7 @@ import { error } from '@sveltejs/kit' import sql from 'sql-template-tag' export const load = async (event) => { - const { rows, err } = await query<{ id: string }>(sql` + const { rows, err } = query<{ id: string }>(sql` SELECT id FROM functor_properties ORDER BY lower(id) `) diff --git a/src/routes/functor-search/results/+page.server.ts b/src/routes/functor-search/results/+page.server.ts index 25717468..624bf355 100644 --- a/src/routes/functor-search/results/+page.server.ts +++ b/src/routes/functor-search/results/+page.server.ts @@ -3,5 +3,5 @@ import { search_handler } from '$lib/server/search' export const prerender = false export const load = async (event) => { - return await search_handler(event, 'functor') + return search_handler(event, 'functor') } diff --git a/src/routes/functor/[id]/+page.server.ts b/src/routes/functor/[id]/+page.server.ts index fe9bfb76..e359a612 100644 --- a/src/routes/functor/[id]/+page.server.ts +++ b/src/routes/functor/[id]/+page.server.ts @@ -14,7 +14,7 @@ import sql from 'sql-template-tag' export const load = async (event) => { const id = event.params.id - const { results, err } = await batch< + const { results, err } = batch< [ FunctorDB, FunctorPropertyAssignmentDB & { is_satisfied: number }, diff --git a/src/routes/functors/+page.server.ts b/src/routes/functors/+page.server.ts index 410fec41..7377042b 100644 --- a/src/routes/functors/+page.server.ts +++ b/src/routes/functors/+page.server.ts @@ -6,7 +6,7 @@ import sql from 'sql-template-tag' export const prerender = true export const load = async () => { - const { rows: functors, err } = await query( + const { rows: functors, err } = query( sql`SELECT id, name FROM functors ORDER BY lower(name)`, ) diff --git a/src/routes/lemma/[id]/+page.server.ts b/src/routes/lemma/[id]/+page.server.ts index aff22542..37c707e6 100644 --- a/src/routes/lemma/[id]/+page.server.ts +++ b/src/routes/lemma/[id]/+page.server.ts @@ -6,7 +6,7 @@ import sql from 'sql-template-tag' import type { EntryGenerator } from './$types' export const entries: EntryGenerator = async () => { - const { rows, err } = await query<{ id: string }>(sql`SELECT id FROM lemmas`) + const { rows, err } = query<{ id: string }>(sql`SELECT id FROM lemmas`) if (err) throw new Error('Database error: Failed to load tags') return rows } @@ -14,7 +14,7 @@ export const entries: EntryGenerator = async () => { export const load = async (event) => { const id = event.params.id - const { results, err } = await batch<[Lemma, CategoryShort, { id: string }]>([ + const { results, err } = batch<[Lemma, CategoryShort, { id: string }]>([ sql` SELECT title, claim, proof FROM lemmas WHERE id = ${id} `, diff --git a/src/routes/missing/+page.server.ts b/src/routes/missing/+page.server.ts index e645dfd6..b28c822c 100644 --- a/src/routes/missing/+page.server.ts +++ b/src/routes/missing/+page.server.ts @@ -7,7 +7,7 @@ import { get_missing_combinations } from '$lib/server/consistency' type CategoryPairShort = { id1: string; name1: string; id2: string; name2: string } export const load = async () => { - const { results, err } = await batch< + const { results, err } = batch< [ CategoryShort & { count: number }, CategoryShort & { count: number }, @@ -87,7 +87,7 @@ export const load = async () => { 0, ) - const missing_combinations = await get_missing_combinations() + const missing_combinations = get_missing_combinations() if (!missing_combinations) { error(500, 'Failed to load missing combinations')