diff --git a/.ai/knowledge/02-dependencies.md b/.ai/knowledge/02-dependencies.md index 26d531e1a..1853f35c7 100644 --- a/.ai/knowledge/02-dependencies.md +++ b/.ai/knowledge/02-dependencies.md @@ -22,7 +22,7 @@ bunx # Execute packages ### Development - **Turbo** 2.8.1 - Monorepo build orchestration -- **Biome** 2.3.13 - Linting and formatting +- **Biome** 2.3.14 - Linting and formatting - **Vitest** ^4.0.18 - Testing framework - **TypeDoc** ^0.28.16 - API documentation diff --git a/.ai/tasks/archive/cherry-pick-common-v8-SUPERSEDED.md b/.ai/tasks/archive/cherry-pick-common-v8-SUPERSEDED.md index 9c774a409..286a1a7e6 100644 --- a/.ai/tasks/archive/cherry-pick-common-v8-SUPERSEDED.md +++ b/.ai/tasks/archive/cherry-pick-common-v8-SUPERSEDED.md @@ -22,7 +22,7 @@ Migrating changes from `upstream/common-v8` to our fork, while preserving our st | Tool | Before | After | Status | | ------- | ------ | ------ | ---------------- | | Bun | 1.3.6 | 1.3.8 | ✅ Done | -| Biome | 2.3.13 | 2.3.13 | ✅ Current | +| Biome | 2.3.14 | 2.3.14 | ✅ Current | | Turbo | 2.8.1 | 2.8.1 | ✅ Current | | Node.js | >=24 | >=24 | ✅ LTS 24 correct | diff --git a/.changeset/create-query-builder.md b/.changeset/create-query-builder.md new file mode 100644 index 000000000..86868d34a --- /dev/null +++ b/.changeset/create-query-builder.md @@ -0,0 +1,16 @@ +--- +"@evolu/common": major +--- + +Replaced `evolu.createQuery` with standalone `createQueryBuilder` function + +Queries are now created using a standalone `createQueryBuilder` function instead of `evolu.createQuery` method. This enables query creation without an Evolu instance, improving code organization and enabling schema-first development. + +```ts +// Before +const todosQuery = evolu.createQuery((db) => db.selectFrom("todo").selectAll()); + +// After +const createQuery = createQueryBuilder(Schema); +const todosQuery = createQuery((db) => db.selectFrom("todo").selectAll()); +``` diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d85da0779..12b6fc92d 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -71,11 +71,6 @@ apps/ Follow these specific conventions and patterns: -## Test-driven development - -- Write a failing test before implementing a new feature or fixing a bug -- Keep test code cleaner than production code — good tests let you refactor production code; nothing protects messy tests - ## Code organization & imports - **Use named imports only** - avoid default exports and namespace imports @@ -498,6 +493,68 @@ const processTask: Task = async (run) => { const result = await sleep("1s")(run); ``` +## Test-driven development + +- Write a failing test before implementing a new feature or fixing a bug +- Run tests using the `runTests` tool with the test file path +- Test files are in `packages/*/test/*.test.ts` +- Use `testNames` parameter to run specific tests by name +- Run related tests after making code changes to verify correctness + +### Test structure + +- Use `describe` blocks to group related tests by feature or function +- Use `test` or `it` for individual test cases (both are equivalent) +- Test names should be descriptive phrases: `"returns true for non-empty array"` +- Use nested `describe` for sub-categories + +```ts +import { describe, expect, expectTypeOf, test } from "vitest"; + +describe("arrayFrom", () => { + test("creates array from iterable", () => { + const result = arrayFrom(new Set([1, 2, 3])); + expect(result).toEqual([1, 2, 3]); + }); + + test("returns input unchanged if already an array", () => { + const input = [1, 2, 3]; + const result = arrayFrom(input); + expect(result).toBe(input); + }); +}); +``` + +### Type testing + +Use `expectTypeOf` from Vitest for compile-time type assertions: + +```ts +import { expectTypeOf } from "vitest"; + +test("returns readonly array", () => { + const result = arrayFrom(2, () => "x"); + expectTypeOf(result).toEqualTypeOf>(); +}); + +test("NonEmptyArray requires at least one element", () => { + const _valid: NonEmptyArray = [1, 2, 3]; + // @ts-expect-error - empty array is not a valid NonEmptyArray + const _invalid: NonEmptyArray = []; +}); +``` + +### Inline snapshots + +Use `toMatchInlineSnapshot` for readable test output directly in the test file: + +```ts +test("Buffer", () => { + const buffer = createBuffer([1, 2, 3]); + expect(buffer.unwrap()).toMatchInlineSnapshot(`uint8:[1,2,3]`); +}); +``` + ## Testing - **Create deps per test** - use `testCreateDeps()` from `@evolu/common` for test isolation @@ -564,18 +621,6 @@ bun run test --filter @evolu/common -- -t "yields and returns ok" - **No prefixes** - avoid `feat:`, `fix:`, `feature:` etc. - **Be descriptive** - explain what the change does -```bash -# Good -Add support for custom error formatters -Fix memory leak in WebSocket reconnection -Update schema validation to handle edge cases - -# Avoid -feat: add support for custom error formatters -fix: memory leak in websocket reconnection -Update schema validation to handle edge cases. -``` - ## Changesets - **Write in past tense** - describe what was done, not what will be done diff --git a/AGENTS.md b/AGENTS.md index 1d3ab76b3..c04824132 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,13 +12,13 @@ ## 📊 Quick Context -| Aspect | Value | -|--------|-------| -| Package Manager | Bun 1.3.8 | -| Node.js | >=24.0.0 | -| Linter/Formatter | Biome 2.3.13 | -| Test Framework | Vitest | -| Upstream | evoluhq/evolu | +| Aspect | Value | +| ---------------- | ------------- | +| Package Manager | Bun 1.3.8 | +| Node.js | >=24.0.0 | +| Linter/Formatter | Biome 2.3.14 | +| Test Framework | Vitest | +| Upstream | evoluhq/evolu | ## 🗂️ Repository Structure @@ -92,13 +92,13 @@ bun run verify ## 📍 Related Resources -| Resource | Location | -|----------|----------| -| Issues | `../knowledge/05-Issues/` | -| Roadmap | `../knowledge/05-Issues/roadmap.md` | -| Architecture | `../knowledge/02-Architecture/` | -| Bench Suite | `../bench-suite/` (sibling repo) | -| Upstream | https://github.com/evoluhq/evolu | +| Resource | Location | +| ------------ | ----------------------------------- | +| Issues | `../knowledge/05-Issues/` | +| Roadmap | `../knowledge/05-Issues/roadmap.md` | +| Architecture | `../knowledge/02-Architecture/` | +| Bench Suite | `../bench-suite/` (sibling repo) | +| Upstream | https://github.com/evoluhq/evolu | ## 🤖 For AI Agents diff --git a/README.md b/README.md index 57bb03657..fbaf0ae2a 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ Linting Testing - `bun run test` - Run tests +- [Vitest VS Code extension](https://github.com/vitest-dev/vscode) Release diff --git a/apps/web/package.json b/apps/web/package.json index 057f7f0ea..18e0afed2 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -61,7 +61,7 @@ "@evolu/tsconfig": "workspace:*", "@types/mdx": "^2.0.13", "@types/node": "^24.10.9", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "@types/react-highlight-words": "^0.20.1", "@types/rss": "^0.0.32", diff --git a/apps/web/src/app/(playgrounds)/playgrounds/full/EvoluFullExample.tsx b/apps/web/src/app/(playgrounds)/playgrounds/full/EvoluFullExample.tsx index a89e6ec46..edd8ec328 100644 --- a/apps/web/src/app/(playgrounds)/playgrounds/full/EvoluFullExample.tsx +++ b/apps/web/src/app/(playgrounds)/playgrounds/full/EvoluFullExample.tsx @@ -5,6 +5,7 @@ import { createEvolu, createFormatTypeError, createObjectURL, + createQueryBuilder, FiniteNumber, id, idToIdBytes, @@ -99,6 +100,8 @@ const Schema = { }, }; +const createQuery = createQueryBuilder(Schema); + const deps = createEvoluDeps(); const evolu = createEvolu(deps)(Schema, { @@ -212,7 +215,7 @@ const App: FC = () => { ); }; -const projectsWithTodosQuery = evolu.createQuery( +const projectsWithTodosQuery = createQuery( (db) => db .selectFrom("project") @@ -409,7 +412,7 @@ const HomeTabProjectSectionTodoItem: FC<{ // Demonstrate history tracking. Evolu automatically tracks all changes // in the evolu_history table, making it easy to build audit logs or undo features. - const titleHistoryQuery = evolu.createQuery((db) => + const titleHistoryQuery = createQuery((db) => db .selectFrom("evolu_history") .select(["value", "timestamp"]) @@ -503,7 +506,7 @@ const HomeTabProjectSectionTodoItem: FC<{ ); }; -const projectsQuery = evolu.createQuery((db) => +const projectsQuery = createQuery((db) => db .selectFrom("project") .select(["id", "name", "fooJson"]) @@ -716,7 +719,7 @@ const AccountTab: FC = () => { ); }; -const deletedProjectsQuery = evolu.createQuery((db) => +const deletedProjectsQuery = createQuery((db) => db .selectFrom("project") .select(["id", "name", "updatedAt"]) @@ -728,7 +731,7 @@ const deletedProjectsQuery = evolu.createQuery((db) => type DeletedProjectsRow = typeof deletedProjectsQuery.Row; -const deletedTodosQuery = evolu.createQuery((db) => +const deletedTodosQuery = createQuery((db) => db .selectFrom("todo") .select(["id", "title", "isCompleted", "projectId", "updatedAt"]) diff --git a/apps/web/src/app/(playgrounds)/playgrounds/multitenant/EvoluMultitenantExample.tsx b/apps/web/src/app/(playgrounds)/playgrounds/multitenant/EvoluMultitenantExample.tsx index 9779988f1..eec1873f8 100644 --- a/apps/web/src/app/(playgrounds)/playgrounds/multitenant/EvoluMultitenantExample.tsx +++ b/apps/web/src/app/(playgrounds)/playgrounds/multitenant/EvoluMultitenantExample.tsx @@ -23,6 +23,9 @@ const Schema = { const deps = createEvoluDeps(); +// Create a typed query builder from the schema +const createQuery = Evolu.createQueryBuilder(Schema); + deps.evoluError.subscribe(() => { const error = deps.evoluError.get(); if (!error) return; @@ -73,7 +76,7 @@ export const EvoluMultitenantExample: FC = () => ( ); // Evolu uses Kysely for type-safe SQL (https://kysely.dev/). -const todosQuery = evolu.createQuery((db) => +const todosQuery = createQuery((db) => db // Type-safe SQL: try autocomplete for table and column names. .selectFrom("todo") diff --git a/biome.json b/biome.json index 6d7212062..ccf5ffd67 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.13/schema.json", + "$schema": "https://biomejs.dev/schemas/2.3.14/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/bun.lock b/bun.lock index 9fe08654a..eed8d2f5f 100644 --- a/bun.lock +++ b/bun.lock @@ -5,16 +5,19 @@ "": { "name": "@evolu/monorepo", "devDependencies": { - "@biomejs/biome": "2.3.13", + "@biomejs/biome": "2.3.14", "@changesets/cli": "^2.29.8", "@types/webpack": "^5.28.5", + "@vitest/browser": "^4.0.17", + "@vitest/browser-playwright": "^4.0.17", + "@vitest/coverage-v8": "^4.0.17", "rimraf": "^6.1.2", - "turbo": "^2.8.2", + "turbo": "^2.8.3", "typedoc": "^0.28.16", "typedoc-plugin-markdown": "^4.9.0", "typescript": "^5.9.3", "vitest": "^4.0.17", - "webpack": "^5.104.1", + "webpack": "^5.105.0", }, }, "apps/relay": { @@ -79,7 +82,7 @@ "@evolu/tsconfig": "workspace:*", "@types/mdx": "^2.0.13", "@types/node": "^24.10.9", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "@types/react-highlight-words": "^0.20.1", "@types/rss": "^0.0.32", @@ -91,15 +94,15 @@ "name": "@example/angular-vite-pwa", "version": "0.0.0", "dependencies": { - "@angular/core": "^21.1.0", - "@angular/platform-browser": "^21.1.0", - "@evolu/common": "latest", - "@evolu/web": "latest", + "@angular/core": "^21.1.3", + "@angular/platform-browser": "^21.1.3", + "@evolu/common": "workspace:*", + "@evolu/web": "workspace:*", }, "devDependencies": { "@analogjs/vite-plugin-angular": "^2.2.2", "@angular/build": "^21.1.0", - "@angular/compiler-cli": "^21.1.0", + "@angular/compiler-cli": "^21.1.3", "@tailwindcss/vite": "^4.1.18", "@vite-pwa/assets-generator": "^1.0.2", "tailwindcss": "^4.1.18", @@ -112,14 +115,14 @@ "name": "@example/react-electron", "version": "0.0.0", "dependencies": { - "@evolu/common": "latest", - "@evolu/react": "latest", - "@evolu/react-web": "latest", + "@evolu/common": "workspace:*", + "@evolu/react": "workspace:*", + "@evolu/react-web": "workspace:*", "react": "19.2.4", "react-dom": "19.2.4", }, "devDependencies": { - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "@vitejs/plugin-react": "^5.1.3", "electron": "38.2.0", @@ -135,9 +138,9 @@ "version": "1.0.0", "dependencies": { "@blazejkustra/react-native-alert": "^1.0.0", - "@evolu/common": "latest", - "@evolu/react": "latest", - "@evolu/react-native": "latest", + "@evolu/common": "workspace:*", + "@evolu/react": "workspace:*", + "@evolu/react-native": "workspace:*", "@expo/metro-runtime": "^6.1.2", "@expo/vector-icons": "^15.0.3", "abort-signal-polyfill": "^1.0.0", @@ -155,7 +158,7 @@ "react-native-quick-crypto": "^1.0.6", "react-native-safe-area-context": "^5.6.2", "react-native-screens": "^4.21.0", - "react-native-svg": "^15.15.1", + "react-native-svg": "^15.15.2", "set.prototype.difference": "^1.1.7", "set.prototype.intersection": "^1.1.8", "set.prototype.isdisjointfrom": "^1.1.5", @@ -168,7 +171,7 @@ "@babel/core": "^7.28.6", "@babel/plugin-transform-explicit-resource-management": "^7.28.6", "@babel/plugin-transform-modules-commonjs": "^7.28.6", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "typescript": "^5.9.3", }, }, @@ -176,9 +179,9 @@ "name": "@example/react-nextjs", "version": "0.1.0", "dependencies": { - "@evolu/common": "latest", - "@evolu/react": "latest", - "@evolu/react-web": "latest", + "@evolu/common": "workspace:*", + "@evolu/react": "workspace:*", + "@evolu/react-web": "workspace:*", "@tabler/icons-react": "^3.36.1", "clsx": "^2.1.1", "next": "^16.1.3", @@ -189,7 +192,7 @@ "@tailwindcss/forms": "^0.5.11", "@tailwindcss/postcss": "^4.1.18", "@types/node": "^24.10.9", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "postcss": "^8.5.6", "tailwindcss": "^4.1.18", @@ -200,9 +203,9 @@ "name": "@example/react-vite-pwa", "version": "0.0.0", "dependencies": { - "@evolu/common": "latest", - "@evolu/react": "latest", - "@evolu/react-web": "latest", + "@evolu/common": "workspace:*", + "@evolu/react": "workspace:*", + "@evolu/react-web": "workspace:*", "@tabler/icons-react": "^3.36.1", "clsx": "^2.1.1", "react": "19.2.4", @@ -212,7 +215,7 @@ "devDependencies": { "@tailwindcss/forms": "^0.5.11", "@tailwindcss/vite": "^4.1.18", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "@vite-pwa/assets-generator": "^1.0.2", "@vitejs/plugin-react": "^5.1.3", @@ -231,8 +234,8 @@ "@evolu/svelte": "workspace:*", "@evolu/web": "workspace:*", "@sveltejs/vite-plugin-svelte": "^6.2.4", - "@tsconfig/svelte": "^5.0.6", - "svelte": "^5.48.2", + "@tsconfig/svelte": "^5.0.7", + "svelte": "^5.49.2", "svelte-check": "^4.3.6", "tslib": "^2.8.1", "typescript": "^5.9.3", @@ -244,9 +247,9 @@ "name": "@example/vue-vite-pwa", "version": "0.0.0", "dependencies": { - "@evolu/common": "latest", - "@evolu/vue": "latest", - "@evolu/web": "latest", + "@evolu/common": "workspace:*", + "@evolu/vue": "workspace:*", + "@evolu/web": "workspace:*", "vue": "^3.5.26", "workbox-window": "^7.4.0", }, @@ -268,27 +271,20 @@ "@noble/hashes": "^2.0.1", "@scure/bip39": "^2.0.1", "disposablestack": "^1.1.7", - "kysely": "^0.28.10", + "kysely": "^0.28.11", "msgpackr": "^1.11.8", + "playwright": "^1.58.1", "random": "^5.4.1", + "typescript": "^5.9.3", + "webpack": "^5.105.0", + "ws": "^8.19.0", }, "devDependencies": { - "@bokuweb/zstd-wasm": "0.0.27", - "@evolu/tsconfig": "workspace:*", + "@bokuweb/zstd-wasm": "^0.0.27", "@types/better-sqlite3": "^7.6.13", - "@types/node": "^24.10.9", - "@types/webpack": "^5.28.5", "@types/ws": "^8.18.1", - "@vitest/browser": "^4.0.17", - "@vitest/browser-playwright": "^4.0.17", - "@vitest/coverage-v8": "^4.0.18", "better-sqlite3": "^12.6.2", "fast-check": "^4.5.3", - "playwright": "^1.58.1", - "typescript": "^5.9.3", - "vitest": "^4.0.17", - "webpack": "^5.104.1", - "ws": "^8.19.0", }, }, "packages/nodejs": { @@ -304,9 +300,7 @@ "@types/better-sqlite3": "^7.6.13", "@types/node": "^24.10.9", "@types/ws": "^8.18.1", - "@vitest/coverage-v8": "^4.0.18", "typescript": "^5.9.3", - "vitest": "^4.0.17", }, "peerDependencies": { "@evolu/common": "^7.4.1", @@ -318,11 +312,10 @@ "devDependencies": { "@evolu/common": "workspace:*", "@evolu/tsconfig": "workspace:*", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "react": "19.2.4", "typescript": "^5.9.3", - "vitest": "^4.0.17", }, "peerDependencies": { "@evolu/common": "^7.4.1", @@ -337,8 +330,7 @@ "@evolu/react": "workspace:*", "@evolu/tsconfig": "workspace:*", "@op-engineering/op-sqlite": "^15.2.2", - "@types/react": "~19.2.10", - "@vitest/coverage-v8": "^4.0.18", + "@types/react": "~19.2.11", "expo": "^54.0.31", "expo-secure-store": "~15.0.8", "expo-sqlite": "~16.0.10", @@ -346,9 +338,8 @@ "react-native": "^0.81.5", "react-native-nitro-modules": "^0.31.10", "react-native-sensitive-info": "6.0.0-rc.11", - "react-native-svg": "^15.15.1", + "react-native-svg": "^15.15.2", "typescript": "^5.9.3", - "vitest": "^4.0.17", }, "peerDependencies": { "@evolu/common": "^7.4.1", @@ -380,13 +371,12 @@ "@evolu/common": "workspace:*", "@evolu/tsconfig": "workspace:*", "@evolu/web": "workspace:*", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "react": "19.2.4", "react-dom": "19.2.4", "typescript": "^5.9.3", "user-agent-data-types": "^0.4.2", - "vitest": "^4.0.17", }, "peerDependencies": { "@evolu/common": "^7.4.1", @@ -403,15 +393,15 @@ "@evolu/tsconfig": "workspace:*", "@evolu/web": "workspace:*", "@sveltejs/package": "^2.5.7", - "@tsconfig/svelte": "^5.0.6", - "svelte": "^5.48.2", + "@tsconfig/svelte": "^5.0.7", + "svelte": "^5.49.2", "svelte-check": "^4.3.6", "typescript": "^5.9.3", }, "peerDependencies": { "@evolu/common": "^7.4.1", "@evolu/web": "^2.4.0", - "svelte": ">=5", + "svelte": ">=5.49.2", }, }, "packages/tsconfig": { @@ -425,7 +415,6 @@ "@evolu/common": "workspace:*", "@evolu/tsconfig": "workspace:*", "typescript": "^5.9.3", - "vitest": "^4.0.17", }, "peerDependencies": { "@evolu/common": "^7.4.1", @@ -444,12 +433,8 @@ "@evolu/tsconfig": "workspace:*", "@types/sharedworker": "^0.0.211", "@types/web-locks-api": "^0.0.5", - "@vitest/browser": "^4.0.17", - "@vitest/browser-playwright": "^4.0.17", - "@vitest/coverage-v8": "^4.0.18", "typescript": "^5.9.3", "user-agent-data-types": "^0.4.2", - "vitest": "^4.0.17", }, "peerDependencies": { "@evolu/common": "^7.4.1", @@ -520,15 +505,15 @@ "@angular/build": ["@angular/build@21.1.2", "", { "dependencies": { "@ampproject/remapping": "2.3.0", "@angular-devkit/architect": "0.2101.2", "@babel/core": "7.28.5", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", "@inquirer/confirm": "5.1.21", "@vitejs/plugin-basic-ssl": "2.1.0", "beasties": "0.3.5", "browserslist": "^4.26.0", "esbuild": "0.27.2", "https-proxy-agent": "7.0.6", "istanbul-lib-instrument": "6.0.3", "jsonc-parser": "3.3.1", "listr2": "9.0.5", "magic-string": "0.30.21", "mrmime": "2.0.1", "parse5-html-rewriting-stream": "8.0.0", "picomatch": "4.0.3", "piscina": "5.1.4", "rolldown": "1.0.0-beta.58", "sass": "1.97.1", "semver": "7.7.3", "source-map-support": "0.5.21", "tinyglobby": "0.2.15", "undici": "7.18.2", "vite": "7.3.0", "watchpack": "2.5.0" }, "optionalDependencies": { "lmdb": "3.4.4" }, "peerDependencies": { "@angular/compiler": "^21.0.0", "@angular/compiler-cli": "^21.0.0", "@angular/core": "^21.0.0", "@angular/localize": "^21.0.0", "@angular/platform-browser": "^21.0.0", "@angular/platform-server": "^21.0.0", "@angular/service-worker": "^21.0.0", "@angular/ssr": "^21.1.2", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^21.0.0", "postcss": "^8.4.0", "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", "tslib": "^2.3.0", "typescript": ">=5.9 <6.0", "vitest": "^4.0.8" }, "optionalPeers": ["@angular/core", "@angular/localize", "@angular/platform-browser", "@angular/platform-server", "@angular/service-worker", "@angular/ssr", "karma", "less", "ng-packagr", "postcss", "tailwindcss", "vitest"] }, "sha512-5hl7OTZeQcdkr/3LXSijLuUCwlcqGyYJYOb8GbFqSifSR03JFI3tLQtyQ0LX2CXv3MOx1qFUQbYVfcjW5M36QQ=="], - "@angular/common": ["@angular/common@21.1.2", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/core": "21.1.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "sha512-NK26OG1+/3EXLDWstSPmdGbkpt8bP9AsT9J7EBornMswUjmQDbjyb85N/esKjRjDMkw4p/aKpBo24eCV5uUmBA=="], + "@angular/common": ["@angular/common@21.1.3", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/core": "21.1.3", "rxjs": "^6.5.3 || ^7.4.0" } }, "sha512-Wdbln/UqZM5oVnpfIydRdhhL8A9x3bKZ9Zy1/mM0q+qFSftPvmFZIXhEpFqbDwNYbGUhGzx7t8iULC4sVVp/zA=="], - "@angular/compiler": ["@angular/compiler@21.1.2", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-5OFdZPNix7iK4HSdRxPgg74VvcmQZAMzv9ACYZ8iGfNxiJUjFSurfz0AtVEh0oE2oZDH1v48bHI1s+0ljCHZhA=="], + "@angular/compiler": ["@angular/compiler@21.1.3", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-gDNLh7MEf7Qf88ktZzS4LJQXCA5U8aQTfK9ak+0mi2ruZ0x4XSjQCro4H6OPKrrbq94+6GcnlSX5+oVIajEY3w=="], - "@angular/compiler-cli": ["@angular/compiler-cli@21.1.2", "", { "dependencies": { "@babel/core": "7.28.5", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^5.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", "yargs": "^18.0.0" }, "peerDependencies": { "@angular/compiler": "21.1.2", "typescript": ">=5.9 <6.0" }, "optionalPeers": ["typescript"], "bin": { "ngc": "bundles/src/bin/ngc.js", "ng-xi18n": "bundles/src/bin/ng_xi18n.js" } }, "sha512-h+sX7QvSz58KvmRwNMa33EZHti8Cnw1DL01kInJ/foDchC/O2VMOumeGHS+lAe48t2Nbhiq/obgf275TkDZYsA=="], + "@angular/compiler-cli": ["@angular/compiler-cli@21.1.3", "", { "dependencies": { "@babel/core": "7.28.5", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^5.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", "yargs": "^18.0.0" }, "peerDependencies": { "@angular/compiler": "21.1.3", "typescript": ">=5.9 <6.0" }, "optionalPeers": ["typescript"], "bin": { "ngc": "bundles/src/bin/ngc.js", "ng-xi18n": "bundles/src/bin/ng_xi18n.js" } }, "sha512-nKxoQ89W2B1WdonNQ9kgRnvLNS6DAxDrRHBslsKTlV+kbdv7h59M9PjT4ZZ2sp1M/M8LiofnUfa/s2jd/xYj5w=="], - "@angular/core": ["@angular/core@21.1.2", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/compiler": "21.1.2", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, "optionalPeers": ["@angular/compiler", "zone.js"] }, "sha512-W2xxRb7noOD1DdMwKaZ3chFhii6nutaNIXt7dfWsMWoujg3Kqpdn1ukeyW5aHKQZvCJTIGr4f3whZ8Sj/17aCA=="], + "@angular/core": ["@angular/core@21.1.3", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/compiler": "21.1.3", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, "optionalPeers": ["@angular/compiler", "zone.js"] }, "sha512-TbhQxRC7Lb/3WBdm1n8KRsktmVEuGBBp0WRF5mq0Ze4s1YewIM6cULrSw9ACtcL5jdcq7c74ms+uKQsaP/gdcQ=="], - "@angular/platform-browser": ["@angular/platform-browser@21.1.2", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "21.1.2", "@angular/common": "21.1.2", "@angular/core": "21.1.2" }, "optionalPeers": ["@angular/animations"] }, "sha512-8vnCbQhxugQ3meGQ0YlSp0uNBYUjpFXYjFnGQ0Xq5jvzc9WX7KSix6+AydEjZtQfc1bWRetBTOlhQpqnwYp53g=="], + "@angular/platform-browser": ["@angular/platform-browser@21.1.3", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "21.1.3", "@angular/common": "21.1.3", "@angular/core": "21.1.3" }, "optionalPeers": ["@angular/animations"] }, "sha512-W+ZMXAioaP7CsACafBCHsIxiiKrRTPOlQ+hcC7XNBwy+bn5mjGONoCgLreQs76M8HNWLtr/OAUAr6h26OguOuA=="], "@apideck/better-ajv-errors": ["@apideck/better-ajv-errors@0.3.6", "", { "dependencies": { "json-schema": "^0.4.0", "jsonpointer": "^5.0.0", "leven": "^3.1.0" }, "peerDependencies": { "ajv": ">=8" } }, "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA=="], @@ -538,7 +523,7 @@ "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], - "@babel/generator": ["@babel/generator@7.29.0", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ=="], + "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], @@ -786,23 +771,23 @@ "@bcoe/v8-coverage": ["@bcoe/v8-coverage@1.0.2", "", {}, "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA=="], - "@biomejs/biome": ["@biomejs/biome@2.3.13", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.13", "@biomejs/cli-darwin-x64": "2.3.13", "@biomejs/cli-linux-arm64": "2.3.13", "@biomejs/cli-linux-arm64-musl": "2.3.13", "@biomejs/cli-linux-x64": "2.3.13", "@biomejs/cli-linux-x64-musl": "2.3.13", "@biomejs/cli-win32-arm64": "2.3.13", "@biomejs/cli-win32-x64": "2.3.13" }, "bin": { "biome": "bin/biome" } }, "sha512-Fw7UsV0UAtWIBIm0M7g5CRerpu1eKyKAXIazzxhbXYUyMkwNrkX/KLkGI7b+uVDQ5cLUMfOC9vR60q9IDYDstA=="], + "@biomejs/biome": ["@biomejs/biome@2.3.14", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.14", "@biomejs/cli-darwin-x64": "2.3.14", "@biomejs/cli-linux-arm64": "2.3.14", "@biomejs/cli-linux-arm64-musl": "2.3.14", "@biomejs/cli-linux-x64": "2.3.14", "@biomejs/cli-linux-x64-musl": "2.3.14", "@biomejs/cli-win32-arm64": "2.3.14", "@biomejs/cli-win32-x64": "2.3.14" }, "bin": { "biome": "bin/biome" } }, "sha512-QMT6QviX0WqXJCaiqVMiBUCr5WRQ1iFSjvOLoTk6auKukJMvnMzWucXpwZB0e8F00/1/BsS9DzcKgWH+CLqVuA=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0OCwP0/BoKzyJHnFdaTk/i7hIP9JHH9oJJq6hrSCPmJPo8JWcJhprK4gQlhFzrwdTBAW4Bjt/RmCf3ZZe59gwQ=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UJGPpvWJMkLxSRtpCAKfKh41Q4JJXisvxZL8ChN1eNW3m/WlPFJ6EFDCE7YfUb4XS8ZFi3C1dFpxUJ0Ety5n+A=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-AGr8OoemT/ejynbIu56qeil2+F2WLkIjn2d8jGK1JkchxnMUhYOfnqc9sVzcRxpG9Ycvw4weQ5sprRvtb7Yhcw=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-PNkLNQG6RLo8lG7QoWe/hhnMxJIt1tEimoXpGQjwS/dkdNiKBLPv4RpeQl8o3s1OKI3ZOR5XPiYtmbGGHAOnLA=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-xvOiFkrDNu607MPMBUQ6huHmBG1PZLOrqhtK6pXJW3GjfVqJg0Z/qpTdhXfcqWdSZHcT+Nct2fOgewZvytESkw=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-KT67FKfzIw6DNnUNdYlBg+eU24Go3n75GWK6NwU4+yJmDYFe9i/MjiI+U/iEzKvo0g7G7MZqoyrhIYuND2w8QQ=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-TUdDCSY+Eo/EHjhJz7P2GnWwfqet+lFxBZzGHldrvULr59AgahamLs/N85SC4+bdF86EhqDuuw9rYLvLFWWlXA=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-LInRbXhYujtL3sH2TMCH/UBwJZsoGwfQjBrMfl84CD4hL/41C/EU5mldqf1yoFpsI0iPWuU83U+nB2TUUypWeg=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.13", "", { "os": "linux", "cpu": "x64" }, "sha512-s+YsZlgiXNq8XkgHs6xdvKDFOj/bwTEevqEY6rC2I3cBHbxXYU1LOZstH3Ffw9hE5tE1sqT7U23C00MzkXztMw=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-ZsZzQsl9U+wxFrGGS4f6UxREUlgHwmEfu1IrXlgNFrNnd5Th6lIJr8KmSzu/+meSa9f4rzFrbEW9LBBA6ScoMA=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.13", "", { "os": "linux", "cpu": "x64" }, "sha512-0bdwFVSbbM//Sds6OjtnmQGp4eUjOTt6kHvR/1P0ieR9GcTUAlPNvPC3DiavTqq302W34Ae2T6u5VVNGuQtGlQ=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.14", "", { "os": "linux", "cpu": "x64" }, "sha512-KQU7EkbBBuHPW3/rAcoiVmhlPtDSGOGRPv9js7qJVpYTzjQmVR+C9Rfcz+ti8YCH+zT1J52tuBybtP4IodjxZQ=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-QweDxY89fq0VvrxME+wS/BXKmqMrOTZlN9SqQ79kQSIc3FrEwvW/PvUegQF6XIVaekncDykB5dzPqjbwSKs9DA=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-+IKYkj/pUBbnRf1G1+RlyA3LWiDgra1xpS7H2g4BuOzzRbRB+hmlw0yFsLprHhbbt7jUzbzAbAjK/Pn0FDnh1A=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.13", "", { "os": "win32", "cpu": "x64" }, "sha512-trDw2ogdM2lyav9WFQsdsfdVy1dvZALymRpgmWsvSez0BJzBjulhOT/t+wyKeh3pZWvwP3VMs1SoOKwO3wecMQ=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.14", "", { "os": "win32", "cpu": "x64" }, "sha512-oizCjdyQ3WJEswpb3Chdngeat56rIdSYK12JI3iI11Mt5T5EXcZ7WLuowzEaFPNJ3zmOQFliMN8QY1Pi+qsfdQ=="], "@blazejkustra/react-native-alert": ["@blazejkustra/react-native-alert@1.0.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-bgvKlnhfS39vz38BSBdHk1smVME0Nf5tJEzgoQOIPpci8KuTBcOORa93B2PV3/S5a0QkR1d8nW2yw76HDj6zqQ=="], @@ -1090,7 +1075,7 @@ "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], - "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], + "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.1", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ=="], "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], @@ -1318,13 +1303,13 @@ "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], - "@react-aria/focus": ["@react-aria/focus@3.21.3", "", { "dependencies": { "@react-aria/interactions": "^3.26.0", "@react-aria/utils": "^3.32.0", "@react-types/shared": "^3.32.1", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-FsquWvjSCwC2/sBk4b+OqJyONETUIXQ2vM0YdPAuC+QFQh2DT6TIBo6dOZVSezlhudDla69xFBd6JvCFq1AbUw=="], + "@react-aria/focus": ["@react-aria/focus@3.21.4", "", { "dependencies": { "@react-aria/interactions": "^3.27.0", "@react-aria/utils": "^3.33.0", "@react-types/shared": "^3.33.0", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-6gz+j9ip0/vFRTKJMl3R30MHopn4i19HqqLfSQfElxJD+r9hBnYG1Q6Wd/kl/WRR1+CALn2F+rn06jUnf5sT8Q=="], - "@react-aria/interactions": ["@react-aria/interactions@3.26.0", "", { "dependencies": { "@react-aria/ssr": "^3.9.10", "@react-aria/utils": "^3.32.0", "@react-stately/flags": "^3.1.2", "@react-types/shared": "^3.32.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-AAEcHiltjfbmP1i9iaVw34Mb7kbkiHpYdqieWufldh4aplWgsF11YQZOfaCJW4QoR2ML4Zzoa9nfFwLXA52R7Q=="], + "@react-aria/interactions": ["@react-aria/interactions@3.27.0", "", { "dependencies": { "@react-aria/ssr": "^3.9.10", "@react-aria/utils": "^3.33.0", "@react-stately/flags": "^3.1.2", "@react-types/shared": "^3.33.0", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-D27pOy+0jIfHK60BB26AgqjjRFOYdvVSkwC31b2LicIzRCSPOSP06V4gMHuGmkhNTF4+YWDi1HHYjxIvMeiSlA=="], "@react-aria/ssr": ["@react-aria/ssr@3.9.10", "", { "dependencies": { "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ=="], - "@react-aria/utils": ["@react-aria/utils@3.32.0", "", { "dependencies": { "@react-aria/ssr": "^3.9.10", "@react-stately/flags": "^3.1.2", "@react-stately/utils": "^3.11.0", "@react-types/shared": "^3.32.1", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-/7Rud06+HVBIlTwmwmJa2W8xVtgxgzm0+kLbuFooZRzKDON6hhozS1dOMR/YLMxyJOaYOTpImcP4vRR9gL1hEg=="], + "@react-aria/utils": ["@react-aria/utils@3.33.0", "", { "dependencies": { "@react-aria/ssr": "^3.9.10", "@react-stately/flags": "^3.1.2", "@react-stately/utils": "^3.11.0", "@react-types/shared": "^3.33.0", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-yvz7CMH8d2VjwbSa5nGXqjU031tYhD8ddax95VzJsHSPyqHDEGfxul8RkhGV6oO7bVqZxVs6xY66NIgae+FHjw=="], "@react-native/assets-registry": ["@react-native/assets-registry@0.81.5", "", {}, "sha512-705B6x/5Kxm1RKRvSv0ADYWm5JOnoiQ1ufW7h8uu2E6G9Of/eE6hP/Ivw3U5jI16ERqZxiKQwk34VJbB0niX9w=="], @@ -1364,7 +1349,7 @@ "@react-stately/utils": ["@react-stately/utils@3.11.0", "", { "dependencies": { "@swc/helpers": "^0.5.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-8LZpYowJ9eZmmYLpudbo/eclIRnbhWIJZ994ncmlKlouNzKohtM8qTC6B1w1pwUbiwGdUoyzLuQbeaIor5Dvcw=="], - "@react-types/shared": ["@react-types/shared@3.32.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-famxyD5emrGGpFuUlgOP6fVW2h/ZaF405G5KDi3zPHzyjAWys/8W6NAVJtNbkCkhedmvL0xOhvt8feGXyXaw5w=="], + "@react-types/shared": ["@react-types/shared@3.33.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-xuUpP6MyuPmJtzNOqF5pzFUIHH2YogyOQfUQHag54PRmWB7AbjuGWBUv0l1UDmz6+AbzAYGmDVAzcRDOu2PFpw=="], "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-beta.58", "", { "os": "android", "cpu": "arm64" }, "sha512-mWj5eE4Qc8TbPdGGaaLvBb9XfDPvE1EmZkJQgiGKwchkWH4oAJcRAKMTw7ZHnb1L+t7Ah41sBkAecaIsuUgsug=="], @@ -1472,7 +1457,7 @@ "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], - "@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="], + "@sinclair/typebox": ["@sinclair/typebox@0.27.10", "", {}, "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA=="], "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], @@ -1546,7 +1531,7 @@ "@ts-morph/common": ["@ts-morph/common@0.22.0", "", { "dependencies": { "fast-glob": "^3.3.2", "minimatch": "^9.0.3", "mkdirp": "^3.0.1", "path-browserify": "^1.0.1" } }, "sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw=="], - "@tsconfig/svelte": ["@tsconfig/svelte@5.0.6", "", {}, "sha512-yGxYL0I9eETH1/DR9qVJey4DAsCdeau4a9wYPKuXfEhm8lFO8wg+LLYJjIpAm6Fw7HSlhepPhYPDop75485yWQ=="], + "@tsconfig/svelte": ["@tsconfig/svelte@5.0.7", "", {}, "sha512-NOtJF9LQnV7k6bpzcXwL/rXdlFHvAT9e0imrftiMc6/+FUNBHRZ8UngDrM+jciA6ENzFYNoFs8rfwumuGF+Dhw=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], @@ -1604,7 +1589,7 @@ "@types/plist": ["@types/plist@3.0.5", "", { "dependencies": { "@types/node": "*", "xmlbuilder": ">=11.0.1" } }, "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA=="], - "@types/react": ["@types/react@19.2.10", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw=="], + "@types/react": ["@types/react@19.2.11", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-tORuanb01iEzWvMGVGv2ZDhYZVeRMrw453DCSAIn/5yvcSVnMoUMTyf33nQJLahYEnv9xqrTNbgz4qY5EfSh0g=="], "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], @@ -1920,7 +1905,7 @@ "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001767", "", {}, "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ=="], + "caniuse-lite": ["caniuse-lite@1.0.30001768", "", {}, "sha512-qY3aDRZC5nWPgHUgIB84WL+nySuo19wk0VJpp/XI9T34lrvkyhRvNVOFJOp2kxClQhiFBu+TaUSudf6oa3vkSA=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], @@ -2360,7 +2345,7 @@ "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], - "glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="], + "glob": ["glob@13.0.1", "", { "dependencies": { "minimatch": "^10.1.2", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-B7U/vJpE3DkJ5WXTgTpTRN63uV42DseiXXKMwG14LQBXmsdeIoHAPbU/MEo6II0k5ED74uc2ZGTC6MwHFQhF6w=="], "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -2700,7 +2685,7 @@ "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], - "magicast": ["magicast@0.5.1", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "source-map-js": "^1.2.1" } }, "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw=="], + "magicast": ["magicast@0.5.2", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ=="], "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], @@ -3162,7 +3147,7 @@ "react-native-sensitive-info": ["react-native-sensitive-info@6.0.0-rc.11", "", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-nitro-modules": "*" } }, "sha512-nBVUcjXK4T2KjdH+nIZaCgS0HbX8AtiOWSvAdkZEoOvnUxpo+l+r9dvSWcIPbhj/EHLiZmTM4WbEATLokwe5tQ=="], - "react-native-svg": ["react-native-svg@15.15.1", "", { "dependencies": { "css-select": "^5.1.0", "css-tree": "^1.1.3", "warn-once": "0.1.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-ZUD1xwc3Hwo4cOmOLumjJVoc7lEf9oQFlHnLmgccLC19fNm6LVEdtB+Cnip6gEi0PG3wfvVzskViEtrySQP8Fw=="], + "react-native-svg": ["react-native-svg@15.15.2", "", { "dependencies": { "css-select": "^5.1.0", "css-tree": "^1.1.3", "warn-once": "0.1.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-lpaSwA2i+eLvcEdDZyGgMEInQW99K06zjJqfMFblE0yxI0SCN5E4x6in46f0IYi6i3w2t2aaq3oOnyYBe+bo4w=="], "react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="], @@ -3478,7 +3463,7 @@ "suppressed-error": ["suppressed-error@1.0.3", "", { "dependencies": { "define-data-property": "^1.1.1", "define-properties": "^1.2.1", "es-abstract": "^1.22.3", "es-errors": "^1.1.0", "function-bind": "^1.1.2", "globalthis": "^1.0.3", "has-property-descriptors": "^1.0.1", "set-function-name": "^2.0.1" } }, "sha512-6+ZiCVUmDLFRyYRswTrDTYWaM/IT01W/cqQBLnnyg8T0njVrWj3tP+EXFevXk6qK61yDXnmZsOFVzFfYoUy/KA=="], - "svelte": ["svelte@5.49.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.2", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-jj95WnbKbXsXXngYj28a4zx8jeZx50CN/J4r0CEeax2pbfdsETv/J1K8V9Hbu3DCXnpHz5qAikICuxEooi7eNQ=="], + "svelte": ["svelte@5.49.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.2", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-PYLwnngYzyhKzqDlGVlCH4z+NVI8mC0/bTv15vw25CcdOhxENsOHIbQ36oj5DIf3oBazM+STbCAvaskpxtBmWA=="], "svelte-check": ["svelte-check@4.3.6", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-uBkz96ElE3G4pt9E1Tw0xvBfIUQkeH794kDQZdAUk795UVMr+NJZpuFSS62vcmO/DuSalK83LyOwhgWq8YGU1Q=="], @@ -3560,19 +3545,19 @@ "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "turbo": ["turbo@2.8.2", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.2", "turbo-darwin-arm64": "2.8.2", "turbo-linux-64": "2.8.2", "turbo-linux-arm64": "2.8.2", "turbo-windows-64": "2.8.2", "turbo-windows-arm64": "2.8.2" }, "bin": { "turbo": "bin/turbo" } }, "sha512-biW/S5hENCcJ5vxxJszCozEKcXtwGK29vxXzNbdfY/0q7QpYTCoyKdj0e8k/ADA6qkqaKDJwgrrHbC8Vy6wszg=="], + "turbo": ["turbo@2.8.3", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.3", "turbo-darwin-arm64": "2.8.3", "turbo-linux-64": "2.8.3", "turbo-linux-arm64": "2.8.3", "turbo-windows-64": "2.8.3", "turbo-windows-arm64": "2.8.3" }, "bin": { "turbo": "bin/turbo" } }, "sha512-8Osxz5Tu/Dw2kb31EAY+nhq/YZ3wzmQSmYa1nIArqxgCAldxv9TPlrAiaBUDVnKA4aiPn0OFBD1ACcpc5VFOAQ=="], - "turbo-darwin-64": ["turbo-darwin-64@2.8.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-sumREbxABHxrWIwlK67sZEaDRE7+BFSU8gZj8OK+X7dLpgW1vTjsHzTECB5m2qzWlXHRdueAk8sKv7wyHqv9jw=="], + "turbo-darwin-64": ["turbo-darwin-64@2.8.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-4kXRLfcygLOeNcP6JquqRLmGB/ATjjfehiojL2dJkL7GFm3SPSXbq7oNj8UbD8XriYQ5hPaSuz59iF1ijPHkTw=="], - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-J3zoDkf+k9yozdJmdNUOc9YfIoFs01Zm+GgNyfY8pU6siMWlPlgdt+3ezbIMeOns6CAQUzUcqo9awowykAS9Vw=="], + "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-xF7uCeC0UY0Hrv/tqax0BMbFlVP1J/aRyeGQPZT4NjvIPj8gSPDgFhfkfz06DhUwDg5NgMo04uiSkAWE8WB/QQ=="], - "turbo-linux-64": ["turbo-linux-64@2.8.2", "", { "os": "linux", "cpu": "x64" }, "sha512-iVYUM+tyNAPd34HhMSjYWi7OSXnxnDhPjFKVvzSb7cZmQS6GlDSr7MALc5Wt/zn6/7jm1FuS7c5Wffg9WD2e1Q=="], + "turbo-linux-64": ["turbo-linux-64@2.8.3", "", { "os": "linux", "cpu": "x64" }, "sha512-vxMDXwaOjweW/4etY7BxrXCSkvtwh0PbwVafyfT1Ww659SedUxd5rM3V2ZCmbwG8NiCfY7d6VtxyHx3Wh1GoZA=="], - "turbo-linux-arm64": ["turbo-linux-arm64@2.8.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-v7FJAHUhY2nSEE87mr5ZBO51GmsFKp0EmK2P6rO+vGimCPmnGlLNj1at/eVcnp/cHRDnJj8J+b3QHWdUzTPTkg=="], + "turbo-linux-arm64": ["turbo-linux-arm64@2.8.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-mQX7uYBZFkuPLLlKaNe9IjR1JIef4YvY8f21xFocvttXvdPebnq3PK1Zjzl9A1zun2BEuWNUwQIL8lgvN9Pm3Q=="], - "turbo-windows-64": ["turbo-windows-64@2.8.2", "", { "os": "win32", "cpu": "x64" }, "sha512-d1X+U5JLhyAse0VXM0rpmu6iLbBTAvjwc7MX0PBkEaTz2aZQqOHBpQkkrxia7bZzRNbfXHbGSqY/vbE3GSFWzw=="], + "turbo-windows-64": ["turbo-windows-64@2.8.3", "", { "os": "win32", "cpu": "x64" }, "sha512-YLGEfppGxZj3VWcNOVa08h6ISsVKiG85aCAWosOKNUjb6yErWEuydv6/qImRJUI+tDLvDvW7BxopAkujRnWCrw=="], - "turbo-windows-arm64": ["turbo-windows-arm64@2.8.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-fMln07/l/5kscs79V0kTwdf17gkZW+E2iyqnzz691gLM7Jf6la0afd3IMsNtLzUh+dxKIFCswNiFVmHe8g+2jA=="], + "turbo-windows-arm64": ["turbo-windows-arm64@2.8.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-afTUGKBRmOJU1smQSBnFGcbq0iabAPwh1uXu2BVk7BREg30/1gMnJh9DFEQTah+UD3n3ru8V55J83RQNFfqoyw=="], "type-detect": ["type-detect@4.0.8", "", {}, "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="], @@ -3710,7 +3695,7 @@ "webidl-conversions": ["webidl-conversions@5.0.0", "", {}, "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="], - "webpack": ["webpack@5.104.1", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.17.4", "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "terser-webpack-plugin": "^5.3.16", "watchpack": "^2.4.4", "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA=="], + "webpack": ["webpack@5.105.0", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.19.0", "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "terser-webpack-plugin": "^5.3.16", "watchpack": "^2.5.1", "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw=="], "webpack-sources": ["webpack-sources@3.3.3", "", {}, "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg=="], @@ -3870,40 +3855,6 @@ "@electron/windows-sign/fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], - "@example/angular-vite-pwa/@evolu/common": ["@evolu/common@7.4.1", "", { "dependencies": { "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "@scure/bip39": "^2.0.0", "kysely": "^0.28.4", "msgpackr": "^1.11.5", "random": "^5.4.1" } }, "sha512-aTSJN9GXvoN5FXo8DRiYdbMVFvBUG6N7Ygu7n5viyauPKBwylyAazZuDcBlQg5MxVv6YrF5c6w2LRG/OR2UIHA=="], - - "@example/angular-vite-pwa/@evolu/web": ["@evolu/web@2.4.0", "", { "dependencies": { "@evolu/sqlite-wasm": "2.2.4", "idb-keyval": "^6.2.2" }, "peerDependencies": { "@evolu/common": "^7.4.0" } }, "sha512-yba/zpcsf5qu4NEup/rx8j+M/7DmF53/EZXKe8NRJefPJxrCxjzteOgUqUMkHQwYDRdH3u81KMoPlhvdBgSFuQ=="], - - "@example/react-electron/@evolu/common": ["@evolu/common@7.4.1", "", { "dependencies": { "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "@scure/bip39": "^2.0.0", "kysely": "^0.28.4", "msgpackr": "^1.11.5", "random": "^5.4.1" } }, "sha512-aTSJN9GXvoN5FXo8DRiYdbMVFvBUG6N7Ygu7n5viyauPKBwylyAazZuDcBlQg5MxVv6YrF5c6w2LRG/OR2UIHA=="], - - "@example/react-electron/@evolu/react": ["@evolu/react@10.4.0", "", { "peerDependencies": { "@evolu/common": "^7.4.0", "react": ">=19" } }, "sha512-BLXlLT+/dKSei/JrkLc9Z3fRb48vcXQmaExe0VMdxMzv2h8CyO5l4G635eQtH8F7I40VsnXLCURxNyzKF9DEQw=="], - - "@example/react-electron/@evolu/react-web": ["@evolu/react-web@2.4.0", "", { "peerDependencies": { "@evolu/common": "^7.4.0", "@evolu/web": "^2.4.0", "react": ">=19", "react-dom": ">=19" } }, "sha512-8zf/qQM+JZWykh0eGIAhE3CRFptGB0FwyQa4jp5Ce7yyOkekRMRs5WMZQA9QbRoY/OBRyOcwIP4aUk/tj49VwQ=="], - - "@example/react-expo/@evolu/common": ["@evolu/common@7.4.1", "", { "dependencies": { "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "@scure/bip39": "^2.0.0", "kysely": "^0.28.4", "msgpackr": "^1.11.5", "random": "^5.4.1" } }, "sha512-aTSJN9GXvoN5FXo8DRiYdbMVFvBUG6N7Ygu7n5viyauPKBwylyAazZuDcBlQg5MxVv6YrF5c6w2LRG/OR2UIHA=="], - - "@example/react-expo/@evolu/react": ["@evolu/react@10.4.0", "", { "peerDependencies": { "@evolu/common": "^7.4.0", "react": ">=19" } }, "sha512-BLXlLT+/dKSei/JrkLc9Z3fRb48vcXQmaExe0VMdxMzv2h8CyO5l4G635eQtH8F7I40VsnXLCURxNyzKF9DEQw=="], - - "@example/react-expo/@evolu/react-native": ["@evolu/react-native@14.3.0", "", { "peerDependencies": { "@evolu/common": "^7.4.0", "@evolu/react": "^10.4.0", "@op-engineering/op-sqlite": ">=12", "expo": ">=54", "expo-secure-store": ">=15", "expo-sqlite": ">=16", "react-native": ">=0.81", "react-native-nitro-modules": ">=0.31", "react-native-sensitive-info": ">=6", "react-native-svg": ">=15" }, "optionalPeers": ["@op-engineering/op-sqlite", "expo", "expo-secure-store", "expo-sqlite", "react-native-nitro-modules", "react-native-sensitive-info", "react-native-svg"] }, "sha512-/HfypD6F1WrJw2DNcipbDjfFPmy5ebezNNI//GOvy6wCejk/QxPUCNCPksR9akA+UIdqvE1fE9Xct65bBK1e9w=="], - - "@example/react-nextjs/@evolu/common": ["@evolu/common@7.4.1", "", { "dependencies": { "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "@scure/bip39": "^2.0.0", "kysely": "^0.28.4", "msgpackr": "^1.11.5", "random": "^5.4.1" } }, "sha512-aTSJN9GXvoN5FXo8DRiYdbMVFvBUG6N7Ygu7n5viyauPKBwylyAazZuDcBlQg5MxVv6YrF5c6w2LRG/OR2UIHA=="], - - "@example/react-nextjs/@evolu/react": ["@evolu/react@10.4.0", "", { "peerDependencies": { "@evolu/common": "^7.4.0", "react": ">=19" } }, "sha512-BLXlLT+/dKSei/JrkLc9Z3fRb48vcXQmaExe0VMdxMzv2h8CyO5l4G635eQtH8F7I40VsnXLCURxNyzKF9DEQw=="], - - "@example/react-nextjs/@evolu/react-web": ["@evolu/react-web@2.4.0", "", { "peerDependencies": { "@evolu/common": "^7.4.0", "@evolu/web": "^2.4.0", "react": ">=19", "react-dom": ">=19" } }, "sha512-8zf/qQM+JZWykh0eGIAhE3CRFptGB0FwyQa4jp5Ce7yyOkekRMRs5WMZQA9QbRoY/OBRyOcwIP4aUk/tj49VwQ=="], - - "@example/react-vite-pwa/@evolu/common": ["@evolu/common@7.4.1", "", { "dependencies": { "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "@scure/bip39": "^2.0.0", "kysely": "^0.28.4", "msgpackr": "^1.11.5", "random": "^5.4.1" } }, "sha512-aTSJN9GXvoN5FXo8DRiYdbMVFvBUG6N7Ygu7n5viyauPKBwylyAazZuDcBlQg5MxVv6YrF5c6w2LRG/OR2UIHA=="], - - "@example/react-vite-pwa/@evolu/react": ["@evolu/react@10.4.0", "", { "peerDependencies": { "@evolu/common": "^7.4.0", "react": ">=19" } }, "sha512-BLXlLT+/dKSei/JrkLc9Z3fRb48vcXQmaExe0VMdxMzv2h8CyO5l4G635eQtH8F7I40VsnXLCURxNyzKF9DEQw=="], - - "@example/react-vite-pwa/@evolu/react-web": ["@evolu/react-web@2.4.0", "", { "peerDependencies": { "@evolu/common": "^7.4.0", "@evolu/web": "^2.4.0", "react": ">=19", "react-dom": ">=19" } }, "sha512-8zf/qQM+JZWykh0eGIAhE3CRFptGB0FwyQa4jp5Ce7yyOkekRMRs5WMZQA9QbRoY/OBRyOcwIP4aUk/tj49VwQ=="], - - "@example/vue-vite-pwa/@evolu/common": ["@evolu/common@7.4.1", "", { "dependencies": { "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "@scure/bip39": "^2.0.0", "kysely": "^0.28.4", "msgpackr": "^1.11.5", "random": "^5.4.1" } }, "sha512-aTSJN9GXvoN5FXo8DRiYdbMVFvBUG6N7Ygu7n5viyauPKBwylyAazZuDcBlQg5MxVv6YrF5c6w2LRG/OR2UIHA=="], - - "@example/vue-vite-pwa/@evolu/vue": ["@evolu/vue@1.4.0", "", { "peerDependencies": { "@evolu/common": "^7.4.0", "vue": ">=3.5.24" } }, "sha512-ydT8VxDOIXqfC6n6NQxXPsDX+Jvqg/CP+2Tj8hzZgqFO6PZpIBqOX8pS6ceqVCv+9FI4pC+LGyz4X9idrdX87g=="], - - "@example/vue-vite-pwa/@evolu/web": ["@evolu/web@2.4.0", "", { "dependencies": { "@evolu/sqlite-wasm": "2.2.4", "idb-keyval": "^6.2.2" }, "peerDependencies": { "@evolu/common": "^7.4.0" } }, "sha512-yba/zpcsf5qu4NEup/rx8j+M/7DmF53/EZXKe8NRJefPJxrCxjzteOgUqUMkHQwYDRdH3u81KMoPlhvdBgSFuQ=="], - "@expo/cli/picomatch": ["picomatch@3.0.1", "", {}, "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag=="], "@expo/cli/pretty-bytes": ["pretty-bytes@5.6.0", "", {}, "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg=="], @@ -4020,7 +3971,7 @@ "app-builder-lib/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], - "app-builder-lib/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + "app-builder-lib/minimatch": ["minimatch@10.1.2", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.1" } }, "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw=="], "babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@5.2.1", "", { "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg=="], @@ -4054,8 +4005,6 @@ "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], - "compressible/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "compression/negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="], @@ -4108,7 +4057,7 @@ "finalhandler/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], - "glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + "glob/minimatch": ["minimatch@10.1.2", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.1" } }, "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw=="], "global-agent/serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="], @@ -4136,7 +4085,7 @@ "log-symbols/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], - "log-update/ansi-escapes": ["ansi-escapes@7.2.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw=="], + "log-update/ansi-escapes": ["ansi-escapes@7.3.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="], "log-update/cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], @@ -4578,7 +4527,7 @@ "workbox-build/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "workbox-build/glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + "workbox-build/glob/minimatch": ["minimatch@10.1.2", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.1" } }, "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw=="], "workbox-build/rollup/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], diff --git a/examples/angular-vite-pwa/package.json b/examples/angular-vite-pwa/package.json index 4d0716a84..5eea68365 100644 --- a/examples/angular-vite-pwa/package.json +++ b/examples/angular-vite-pwa/package.json @@ -9,15 +9,15 @@ "generate-pwa-assets": "pwa-assets-generator" }, "dependencies": { - "@angular/core": "^21.1.0", - "@angular/platform-browser": "^21.1.0", + "@angular/core": "^21.1.3", + "@angular/platform-browser": "^21.1.3", "@evolu/common": "workspace:*", "@evolu/web": "workspace:*" }, "devDependencies": { "@analogjs/vite-plugin-angular": "^2.2.2", "@angular/build": "^21.1.0", - "@angular/compiler-cli": "^21.1.0", + "@angular/compiler-cli": "^21.1.3", "@tailwindcss/vite": "^4.1.18", "@vite-pwa/assets-generator": "^1.0.2", "tailwindcss": "^4.1.18", diff --git a/examples/angular-vite-pwa/src/app/app.service.ts b/examples/angular-vite-pwa/src/app/app.service.ts index ecdf833ff..4a8320502 100644 --- a/examples/angular-vite-pwa/src/app/app.service.ts +++ b/examples/angular-vite-pwa/src/app/app.service.ts @@ -2,14 +2,14 @@ import { Injectable, inject, type OnDestroy, signal } from "@angular/core"; import { type InferRow, Mnemonic, type Query, type Row } from "@evolu/common"; import { EVOLU } from "./app.config"; import { formatTypeError } from "./error-formatter"; -import type { TodoId } from "./schema"; +import { createQuery, type TodoId } from "./schema"; @Injectable({ providedIn: "root" }) export class AppService implements OnDestroy { private readonly evolu = inject(EVOLU); private readonly unsubscribes: Array<() => void> = []; - private readonly todosQuery = this.evolu.createQuery((db) => + private readonly todosQuery = createQuery((db) => db .selectFrom("todo") .select(["id", "title", "isCompleted"]) diff --git a/examples/angular-vite-pwa/src/app/schema.ts b/examples/angular-vite-pwa/src/app/schema.ts index cbdd38bba..9199a0b0b 100644 --- a/examples/angular-vite-pwa/src/app/schema.ts +++ b/examples/angular-vite-pwa/src/app/schema.ts @@ -1,4 +1,5 @@ import { + createQueryBuilder, type EvoluSchema, id, NonEmptyString100, @@ -19,3 +20,6 @@ const TodoSchema = { export const Schema = { todo: TodoSchema, } satisfies EvoluSchema; + +// Create a query builder (once per schema). +export const createQuery = createQueryBuilder(Schema); diff --git a/examples/react-electron/components/EvoluMinimalExample.tsx b/examples/react-electron/components/EvoluMinimalExample.tsx index 231bdc1d3..c60d2cd96 100644 --- a/examples/react-electron/components/EvoluMinimalExample.tsx +++ b/examples/react-electron/components/EvoluMinimalExample.tsx @@ -74,8 +74,11 @@ export const EvoluMinimalExample: FC = () => { ); }; +// Create a query builder (once per schema). +const createQuery = Evolu.createQueryBuilder(Schema); + // Evolu uses Kysely for type-safe SQL (https://kysely.dev/). -const todosQuery = evolu.createQuery((db) => +const todosQuery = createQuery((db) => db // Type-safe SQL: try autocomplete for table and column names. .selectFrom("todo") diff --git a/examples/react-electron/package.json b/examples/react-electron/package.json index 650211b76..3c321963e 100644 --- a/examples/react-electron/package.json +++ b/examples/react-electron/package.json @@ -17,7 +17,7 @@ "react-dom": "19.2.4" }, "devDependencies": { - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "@vitejs/plugin-react": "^5.1.3", "electron": "38.2.0", diff --git a/examples/react-expo/app/index.tsx b/examples/react-expo/app/index.tsx index 2cda2fe9a..0813afd7f 100644 --- a/examples/react-expo/app/index.tsx +++ b/examples/react-expo/app/index.tsx @@ -107,8 +107,11 @@ const EvoluDemo = ({ }): React.ReactNode => { const useEvolu = createUseEvolu(evolu); + // Create a query builder (once per schema). + const createQuery = Evolu.createQueryBuilder(Schema); + // Evolu uses Kysely for type-safe SQL (https://kysely.dev/). - const todosQuery = evolu.createQuery((db) => + const todosQuery = createQuery((db) => db // Type-safe SQL: try autocomplete for table and column names. .selectFrom("todo") diff --git a/examples/react-expo/package.json b/examples/react-expo/package.json index 9ddb083ef..2065706b6 100644 --- a/examples/react-expo/package.json +++ b/examples/react-expo/package.json @@ -38,7 +38,7 @@ "react-native-quick-crypto": "^1.0.6", "react-native-safe-area-context": "^5.6.2", "react-native-screens": "^4.21.0", - "react-native-svg": "^15.15.1", + "react-native-svg": "^15.15.2", "set.prototype.difference": "^1.1.7", "set.prototype.intersection": "^1.1.8", "set.prototype.isdisjointfrom": "^1.1.5", @@ -51,7 +51,7 @@ "@babel/core": "^7.28.6", "@babel/plugin-transform-explicit-resource-management": "^7.28.6", "@babel/plugin-transform-modules-commonjs": "^7.28.6", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "typescript": "^5.9.3" } } diff --git a/examples/react-nextjs/components/EvoluMinimalExample.tsx b/examples/react-nextjs/components/EvoluMinimalExample.tsx index d72c1a21c..c640e996a 100644 --- a/examples/react-nextjs/components/EvoluMinimalExample.tsx +++ b/examples/react-nextjs/components/EvoluMinimalExample.tsx @@ -76,8 +76,11 @@ export const EvoluMinimalExample: FC = () => { ); }; +// Create a query builder (once per schema). +const createQuery = Evolu.createQueryBuilder(Schema); + // Evolu uses Kysely for type-safe SQL (https://kysely.dev/). -const todosQuery = evolu.createQuery((db) => +const todosQuery = createQuery((db) => db // Type-safe SQL: try autocomplete for table and column names. .selectFrom("todo") diff --git a/examples/react-nextjs/package.json b/examples/react-nextjs/package.json index d2e69feb4..35d147cf6 100644 --- a/examples/react-nextjs/package.json +++ b/examples/react-nextjs/package.json @@ -22,7 +22,7 @@ "@tailwindcss/forms": "^0.5.11", "@tailwindcss/postcss": "^4.1.18", "@types/node": "^24.10.9", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "postcss": "^8.5.6", "tailwindcss": "^4.1.18", diff --git a/examples/react-vite-pwa/package.json b/examples/react-vite-pwa/package.json index 0567a3d14..404d919fc 100644 --- a/examples/react-vite-pwa/package.json +++ b/examples/react-vite-pwa/package.json @@ -23,7 +23,7 @@ "devDependencies": { "@tailwindcss/forms": "^0.5.11", "@tailwindcss/vite": "^4.1.18", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "@vite-pwa/assets-generator": "^1.0.2", "@vitejs/plugin-react": "^5.1.3", diff --git a/examples/react-vite-pwa/src/components/EvoluMinimalExample.tsx b/examples/react-vite-pwa/src/components/EvoluMinimalExample.tsx index 5a83571c2..fb45633bb 100644 --- a/examples/react-vite-pwa/src/components/EvoluMinimalExample.tsx +++ b/examples/react-vite-pwa/src/components/EvoluMinimalExample.tsx @@ -86,8 +86,11 @@ export const EvoluMinimalExample: FC = () => { ); }; +// Create a query builder (once per schema). +const createQuery = Evolu.createQueryBuilder(Schema); + // Evolu uses Kysely for type-safe SQL (https://kysely.dev/). -const todosQuery = evolu.createQuery((db) => +const todosQuery = createQuery((db) => db // Type-safe SQL: try autocomplete for table and column names. .selectFrom("todo") diff --git a/examples/svelte-vite-pwa/package.json b/examples/svelte-vite-pwa/package.json index f5bf69c9e..d6e234e56 100644 --- a/examples/svelte-vite-pwa/package.json +++ b/examples/svelte-vite-pwa/package.json @@ -15,8 +15,8 @@ "@evolu/svelte": "workspace:*", "@evolu/web": "workspace:*", "@sveltejs/vite-plugin-svelte": "^6.2.4", - "@tsconfig/svelte": "^5.0.6", - "svelte": "^5.48.2", + "@tsconfig/svelte": "^5.0.7", + "svelte": "^5.49.2", "svelte-check": "^4.3.6", "tslib": "^2.8.1", "typescript": "^5.9.3", diff --git a/examples/svelte-vite-pwa/src/App.svelte b/examples/svelte-vite-pwa/src/App.svelte index 5f2b909a3..7ee58b094 100644 --- a/examples/svelte-vite-pwa/src/App.svelte +++ b/examples/svelte-vite-pwa/src/App.svelte @@ -42,8 +42,11 @@ console.error(error); }); + // Create a query builder (once per schema). + const createQuery = Evolu.createQueryBuilder(Schema); + // Evolu uses Kysely for type-safe SQL (https://kysely.dev/). - const todosQuery = evolu.createQuery((db) => + const todosQuery = createQuery((db) => db // Type-safe SQL: try autocomplete for table and column names. .selectFrom("todo") diff --git a/examples/vue-vite-pwa/src/App.vue b/examples/vue-vite-pwa/src/App.vue index 2d9ec9738..9a90404bf 100644 --- a/examples/vue-vite-pwa/src/App.vue +++ b/examples/vue-vite-pwa/src/App.vue @@ -7,6 +7,7 @@ import { sqliteTrue, createEvolu, createFormatTypeError, + createQueryBuilder, id, kysely, maxLength, @@ -60,7 +61,10 @@ const evolu = createEvolu(evoluWebDeps)(DatabaseSchema, { provideEvolu(evolu); -const todosWithCategories = evolu.createQuery((db) => +// Create a query builder (once per schema). +const createQuery = createQueryBuilder(DatabaseSchema); + +const todosWithCategories = createQuery((db) => db .selectFrom("todo") .select(["id", "title", "isCompleted", "categoryId", "priority"]) @@ -70,7 +74,7 @@ const todosWithCategories = evolu.createQuery((db) => .orderBy("createdAt"), ); -const todoCategories = evolu.createQuery((db) => +const todoCategories = createQuery((db) => db .selectFrom("todoCategory") .select(["id", "name"]) diff --git a/package.json b/package.json index fbfb73316..c7a5b0c5e 100755 --- a/package.json +++ b/package.json @@ -15,14 +15,14 @@ "build": "turbo --filter @evolu/* build", "build:web": "bun run build:docs && turbo --filter web build", "build:docs": "typedoc && bun --filter=web run fix:docs", - "test": "turbo run test", - "test:coverage": "turbo run test:coverage", - "test:watch": "turbo run test:watch", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "test:watch": "vitest", "start": "turbo start", "lint": "biome check", "lint-monorepo": "bunx sherif@latest", "format": "biome format --write .", - "verify": "bun run format && bun run build && bun run test && bun run test:coverage && bun run lint && bun run lint-monorepo", + "verify": "bun run format && bun run build && bun run test && bun run test:coverage && bun run lint && bun run lint-monorepo && bun run build:docs && INCLUDE_DOCS_TESTS=true bunx vitest run scripts/typedoc-plugin-evolu.test.mts", "clean": "turbo clean && rimraf node_modules bun.lock .turbo out", "version": "changeset version", "release": "bun run build && changeset publish", @@ -37,16 +37,19 @@ "examples:vue-vite-pwa:dev": "turbo --filter @example/vue-vite-pwa dev" }, "devDependencies": { - "@biomejs/biome": "2.3.13", + "@biomejs/biome": "2.3.14", "@changesets/cli": "^2.29.8", "@types/webpack": "^5.28.5", + "@vitest/browser": "^4.0.17", + "@vitest/browser-playwright": "^4.0.17", + "@vitest/coverage-v8": "^4.0.17", "rimraf": "^6.1.2", - "turbo": "^2.8.2", + "turbo": "^2.8.3", "typedoc": "^0.28.16", "typedoc-plugin-markdown": "^4.9.0", "typescript": "^5.9.3", "vitest": "^4.0.17", - "webpack": "^5.104.1" + "webpack": "^5.105.0" }, "engines": { "node": ">=24.0.0" diff --git a/packages/common/package.json b/packages/common/package.json index f42b3cc9d..c7d089304 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -45,11 +45,7 @@ "scripts": { "dev": "tsc", "build": "rimraf dist && tsc", - "test": "vitest run", - "test:watch": "vitest", - "test:coverage": "vitest run --coverage", "clean": "rimraf .turbo node_modules dist coverage test/tmp test/__screenshots__", - "bench": "vitest bench" }, "dependencies": { @@ -57,26 +53,12 @@ "@noble/hashes": "^2.0.1", "@scure/bip39": "^2.0.1", "disposablestack": "^1.1.7", - "kysely": "^0.28.10", + "kysely": "^0.28.11", "msgpackr": "^1.11.8", - "random": "^5.4.1" - }, - "devDependencies": { - "@bokuweb/zstd-wasm": "0.0.27", - "@evolu/tsconfig": "workspace:*", - "@types/better-sqlite3": "^7.6.13", - "@types/node": "^24.10.9", - "@types/webpack": "^5.28.5", - "@types/ws": "^8.18.1", - "@vitest/browser": "^4.0.17", - "@vitest/browser-playwright": "^4.0.17", - "@vitest/coverage-v8": "^4.0.18", - "better-sqlite3": "^12.6.2", - "fast-check": "^4.5.3", "playwright": "^1.58.1", + "random": "^5.4.1", "typescript": "^5.9.3", - "vitest": "^4.0.17", - "webpack": "^5.104.1", + "webpack": "^5.105.0", "ws": "^8.19.0" }, "publishConfig": { @@ -85,5 +67,12 @@ "engines": { "node": ">=24.0.0" }, - "sideEffects": false + "sideEffects": false, + "devDependencies": { + "@bokuweb/zstd-wasm": "^0.0.27", + "@types/better-sqlite3": "^7.6.13", + "@types/ws": "^8.18.1", + "better-sqlite3": "^12.6.2", + "fast-check": "^4.5.3" + } } diff --git a/packages/common/src/Error.ts b/packages/common/src/Error.ts index 1c96a59ab..b4399b58a 100644 --- a/packages/common/src/Error.ts +++ b/packages/common/src/Error.ts @@ -94,7 +94,7 @@ export const createUnknownError = (error: unknown): UnknownError => { * `onunhandledrejection`, `uncaughtException`, etc.). Any error reaching these * handlers is a programming error — all unsafe code should be wrapped with * {@link trySync} or {@link tryAsync}. The `onError` callback exists for - * telemetry and debugging, not error recovery. + * observability, not error recovery. * * Implementations use {@link handleGlobalError} to forward errors. */ diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index b0d456e3f..25ef4eaf9 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -31,8 +31,14 @@ export { createEvolu } from "./local-first/Evolu.js"; export * as kysely from "./local-first/Kysely.js"; export * from "./local-first/LocalAuth.js"; export * from "./local-first/Owner.js"; -export type { InferRow, Query, QueryRows, Row } from "./local-first/Query.js"; +export type { + InferRow, + Query, + QueryRows, + Row, +} from "./local-first/Query.js"; export type { EvoluSchema } from "./local-first/Schema.js"; +export { createQueryBuilder } from "./local-first/Schema.js"; export type { NetworkError, PaymentRequiredError, diff --git a/packages/common/src/local-first/Evolu.ts b/packages/common/src/local-first/Evolu.ts index f685b6394..da368ac5a 100644 --- a/packages/common/src/local-first/Evolu.ts +++ b/packages/common/src/local-first/Evolu.ts @@ -19,12 +19,7 @@ import type { DisposableDep, DisposableStackDep } from "../Resources.js"; import { createDisposableDep } from "../Resources.js"; import type { Result } from "../Result.js"; import { err, ok } from "../Result.js"; -import type { SafeSql, SqliteQuery } from "../Sqlite.js"; -import { - isSqlMutation, - SqliteBoolean, - sqliteBooleanToBoolean, -} from "../Sqlite.js"; +import { SqliteBoolean, sqliteBooleanToBoolean } from "../Sqlite.js"; import type { ReadonlyStore, Store } from "../Store.js"; import { createStore } from "../Store.js"; import type { AnyType, InferErrors, InferInput, ObjectType } from "../Type.js"; @@ -42,9 +37,8 @@ import type { Row, SubscribedQueries, } from "./Query.js"; -import { createSubscribedQueries, emptyRows, serializeQuery } from "./Query.js"; +import { createSubscribedQueries, emptyRows } from "./Query.js"; import type { - CreateQuery, EvoluSchema, IndexesConfig, Mutation, @@ -52,15 +46,10 @@ import type { MutationKind, MutationMapping, MutationOptions, - ValidateSchema, -} from "./Schema.js"; -import { - insertable, - kysely, SystemColumns, - updateable, - upsertable, + ValidateSchema, } from "./Schema.js"; +import { insertable, updateable, upsertable } from "./Schema.js"; import { DbChange } from "./Storage.js"; import type { SyncOwner } from "./Sync.js"; import type { EvoluWorkerDep } from "./Worker.js"; @@ -239,33 +228,6 @@ export interface Evolu extends Disposable { /** Get {@link EvoluError}. */ readonly getError: () => EvoluError | null; - /** - * Create type-safe SQL {@link Query}. - * - * Evolu uses Kysely - the type-safe SQL query builder for TypeScript. See - * https://kysely.dev. - * - * All this function does is compile the Kysely query and serialize it into a - * unique string. Both operations are fast and cheap. - * - * For mutations, use {@link Evolu.insert}, {@link Evolu.update}, or - * {@link Evolu.upsert}. - * - * ### Example - * - * ```ts - * const allTodos = evolu.createQuery((db) => - * db.selectFrom("todo").selectAll(), - * ); - * - * const todoById = (id: TodoId) => - * evolu.createQuery((db) => - * db.selectFrom("todo").selectAll().where("id", "=", id), - * ); - * ``` - */ - readonly createQuery: CreateQuery; - /** * Load {@link Query} and return a promise with {@link QueryRows}. * @@ -283,7 +245,8 @@ export interface Evolu extends Disposable { * ### Example * * ```ts - * const allTodos = evolu.createQuery((db) => + * const createQuery = createQueryBuilder(Schema); + * const allTodos = createQuery((db) => * db.selectFrom("todo").selectAll(), * ); * evolu.loadQuery(allTodos).then((rows) => { @@ -539,7 +502,7 @@ export interface Evolu extends Disposable { * In the future, it will be possible to import a database and export/import * history for 1:1 migrations across owners. */ - readonly exportDatabase: () => Promise>; + readonly exportDatabase: () => Promise; /** * Use a {@link SyncOwner}. Returns a {@link UnuseOwner}. @@ -570,17 +533,17 @@ export interface Evolu extends Disposable { /** Function returned by {@link Evolu.useOwner} to stop using an {@link SyncOwner}. */ export type UnuseOwner = () => void; -export type EvoluPlatformDeps = CreateMessageChannelDep & - ReloadAppDep & - EvoluWorkerDep & - Partial; - export type EvoluDeps = EvoluPlatformDeps & ConsoleDep & DisposableDep & ErrorStoreDep & RandomBytesDep; +export type EvoluPlatformDeps = CreateMessageChannelDep & + ReloadAppDep & + EvoluWorkerDep & + Partial; + export interface ErrorStoreDep { /** * Shared error store for all Evolu instances. Subscribe once to handle errors @@ -674,6 +637,7 @@ export const createEvolu = schema: ValidateSchema extends never ? S : ValidateSchema, { name, + // transports define how Evolu connects to owners; default uses the public WebSocket service. transports: _transports = [ { type: "WebSocket", url: "wss://free.evoluhq.com" }, ], @@ -691,7 +655,7 @@ export const createEvolu = const subscribedQueries = createSubscribedQueries(rowsStore); const loadingPromises = createLoadingPromises(subscribedQueries); const onCompleteCallbacks = createCallbacks(deps); - const exportCallbacks = createCallbacks>(deps); + const exportCallbacks = createCallbacks(deps); const loadQueryMicrotaskQueue: Array = []; const useOwnerMicrotaskQueue: Array<[SyncOwner, boolean, Uint8Array]> = []; @@ -942,8 +906,6 @@ export const createEvolu = subscribeError: errorStore.subscribe, getError: errorStore.get, - createQuery: createQuery as CreateQuery, - loadQuery: (query: Query): Promise> => { const { promise, isNew } = loadingPromises.get(query); @@ -1035,8 +997,7 @@ export const createEvolu = // }, exportDatabase: () => { - const { promise, resolve } = - Promise.withResolvers>(); + const { promise, resolve } = Promise.withResolvers(); const _onCompleteId = exportCallbacks.register(resolve); // dbWorker.postMessage({ type: "export", onCompleteId }); return promise; @@ -1105,27 +1066,6 @@ export const createEvolu = return evolu; }; -// TODO: Should not be exported, it is because of tests. -export const createQuery = ( - queryCallback: Parameters>[0], - options?: Parameters>[1], -): Query => { - const compiledQuery = queryCallback(kysely as never).compile(); - - if (isSqlMutation(compiledQuery.sql)) - throw new Error( - "SQL mutation (INSERT, UPDATE, DELETE, etc.) isn't allowed in the Evolu `createQuery` function. Kysely suggests it because there is no read-only Kysely yet, and removing such an API is not possible. For mutations, use Evolu Mutation API.", - ); - - return serializeQuery({ - sql: compiledQuery.sql as SafeSql, - parameters: compiledQuery.parameters as NonNullable< - SqliteQuery["parameters"] - >, - ...(options && { options }), - }); -}; - interface LoadingPromises { get: ( query: Query, diff --git a/packages/common/src/local-first/Query.ts b/packages/common/src/local-first/Query.ts index 1065d31e2..b2ad15254 100644 --- a/packages/common/src/local-first/Query.ts +++ b/packages/common/src/local-first/Query.ts @@ -35,9 +35,8 @@ import type { Simplify } from "../Types.js"; * ### Example * * ```ts - * const allTodos = evolu.createQuery((db) => - * db.selectFrom("todo").selectAll(), - * ); + * const createQuery = createQueryBuilder(Schema); + * const allTodos = createQuery((db) => db.selectFrom("todo").selectAll()); * type AllTodosRow = typeof allTodos.Row; * ``` */ @@ -49,7 +48,8 @@ export type Query = string & * ### Example * * ```ts - * const allTodos = evolu.createQuery((db) => + * const createQuery = createQueryBuilder(Schema); + * const allTodos = createQuery((db) => * db.selectFrom("todo").selectAll(), * ); * type AllTodosRow = typeof allTodos.Row; diff --git a/packages/common/src/local-first/Schema.ts b/packages/common/src/local-first/Schema.ts index 497554930..f96f483bb 100644 --- a/packages/common/src/local-first/Schema.ts +++ b/packages/common/src/local-first/Schema.ts @@ -14,6 +14,7 @@ import { } from "../Object.js"; import { ok, type Result } from "../Result.js"; import { + isSqlMutation, type SafeSql, SqliteBoolean, type SqliteDep, @@ -51,8 +52,9 @@ import type { Simplify } from "../Types.js"; import type { AppOwner } from "./Owner.js"; import { OwnerId } from "./Owner.js"; import type { Query, Row } from "./Query.js"; +import { serializeQuery } from "./Query.js"; import type { CrdtMessage, DbChange } from "./Storage.js"; -import type { TimestampBytes } from "./Timestamp.js"; +import type { Timestamp, TimestampBytes } from "./Timestamp.js"; /** * Defines the schema of an Evolu database. @@ -559,13 +561,16 @@ export const ensureDbSchema = if (!dbSchema.ok) return dbSchema; currentSchema = dbSchema.value; } + const _currentSchema = currentSchema; for (const [tableName, newColumns] of Object.entries(newSchema.tables)) { - const currentColumns = getProperty(currentSchema.tables, tableName); + const currentColumns = getProperty(_currentSchema.tables, tableName); if (!currentColumns) { queries.push(createAppTable(tableName, newColumns)); } else { - for (const newColumn of newColumns.difference(currentColumns)) { + for (const newColumn of [...newColumns].filter( + (c) => !currentColumns.has(c), + )) { queries.push(sql` alter table ${sql.identifier(tableName)} add column ${sql.identifier(newColumn)} any; @@ -575,7 +580,7 @@ export const ensureDbSchema = } // Remove current indexes that are not in the newSchema. - currentSchema.indexes + _currentSchema.indexes .filter( (currentIndex) => !newSchema.indexes.some((newIndex) => @@ -590,7 +595,7 @@ export const ensureDbSchema = newSchema.indexes .filter( (newIndex) => - !currentSchema.indexes.some((currentIndex) => + !_currentSchema.indexes.some((currentIndex) => indexesAreEqual(newIndex, currentIndex), ), ) @@ -637,6 +642,48 @@ export const kysely = new Kysely.Kysely({ const createIndex = kysely.schema.createIndex.bind(kysely.schema); +/** + * Creates a query builder from a {@link EvoluSchema}. + * + * ### Example + * + * ```ts + * const Schema = { + * todo: { + * id: id("Todo"), + * title: NonEmptyString100, + * isCompleted: nullOr(SqliteBoolean), + * }, + * }; + * + * // Create a typed query builder (once per schema) + * const createQuery = createQueryBuilder(Schema); + * + * // Use it for all queries + * const todosQuery = createQuery((db) => + * db.selectFrom("todo").select(["id", "title", "isCompleted"]), + * ); + * ``` + */ +export const createQueryBuilder = + (_schema: S): CreateQuery => + (queryCallback, options) => { + const compiledQuery = queryCallback(kysely as never).compile(); + + if (isSqlMutation(compiledQuery.sql)) + throw new Error( + "SQL mutation (INSERT, UPDATE, DELETE, etc.) isn't allowed in createQuery. Kysely suggests it because there is no read-only Kysely yet, and removing such an API is not possible. For mutations, use Evolu Mutation API.", + ); + + return serializeQuery({ + sql: compiledQuery.sql as SafeSql, + parameters: compiledQuery.parameters as NonNullable< + SqliteQuery["parameters"] + >, + ...(options && { options }), + }); + }; + // export const maxMutationSize = 655360; // /** diff --git a/packages/common/test/local-first/Protocol.test.ts b/packages/common/test/local-first/Protocol.test.ts index 302a85259..fe07e8ce5 100644 --- a/packages/common/test/local-first/Protocol.test.ts +++ b/packages/common/test/local-first/Protocol.test.ts @@ -300,9 +300,7 @@ test("encodeSqliteValue/decodeSqliteValue property tests", () => { // Test all SqliteValue types fc.constant(null), fc.string(), // Regular strings - fc - .double() - .filter((n) => !Number.isNaN(n)), // Numbers (exclude NaN) + fc.double().filter((n) => !Number.isNaN(n)), // Numbers (exclude NaN) fc.uint8Array(), // Binary data // Special number cases @@ -332,9 +330,7 @@ test("encodeSqliteValue/decodeSqliteValue property tests", () => { fc .stringMatching(/^[A-Za-z0-9_-]{4,}$/) .filter((s) => s.length % 4 === 0), // Valid Base64Url - fc - .string() - .filter((s) => /[^A-Za-z0-9_-]/.test(s)), // Invalid Base64Url chars + fc.string().filter((s) => /[^A-Za-z0-9_-]/.test(s)), // Invalid Base64Url chars // JSON optimization cases fc @@ -347,16 +343,14 @@ test("encodeSqliteValue/decodeSqliteValue property tests", () => { .array(fc.oneof(fc.string(), fc.integer(), fc.boolean())) .map((arr) => JSON.stringify(arr)), fc.constantFrom('{"a":1}', "[]", "null", "true", "false", '"string"'), // Simple JSON - fc - .string() - .filter((s) => { - try { - JSON.parse(s); - return false; - } catch { - return true; - } - }), // Non-JSON strings + fc.string().filter((s) => { + try { + JSON.parse(s); + return false; + } catch { + return true; + } + }), // Non-JSON strings // Date ISO strings - both valid and invalid fc @@ -1305,27 +1299,30 @@ describe("E2E sync", () => { }, ); - it("client and relay each have a random half of the data - many steps", { timeout: 15000 }, async () => { - await using run = testCreateRunner(); - const [clientStorage, relayStorage] = await createStorages(); + it( + "client and relay each have a random half of the data - many steps", + { timeout: 15000 }, + async () => { + await using run = testCreateRunner(); + const [clientStorage, relayStorage] = await createStorages(); - const shuffledMessages = deps.randomLib.shuffle(messages); - const middle = Math.floor(shuffledMessages.length / 2); - const firstHalf = shuffledMessages.slice(0, middle); - const secondHalf = shuffledMessages.slice(middle); + const shuffledMessages = deps.randomLib.shuffle(messages); + const middle = Math.floor(shuffledMessages.length / 2); + const firstHalf = shuffledMessages.slice(0, middle); + const secondHalf = shuffledMessages.slice(middle); - assertNonEmptyArray(firstHalf); - assertNonEmptyArray(secondHalf); + assertNonEmptyArray(firstHalf); + assertNonEmptyArray(secondHalf); - await run(clientStorage.writeMessages(testOwnerIdBytes, firstHalf)); - await run(relayStorage.writeMessages(testOwnerIdBytes, secondHalf)); + await run(clientStorage.writeMessages(testOwnerIdBytes, firstHalf)); + await run(relayStorage.writeMessages(testOwnerIdBytes, secondHalf)); - const syncSteps = await reconcile( - clientStorage, - relayStorage, - ProtocolMessageRangesMaxSize.orThrow(3000), - ); - expect(syncSteps).toMatchInlineSnapshot(` + const syncSteps = await reconcile( + clientStorage, + relayStorage, + ProtocolMessageRangesMaxSize.orThrow(3000), + ); + expect(syncSteps).toMatchInlineSnapshot(` { "syncSizes": [ 392, @@ -1370,7 +1367,8 @@ describe("E2E sync", () => { "syncSteps": 38, } `); - }); + }, + ); it("starts sync from createProtocolMessageFromCrdtMessages", async () => { const owner = testOwner; diff --git a/packages/common/tsconfig.json b/packages/common/tsconfig.json index 1ae925a2a..5705c4dcd 100644 --- a/packages/common/tsconfig.json +++ b/packages/common/tsconfig.json @@ -6,6 +6,6 @@ "allowJs": true, "resolveJsonModule": true }, - "include": ["src", "test", "vitest.config.ts"], + "include": ["src", "test", "vitest.*.config.ts"], "exclude": ["dist", "node_modules", "test/tmp"] } diff --git a/packages/common/vitest.browser.config.ts b/packages/common/vitest.browser.config.ts new file mode 100644 index 000000000..eab8a080e --- /dev/null +++ b/packages/common/vitest.browser.config.ts @@ -0,0 +1,52 @@ +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { playwright } from "@vitest/browser-playwright"; +import { defineProject } from "vitest/config"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +// Coverage with v8 only works with a single browser instance +const isCoverage = process.argv.includes("--coverage"); + +export default defineProject({ + // Transpile `using`/`await using` for WebKit which doesn't support it yet + esbuild: { supported: { using: false } }, + test: { + snapshotSerializers: [ + resolve(__dirname, "./test/local-first/_uint8ArraySerializer.ts"), + ], + include: ["test/*.test.ts"], + exclude: [ + "test/Sqlite.test.ts", // needs SQLite + "test/TreeShaking.test.ts", // needs esbuild + "test/Identicon.test.ts", // needs canvas + "test/Redacted.test.ts", // uses node:util + ], + name: "browser", + setupFiles: ["./test/_browserSetup.ts"], + browser: { + enabled: true, + provider: playwright(), + headless: true, + // Sequential execution is faster than parallel for some reason. + fileParallelism: false, + commands: { + startWsServer: async () => { + const { createServer } = await import("./test/_globalSetup.js"); + return createServer(); + }, + stopWsServer: async (_, port: number) => { + const { closeServer } = await import("./test/_globalSetup.js"); + await closeServer(port); + }, + }, + instances: isCoverage + ? [{ browser: "chromium" }] + : [ + { browser: "chromium" }, + { browser: "firefox" }, + { browser: "webkit" }, + ], + }, + }, +}); diff --git a/packages/common/vitest.config.ts b/packages/common/vitest.config.ts deleted file mode 100644 index 2b5ed271a..000000000 --- a/packages/common/vitest.config.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { playwright } from "@vitest/browser-playwright"; -import { defineConfig } from "vitest/config"; - -// Coverage with v8 only works with a single browser instance -const isCoverage = process.argv.includes("--coverage"); - -export default defineConfig({ - test: { - exclude: [ - "**/node_modules/**", - "**/dist/**", - "**/coverage/**", - "**/__snapshots__/**", - ], - coverage: { - provider: "v8", - include: ["src/**/*.ts"], - exclude: ["src/**/index.ts"], - reporter: ["text", "html"], - thresholds: { - statements: 70, - branches: 65, - functions: 70, - lines: 70, - }, - }, - projects: [ - { - test: { - snapshotSerializers: ["./test/local-first/_uint8ArraySerializer.ts"], - include: ["test/**/*.test.ts"], - name: "unit", - environment: "node", - setupFiles: ["./test/_nodeSetup.ts"], - }, - }, - { - // Transpile `using`/`await using` for WebKit which doesn't support it yet - esbuild: { supported: { using: false } }, - test: { - snapshotSerializers: ["./test/local-first/_uint8ArraySerializer.ts"], - include: ["test/*.test.ts"], - exclude: [ - "test/Sqlite.test.ts", // needs SQLite - "test/TreeShaking.test.ts", // needs esbuild - "test/Identicon.test.ts", // needs canvas - "test/Redacted.test.ts", // uses node:util - ], - name: "browser", - setupFiles: ["./test/_browserSetup.ts"], - browser: { - enabled: true, - provider: playwright(), - headless: true, - // Sequential execution is faster than parallel for some reason. - fileParallelism: false, - commands: { - startWsServer: async () => { - const { createServer } = await import("./test/_globalSetup.js"); - return createServer(); - }, - stopWsServer: async (_, port: number) => { - const { closeServer } = await import("./test/_globalSetup.js"); - await closeServer(port); - }, - }, - instances: isCoverage - ? [{ browser: "chromium" }] - : [ - { browser: "chromium" }, - { browser: "firefox" }, - { browser: "webkit" }, - ], - }, - }, - }, - ], - }, -}); diff --git a/packages/common/vitest.unit.config.ts b/packages/common/vitest.unit.config.ts new file mode 100644 index 000000000..73d9fdb8f --- /dev/null +++ b/packages/common/vitest.unit.config.ts @@ -0,0 +1,16 @@ +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { defineProject } from "vitest/config"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +export default defineProject({ + test: { + snapshotSerializers: [ + resolve(__dirname, "./test/local-first/_uint8ArraySerializer.ts"), + ], + include: ["test/**/*.test.ts"], + name: "unit", + environment: "node", + }, +}); diff --git a/packages/nodejs/package.json b/packages/nodejs/package.json index bcbdd3964..c2e0a513c 100644 --- a/packages/nodejs/package.json +++ b/packages/nodejs/package.json @@ -22,9 +22,6 @@ "scripts": { "dev": "tsc", "build": "rimraf dist && tsc", - "test": "vitest run", - "test:watch": "vitest", - "test:coverage": "vitest run --coverage", "clean": "rimraf .turbo node_modules dist coverage" }, "dependencies": { @@ -37,9 +34,7 @@ "@types/better-sqlite3": "^7.6.13", "@types/node": "^24.10.9", "@types/ws": "^8.18.1", - "@vitest/coverage-v8": "^4.0.18", - "typescript": "^5.9.3", - "vitest": "^4.0.17" + "typescript": "^5.9.3" }, "peerDependencies": { "@evolu/common": "^7.4.1" diff --git a/packages/nodejs/vitest.config.ts b/packages/nodejs/vitest.config.ts index 8c5405af1..4edb62f48 100644 --- a/packages/nodejs/vitest.config.ts +++ b/packages/nodejs/vitest.config.ts @@ -1,15 +1,9 @@ -import { defineConfig } from "vitest/config"; +import { defineProject } from "vitest/config"; -export default defineConfig({ +export default defineProject({ test: { setupFiles: ["./test/setup.ts"], exclude: ["**/node_modules/**", "**/dist/**"], include: ["test/**/*.test.ts"], - coverage: { - provider: "v8", - include: ["src/**/*.ts"], - exclude: ["src/**/index.ts"], - reporter: ["text", "html"], - }, }, }); diff --git a/packages/react-native/package.json b/packages/react-native/package.json index ecc3fe996..38e893c8f 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -67,9 +67,6 @@ "scripts": { "dev": "tsc", "build": "rimraf dist && tsc", - "test": "vitest run", - "test:watch": "vitest", - "test:coverage": "vitest run --coverage", "clean": "rimraf .turbo node_modules dist coverage" }, "devDependencies": { @@ -77,8 +74,7 @@ "@evolu/react": "workspace:*", "@evolu/tsconfig": "workspace:*", "@op-engineering/op-sqlite": "^15.2.2", - "@types/react": "~19.2.10", - "@vitest/coverage-v8": "^4.0.18", + "@types/react": "~19.2.11", "expo": "^54.0.31", "expo-secure-store": "~15.0.8", "expo-sqlite": "~16.0.10", @@ -86,9 +82,8 @@ "react-native": "^0.81.5", "react-native-nitro-modules": "^0.31.10", "react-native-sensitive-info": "6.0.0-rc.11", - "react-native-svg": "^15.15.1", - "typescript": "^5.9.3", - "vitest": "^4.0.17" + "react-native-svg": "^15.15.2", + "typescript": "^5.9.3" }, "peerDependencies": { "@evolu/common": "^7.4.1", diff --git a/packages/react-native/vitest.config.ts b/packages/react-native/vitest.config.ts index 4705738a3..324ed134b 100644 --- a/packages/react-native/vitest.config.ts +++ b/packages/react-native/vitest.config.ts @@ -1,14 +1,8 @@ -import { defineConfig } from "vitest/config"; +import { defineProject } from "vitest/config"; -export default defineConfig({ +export default defineProject({ test: { exclude: ["**/node_modules/**", "**/dist/**"], include: ["test/**/*.test.ts"], - coverage: { - provider: "v8", - include: ["src/**/*.ts"], - exclude: ["src/**/index.ts"], - reporter: ["text", "html"], - }, }, }); diff --git a/packages/react-web/package.json b/packages/react-web/package.json index 96c38393c..26f9975d0 100644 --- a/packages/react-web/package.json +++ b/packages/react-web/package.json @@ -38,13 +38,12 @@ "@evolu/common": "workspace:*", "@evolu/tsconfig": "workspace:*", "@evolu/web": "workspace:*", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "react": "19.2.4", "react-dom": "19.2.4", "typescript": "^5.9.3", - "user-agent-data-types": "^0.4.2", - "vitest": "^4.0.17" + "user-agent-data-types": "^0.4.2" }, "peerDependencies": { "@evolu/common": "^7.4.1", diff --git a/packages/react/package.json b/packages/react/package.json index 6a3e5c429..907559688 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -37,11 +37,10 @@ "devDependencies": { "@evolu/common": "workspace:*", "@evolu/tsconfig": "workspace:*", - "@types/react": "~19.2.10", + "@types/react": "~19.2.11", "@types/react-dom": "~19.2.3", "react": "19.2.4", - "typescript": "^5.9.3", - "vitest": "^4.0.17" + "typescript": "^5.9.3" }, "peerDependencies": { "@evolu/common": "^7.4.1", diff --git a/packages/svelte/package.json b/packages/svelte/package.json index b877df60c..922e49c18 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -41,15 +41,15 @@ "@evolu/tsconfig": "workspace:*", "@evolu/web": "workspace:*", "@sveltejs/package": "^2.5.7", - "@tsconfig/svelte": "^5.0.6", - "svelte": "^5.48.2", + "@tsconfig/svelte": "^5.0.7", + "svelte": "^5.49.2", "svelte-check": "^4.3.6", "typescript": "^5.9.3" }, "peerDependencies": { "@evolu/common": "^7.4.1", "@evolu/web": "^2.4.0", - "svelte": ">=5" + "svelte": ">=5.49.2" }, "publishConfig": { "access": "public" diff --git a/packages/vue/package.json b/packages/vue/package.json index 8cfb8d682..4a0084fc9 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -37,8 +37,7 @@ "devDependencies": { "@evolu/common": "workspace:*", "@evolu/tsconfig": "workspace:*", - "typescript": "^5.9.3", - "vitest": "^4.0.17" + "typescript": "^5.9.3" }, "peerDependencies": { "@evolu/common": "^7.4.1", diff --git a/packages/web/package.json b/packages/web/package.json index c545841ea..ae320baa6 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -30,9 +30,6 @@ "scripts": { "dev": "tsc", "build": "rimraf dist && tsc", - "test": "vitest run", - "test:watch": "vitest", - "test:coverage": "vitest run --coverage", "clean": "rimraf .turbo node_modules dist coverage" }, "dependencies": { @@ -44,12 +41,8 @@ "@evolu/tsconfig": "workspace:*", "@types/sharedworker": "^0.0.211", "@types/web-locks-api": "^0.0.5", - "@vitest/browser": "^4.0.17", - "@vitest/browser-playwright": "^4.0.17", - "@vitest/coverage-v8": "^4.0.18", "typescript": "^5.9.3", - "user-agent-data-types": "^0.4.2", - "vitest": "^4.0.17" + "user-agent-data-types": "^0.4.2" }, "peerDependencies": { "@evolu/common": "^7.4.1" diff --git a/packages/web/vitest.config.ts b/packages/web/vitest.config.ts index cad7e8c03..2b5bba32f 100644 --- a/packages/web/vitest.config.ts +++ b/packages/web/vitest.config.ts @@ -1,21 +1,15 @@ import { playwright } from "@vitest/browser-playwright"; -import { defineConfig } from "vitest/config"; +import { defineProject } from "vitest/config"; // Coverage with v8 only works with a single browser instance const isCoverage = process.argv.includes("--coverage"); -export default defineConfig({ +export default defineProject({ // Transpile `using`/`await using` for WebKit which doesn't support it yet esbuild: { supported: { using: false } }, test: { exclude: ["**/node_modules/**", "**/dist/**"], include: ["test/**/*.test.ts"], - coverage: { - provider: "v8", - include: ["src/**/*.ts"], - exclude: ["src/**/index.ts"], - reporter: ["text", "html"], - }, browser: { enabled: true, provider: playwright(), diff --git a/scripts/typedoc-plugin-evolu.test.mts b/scripts/typedoc-plugin-evolu.test.mts index 18a4993c4..f97a8c3ea 100644 --- a/scripts/typedoc-plugin-evolu.test.mts +++ b/scripts/typedoc-plugin-evolu.test.mts @@ -7,6 +7,10 @@ import { describe, expect, it } from "vitest"; * * These tests verify the generated documentation. Run `bun run build:docs` before * running these tests. + * + * NOTE: This test is excluded from the regular test run in vitest.config.mts + * because it requires generated docs. It runs explicitly in the verify script + * after `bun run build:docs`. */ const docsPath = join( diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..2b02f3ca7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./packages/tsconfig/universal-esm.json", + "compilerOptions": { + "noEmit": true + }, + "include": ["vitest.config.mts"] +} diff --git a/turbo.json b/turbo.json index a135d611a..6bf2d0cc0 100644 --- a/turbo.json +++ b/turbo.json @@ -26,14 +26,6 @@ "cache": false, "persistent": true }, - "test": {}, - "test:coverage": { - "outputs": ["coverage/**"] - }, - "test:watch": { - "cache": false, - "persistent": true - }, "clean": { "cache": false }, diff --git a/vitest.config.mts b/vitest.config.mts new file mode 100644 index 000000000..6d95d6f33 --- /dev/null +++ b/vitest.config.mts @@ -0,0 +1,30 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + projects: [ + "packages/common/vitest.unit.config.ts", + "packages/common/vitest.browser.config.ts", + "packages/web", + "packages/nodejs", + "packages/react-native", + { + test: { + name: "scripts", + include: ["scripts/**/*.test.mts"], + // Exclude typedoc test because it requires generated docs. + // It runs explicitly after build:docs in the verify script. + exclude: process.env.INCLUDE_DOCS_TESTS + ? [] + : ["scripts/typedoc-plugin-evolu.test.mts"], + }, + }, + ], + coverage: { + provider: "v8", + include: ["packages/*/src/**/*.ts"], + exclude: ["packages/*/src/**/index.ts"], + reporter: ["text", "html"], + }, + }, +});