From 7f567aa22eb6cef86be832ed7d6edb728161dd08 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 14:51:03 +0000 Subject: [PATCH 1/2] ci: Version Packages --- .changeset/pre.json | 74 ++++++++++++ examples/angular/todos/package.json | 4 +- examples/electron/offline-first/package.json | 10 +- .../offline-transactions/package.json | 10 +- .../react-native/shopping-list/package.json | 10 +- .../react/action-enforcement/package.json | 4 +- examples/react/next-ssr-e2e/package.json | 4 +- .../react/offline-transactions/package.json | 10 +- .../react/paced-mutations-demo/package.json | 4 +- examples/react/projects/package.json | 4 +- examples/react/start-ssr-e2e/package.json | 4 +- examples/react/todo/package.json | 8 +- examples/solid/todo/package.json | 8 +- packages/angular-db/CHANGELOG.md | 60 +++++++++ packages/angular-db/package.json | 2 +- .../CHANGELOG.md | 27 +++++ .../package.json | 2 +- .../CHANGELOG.md | 21 ++++ .../package.json | 2 +- .../CHANGELOG.md | 21 ++++ .../package.json | 2 +- packages/convex-db-collection/CHANGELOG.md | 29 +++++ packages/convex-db-collection/package.json | 2 +- packages/db-ivm/CHANGELOG.md | 26 ++++ packages/db-ivm/package.json | 2 +- .../db-sqlite-persistence-core/CHANGELOG.md | 89 ++++++++++++++ .../db-sqlite-persistence-core/package.json | 2 +- packages/db/CHANGELOG.md | 114 ++++++++++++++++++ packages/db/package.json | 2 +- packages/electric-db-collection/CHANGELOG.md | 61 ++++++++++ packages/electric-db-collection/package.json | 2 +- .../CHANGELOG.md | 27 +++++ .../package.json | 2 +- .../expo-db-sqlite-persistence/CHANGELOG.md | 21 ++++ .../expo-db-sqlite-persistence/package.json | 2 +- .../node-db-sqlite-persistence/CHANGELOG.md | 21 ++++ .../node-db-sqlite-persistence/package.json | 2 +- packages/offline-transactions/CHANGELOG.md | 20 +++ packages/offline-transactions/package.json | 2 +- packages/powersync-db-collection/CHANGELOG.md | 51 ++++++++ packages/powersync-db-collection/package.json | 2 +- packages/preact-db/CHANGELOG.md | 63 ++++++++++ packages/preact-db/package.json | 2 +- packages/query-db-collection/CHANGELOG.md | 50 ++++++++ packages/query-db-collection/package.json | 2 +- packages/react-db/CHANGELOG.md | 78 ++++++++++++ packages/react-db/package.json | 2 +- .../CHANGELOG.md | 21 ++++ .../package.json | 2 +- packages/react-router-with-db/CHANGELOG.md | 33 +++++ packages/react-router-with-db/package.json | 4 +- packages/rxdb-db-collection/CHANGELOG.md | 51 ++++++++ packages/rxdb-db-collection/package.json | 2 +- packages/solid-db/CHANGELOG.md | 62 ++++++++++ packages/solid-db/package.json | 2 +- packages/svelte-db/CHANGELOG.md | 76 ++++++++++++ packages/svelte-db/package.json | 2 +- .../tauri-db-sqlite-persistence/CHANGELOG.md | 21 ++++ .../tauri-db-sqlite-persistence/package.json | 2 +- packages/trailbase-db-collection/CHANGELOG.md | 51 ++++++++ packages/trailbase-db-collection/package.json | 2 +- packages/vue-db/CHANGELOG.md | 62 ++++++++++ packages/vue-db/package.json | 2 +- pnpm-lock.yaml | 80 ++++++------ 64 files changed, 1336 insertions(+), 106 deletions(-) create mode 100644 .changeset/pre.json create mode 100644 packages/convex-db-collection/CHANGELOG.md create mode 100644 packages/preact-db/CHANGELOG.md diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000000..36af03dffd --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,74 @@ +{ + "mode": "pre", + "tag": "rc", + "initialVersions": { + "todos": "0.0.27", + "offline-first-electron": "1.0.7", + "offline-transactions-react-native": "1.0.14", + "shopping-list-react-native": "1.0.14", + "@tanstack/db-example-react-action-enforcement": "0.0.1", + "@tanstack/db-example-react-next-ssr-e2e": "0.0.9", + "@tanstack/db-example-paced-mutations-demo": "0.0.19", + "@tanstack/db-example-react-start-ssr-e2e": "0.0.3", + "@tanstack/db-example-react-todo": "0.1.31", + "@tanstack/db-example-solid-todo": "0.0.39", + "@tanstack/angular-db": "1.0.0-rc.0", + "@tanstack/browser-db-sqlite-persistence": "1.0.0-rc.0", + "@tanstack/capacitor-db-sqlite-persistence": "1.0.0-rc.0", + "@tanstack/capacitor-db-sqlite-persistence-e2e-app": "0.0.49", + "@tanstack/cloudflare-durable-objects-db-sqlite-persistence": "1.0.0-rc.0", + "@tanstack/convex-db-collection": "1.0.0-rc.0", + "@tanstack/db": "1.0.0-rc.0", + "db-collections": "0.0.0", + "@tanstack/db-ivm": "1.0.0-rc.0", + "@tanstack/db-sqlite-persistence-core": "1.0.0-rc.0", + "@tanstack/electric-db-collection": "1.0.0-rc.0", + "@tanstack/electron-db-sqlite-persistence": "1.0.0-rc.0", + "@tanstack/expo-db-sqlite-persistence": "1.0.0-rc.0", + "@tanstack/expo-db-sqlite-persistence-e2e-app": "0.0.49", + "@tanstack/node-db-sqlite-persistence": "1.0.0-rc.0", + "@tanstack/offline-transactions": "1.1.4", + "@tanstack/powersync-db-collection": "1.0.0-rc.0", + "@tanstack/preact-db": "1.0.0-rc.0", + "@tanstack/query-db-collection": "1.4.8", + "@tanstack/react-db": "1.0.0-rc.0", + "@tanstack/react-native-db-sqlite-persistence": "1.0.0-rc.0", + "@tanstack/react-router-with-db": "1.0.0-rc.0", + "@tanstack/rxdb-db-collection": "1.0.0-rc.0", + "@tanstack/solid-db": "1.0.0-rc.0", + "@tanstack/svelte-db": "1.0.0-rc.0", + "@tanstack/tauri-db-sqlite-persistence": "1.0.0-rc.0", + "@tanstack/tauri-db-sqlite-persistence-e2e-app": "0.0.49", + "@tanstack/trailbase-db-collection": "1.0.0-rc.0", + "@tanstack/vue-db": "1.0.0-rc.0" + }, + "changesets": [ + "bright-cups-infer", + "browser-sqlite-separate-wasm", + "convex-collection", + "db-query-identity-laws", + "defer-term-behind-queued-reads", + "electric-cleanup-stream-listeners", + "first-rc", + "gc-waits-for-persisting-transactions", + "keep-live-query-through-failed-replay", + "on-demand-network-first", + "opt-in-operators", + "ordered-loader-superseded-failure", + "persisted-reload-keeps-status", + "preact-db-adapter", + "react-db-strip-dev-warnings", + "react-db-unhashable-throws", + "reserved-commit-defers-every-hydration", + "resume-independent-subscription-demand", + "skip-complete-collection-setup", + "solid-js-peer-cap", + "sortedmap-merge-restore", + "source-health-channel", + "sqlite-connection-closed-error", + "svelte-db-query-identity", + "sync-metadata-session-reads", + "tidy-opfs-close", + "vue-db-window-binding" + ] +} diff --git a/examples/angular/todos/package.json b/examples/angular/todos/package.json index 5ea357659f..958d77d717 100644 --- a/examples/angular/todos/package.json +++ b/examples/angular/todos/package.json @@ -27,8 +27,8 @@ "@angular/forms": "^20.3.34", "@angular/platform-browser": "^20.3.34", "@angular/router": "^20.3.34", - "@tanstack/angular-db": "^0.2.12", - "@tanstack/db": "^0.15.2", + "@tanstack/angular-db": "^1.0.0-rc.1", + "@tanstack/db": "^1.0.0-rc.1", "rxjs": "^7.8.2", "tslib": "^2.8.1", "zone.js": "~0.15.0" diff --git a/examples/electron/offline-first/package.json b/examples/electron/offline-first/package.json index 4d297aa367..1c139ffaaf 100644 --- a/examples/electron/offline-first/package.json +++ b/examples/electron/offline-first/package.json @@ -13,11 +13,11 @@ "postinstall": "prebuild-install --runtime electron --target 41.0.0 --arch arm64 || echo 'prebuild-install failed, try: npx @electron/rebuild'" }, "dependencies": { - "@tanstack/electron-db-sqlite-persistence": "^0.2.13", - "@tanstack/node-db-sqlite-persistence": "^0.2.37", - "@tanstack/offline-transactions": "^1.1.4", - "@tanstack/query-db-collection": "^1.4.8", - "@tanstack/react-db": "^0.5.12", + "@tanstack/electron-db-sqlite-persistence": "^1.0.0-rc.1", + "@tanstack/node-db-sqlite-persistence": "^1.0.0-rc.1", + "@tanstack/offline-transactions": "^1.2.0", + "@tanstack/query-db-collection": "^1.5.0", + "@tanstack/react-db": "^1.0.0-rc.1", "@tanstack/react-query": "^5.90.20", "better-sqlite3": "^12.6.2", "react": "^19.2.4", diff --git a/examples/react-native/offline-transactions/package.json b/examples/react-native/offline-transactions/package.json index 66ff5ac625..c5eee7c253 100644 --- a/examples/react-native/offline-transactions/package.json +++ b/examples/react-native/offline-transactions/package.json @@ -15,11 +15,11 @@ "@op-engineering/op-sqlite": "^15.2.5", "@react-native-async-storage/async-storage": "2.1.2", "@react-native-community/netinfo": "11.4.1", - "@tanstack/db": "^0.15.2", - "@tanstack/offline-transactions": "^1.1.4", - "@tanstack/query-db-collection": "^1.4.8", - "@tanstack/react-db": "^0.5.12", - "@tanstack/react-native-db-sqlite-persistence": "^0.2.37", + "@tanstack/db": "^1.0.0-rc.1", + "@tanstack/offline-transactions": "^1.2.0", + "@tanstack/query-db-collection": "^1.5.0", + "@tanstack/react-db": "^1.0.0-rc.1", + "@tanstack/react-native-db-sqlite-persistence": "^1.0.0-rc.1", "@tanstack/react-query": "^5.90.20", "expo": "~53.0.26", "expo-constants": "~17.1.0", diff --git a/examples/react-native/shopping-list/package.json b/examples/react-native/shopping-list/package.json index 3db2e0d6ff..a638f9179b 100644 --- a/examples/react-native/shopping-list/package.json +++ b/examples/react-native/shopping-list/package.json @@ -18,11 +18,11 @@ "@op-engineering/op-sqlite": "^15.2.5", "@react-native-async-storage/async-storage": "2.1.2", "@react-native-community/netinfo": "11.4.1", - "@tanstack/db": "^0.15.2", - "@tanstack/electric-db-collection": "^0.6.3", - "@tanstack/offline-transactions": "^1.1.4", - "@tanstack/react-db": "^0.5.12", - "@tanstack/react-native-db-sqlite-persistence": "^0.2.37", + "@tanstack/db": "^1.0.0-rc.1", + "@tanstack/electric-db-collection": "^1.0.0-rc.1", + "@tanstack/offline-transactions": "^1.2.0", + "@tanstack/react-db": "^1.0.0-rc.1", + "@tanstack/react-native-db-sqlite-persistence": "^1.0.0-rc.1", "@tanstack/react-query": "^5.90.20", "expo": "~53.0.26", "expo-constants": "~17.1.0", diff --git a/examples/react/action-enforcement/package.json b/examples/react/action-enforcement/package.json index 52403a30ee..835ee0484d 100644 --- a/examples/react/action-enforcement/package.json +++ b/examples/react/action-enforcement/package.json @@ -12,8 +12,8 @@ }, "dependencies": { "@tanstack/query-core": "^5.90.20", - "@tanstack/query-db-collection": "^1.4.8", - "@tanstack/react-db": "^0.5.12", + "@tanstack/query-db-collection": "^1.5.0", + "@tanstack/react-db": "^1.0.0-rc.1", "react": "^19.2.4", "react-dom": "^19.2.4" }, diff --git a/examples/react/next-ssr-e2e/package.json b/examples/react/next-ssr-e2e/package.json index 21333d2492..5e89c72eb8 100644 --- a/examples/react/next-ssr-e2e/package.json +++ b/examples/react/next-ssr-e2e/package.json @@ -9,8 +9,8 @@ "test:e2e": "pnpm --filter @tanstack/db build && pnpm --filter @tanstack/react-db build && playwright test" }, "dependencies": { - "@tanstack/db": "^0.15.2", - "@tanstack/react-db": "^0.5.12", + "@tanstack/db": "^1.0.0-rc.1", + "@tanstack/react-db": "^1.0.0-rc.1", "next": "^16.3.1", "react": "^19.2.4", "react-dom": "^19.2.4" diff --git a/examples/react/offline-transactions/package.json b/examples/react/offline-transactions/package.json index c6a878047c..5caca40c73 100644 --- a/examples/react/offline-transactions/package.json +++ b/examples/react/offline-transactions/package.json @@ -8,11 +8,11 @@ "build": "vite build && tsc --noEmit" }, "dependencies": { - "@tanstack/browser-db-sqlite-persistence": "^0.2.37", - "@tanstack/db": "^0.15.2", - "@tanstack/offline-transactions": "^1.1.4", - "@tanstack/query-db-collection": "^1.4.8", - "@tanstack/react-db": "^0.5.12", + "@tanstack/browser-db-sqlite-persistence": "^1.0.0-rc.1", + "@tanstack/db": "^1.0.0-rc.1", + "@tanstack/offline-transactions": "^1.2.0", + "@tanstack/query-db-collection": "^1.5.0", + "@tanstack/react-db": "^1.0.0-rc.1", "@tanstack/react-query": "^5.90.20", "@tanstack/react-router": "^1.170.41", "@tanstack/react-router-devtools": "^1.159.5", diff --git a/examples/react/paced-mutations-demo/package.json b/examples/react/paced-mutations-demo/package.json index a1b3ae0fc2..c58d294fa9 100644 --- a/examples/react/paced-mutations-demo/package.json +++ b/examples/react/paced-mutations-demo/package.json @@ -9,8 +9,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/db": "^0.15.2", - "@tanstack/react-db": "^0.5.12", + "@tanstack/db": "^1.0.0-rc.1", + "@tanstack/react-db": "^1.0.0-rc.1", "mitt": "^3.0.1", "react": "^19.2.4", "react-dom": "^19.2.4" diff --git a/examples/react/projects/package.json b/examples/react/projects/package.json index 1a38ff93fe..fa253e1160 100644 --- a/examples/react/projects/package.json +++ b/examples/react/projects/package.json @@ -17,8 +17,8 @@ "dependencies": { "@tailwindcss/vite": "^4.1.18", "@tanstack/query-core": "^5.90.20", - "@tanstack/query-db-collection": "^1.4.8", - "@tanstack/react-db": "^0.5.12", + "@tanstack/query-db-collection": "^1.5.0", + "@tanstack/react-db": "^1.0.0-rc.1", "@tanstack/react-router": "^1.170.41", "@tanstack/react-router-devtools": "^1.159.5", "@tanstack/react-router-with-query": "^1.130.17", diff --git a/examples/react/start-ssr-e2e/package.json b/examples/react/start-ssr-e2e/package.json index 0e514c957e..7192bd70ff 100644 --- a/examples/react/start-ssr-e2e/package.json +++ b/examples/react/start-ssr-e2e/package.json @@ -10,9 +10,9 @@ "test:e2e:hosted": "playwright test" }, "dependencies": { - "@tanstack/react-db": "^0.5.12", + "@tanstack/react-db": "^1.0.0-rc.1", "@tanstack/react-router": "^1.170.41", - "@tanstack/react-router-with-db": "^0.1.0", + "@tanstack/react-router-with-db": "^1.0.0-rc.1", "@tanstack/react-start": "^1.168.60", "react": "^19.2.4", "react-dom": "^19.2.4", diff --git a/examples/react/todo/package.json b/examples/react/todo/package.json index 3d1df4122c..996acfef89 100644 --- a/examples/react/todo/package.json +++ b/examples/react/todo/package.json @@ -3,13 +3,13 @@ "private": true, "version": "0.1.31", "dependencies": { - "@tanstack/electric-db-collection": "^0.6.3", + "@tanstack/electric-db-collection": "^1.0.0-rc.1", "@tanstack/query-core": "^5.90.20", - "@tanstack/query-db-collection": "^1.4.8", - "@tanstack/react-db": "^0.5.12", + "@tanstack/query-db-collection": "^1.5.0", + "@tanstack/react-db": "^1.0.0-rc.1", "@tanstack/react-router": "^1.170.41", "@tanstack/react-start": "^1.168.60", - "@tanstack/trailbase-db-collection": "^0.1.123", + "@tanstack/trailbase-db-collection": "^1.0.0-rc.1", "cors": "^2.8.6", "drizzle-orm": "^0.45.1", "drizzle-zod": "^0.8.3", diff --git a/examples/solid/todo/package.json b/examples/solid/todo/package.json index 5479af674f..7a25df0368 100644 --- a/examples/solid/todo/package.json +++ b/examples/solid/todo/package.json @@ -3,13 +3,13 @@ "private": true, "version": "0.0.39", "dependencies": { - "@tanstack/electric-db-collection": "^0.6.3", + "@tanstack/electric-db-collection": "^1.0.0-rc.1", "@tanstack/query-core": "^5.90.20", - "@tanstack/query-db-collection": "^1.4.8", - "@tanstack/solid-db": "^0.3.12", + "@tanstack/query-db-collection": "^1.5.0", + "@tanstack/solid-db": "^1.0.0-rc.1", "@tanstack/solid-router": "^1.170.38", "@tanstack/solid-start": "^1.168.57", - "@tanstack/trailbase-db-collection": "^0.1.123", + "@tanstack/trailbase-db-collection": "^1.0.0-rc.1", "cors": "^2.8.6", "drizzle-orm": "^0.45.1", "drizzle-zod": "^0.8.3", diff --git a/packages/angular-db/CHANGELOG.md b/packages/angular-db/CHANGELOG.md index 5ed1327d4f..9b13ce8eab 100644 --- a/packages/angular-db/CHANGELOG.md +++ b/packages/angular-db/CHANGELOG.md @@ -1,5 +1,65 @@ # @tanstack/angular-db +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Breaking: grouping, includes, and pooling are now opt-in. An app bundles an operator's code only when it imports the value for that operator. Joins do not change. A typical app is about 8 kB smaller after gzip. This app has a query collection, a filtered live query, and React `useLiveQuery`. ([#2232](https://github.com/TanStack/db/pull/2232)) + + - An include needs `include()`, `toArray()`, or `materialize()`. Change `issues: q.from(...)` in `select()` to `issues: include(q.from(...))`. A subquery in `select()` without one of these throws `IncludeOperatorRequiredError`. + - Aggregates such as `count()` need no change. A `groupBy` with no aggregate takes `groupKeys()`: `.groupBy(groupKeys(({ todo }) => todo.status))`. Without it, the query throws `GroupingOperatorRequiredError`. + - Hooks do not pool live queries by default. To share one partition among many equality-filtered queries, pass `pool: pooledLiveQueries` in the hook's query config: `useLiveQuery({ query, pool: pooledLiveQueries })`. Results do not change. Angular's `{ params, query }` form takes `pool` the same way. Any other `pool` value, such as the old boolean, throws `InvalidPoolOptionError`, also for a disabled query. For adapter authors: the `pool` option of `resolveLiveQueryValue` is now `pooledLiveQueries` or `false`, not a boolean. An adapter that reads `pool` from its own options checks it with `configPool` first. + - Code that builds query IR by hand must supply the operator code. `IR.Aggregate` takes `groupingCompiler` as its third argument. `IR.IncludesSubquery` takes `includesRuntime` as its fifth argument, before `parentFilters`. Import both from `@tanstack/db`. IR without them throws `GroupingOperatorRequiredError` or `IncludeOperatorRequiredError` when it compiles, unless another aggregate or `groupKeys()` in the query supplies the grouping compiler. Queries that the query builder builds need no change. + - Operator code is part of query identity. A hook that re-renders a grouped query without `groupKeys()` now throws `GroupingOperatorRequiredError`. Before, React and Preact kept the grouped query. + - Vue: when a changed query fails to compile, `useLiveQuery` no longer shows the rows of the previous query. + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 + ## 0.2.12 ### Patch Changes diff --git a/packages/angular-db/package.json b/packages/angular-db/package.json index 8616ca2c9e..60a8c3aedb 100644 --- a/packages/angular-db/package.json +++ b/packages/angular-db/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/angular-db", - "version": "0.2.12", + "version": "1.0.0-rc.1", "description": "Angular integration for @tanstack/db", "author": "Ethan McDaniel", "license": "MIT", diff --git a/packages/browser-db-sqlite-persistence/CHANGELOG.md b/packages/browser-db-sqlite-persistence/CHANGELOG.md index 03ff8b9bca..12a8601cee 100644 --- a/packages/browser-db-sqlite-persistence/CHANGELOG.md +++ b/packages/browser-db-sqlite-persistence/CHANGELOG.md @@ -1,5 +1,32 @@ # @tanstack/browser-db-sqlite-persistence +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Patch Changes + +- Ship wa-sqlite WebAssembly as a separate asset that the browser loads automatically, instead of inlining it in the OPFS worker. In Vite development, the package finds its assets without configuration; production builds drop that lookup. An install that Vite cannot resolve by package name, or a worker from another installed version of the package, now reports `PersistenceUnavailableError`, and excluding the package from pre-bundling fixes it. ([#2103](https://github.com/TanStack/db/pull/2103)) + +- Add `SQLiteConnectionClosedError`. A browser OPFS connection now rejects requests made after close starts with this error instead of `InvalidPersistedCollectionConfigError`. ([#2213](https://github.com/TanStack/db/pull/2213)) + +- Reject pending OPFS requests when closing the SQLite connection, including when the worker reports a close error. Close now stops accepting requests when it starts, and concurrent `close()` calls share one outcome. The OPFS worker handles one request at a time, so close waits for earlier queries instead of failing while one waits for the OPFS access handle. ([#2213](https://github.com/TanStack/db/pull/2213)) + +- Updated dependencies [[`45c3329`](https://github.com/TanStack/db/commit/45c33292b2c4f09a63f856a829c1e15ca2b470aa), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`6bf0e86`](https://github.com/TanStack/db/commit/6bf0e86dbc12e903ef28bb6711968ad06b5d5036), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`b052e91`](https://github.com/TanStack/db/commit/b052e91c79201ee376771f99503566e736e3d0dd), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db-sqlite-persistence-core@1.0.0-rc.1 + ## 0.2.37 ### Patch Changes diff --git a/packages/browser-db-sqlite-persistence/package.json b/packages/browser-db-sqlite-persistence/package.json index 3aaff33bf2..d21e92167a 100644 --- a/packages/browser-db-sqlite-persistence/package.json +++ b/packages/browser-db-sqlite-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/browser-db-sqlite-persistence", - "version": "0.2.37", + "version": "1.0.0-rc.1", "description": "Browser wa-sqlite persisted collection adapter for TanStack DB", "author": "TanStack Team", "license": "MIT", diff --git a/packages/capacitor-db-sqlite-persistence/CHANGELOG.md b/packages/capacitor-db-sqlite-persistence/CHANGELOG.md index 92c0ec9de3..c27fedd29a 100644 --- a/packages/capacitor-db-sqlite-persistence/CHANGELOG.md +++ b/packages/capacitor-db-sqlite-persistence/CHANGELOG.md @@ -1,5 +1,26 @@ # @tanstack/capacitor-db-sqlite-persistence +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Patch Changes + +- Updated dependencies [[`45c3329`](https://github.com/TanStack/db/commit/45c33292b2c4f09a63f856a829c1e15ca2b470aa), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`6bf0e86`](https://github.com/TanStack/db/commit/6bf0e86dbc12e903ef28bb6711968ad06b5d5036), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`b052e91`](https://github.com/TanStack/db/commit/b052e91c79201ee376771f99503566e736e3d0dd), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db-sqlite-persistence-core@1.0.0-rc.1 + ## 0.2.37 ### Patch Changes diff --git a/packages/capacitor-db-sqlite-persistence/package.json b/packages/capacitor-db-sqlite-persistence/package.json index cf1567aefb..40977b3fbf 100644 --- a/packages/capacitor-db-sqlite-persistence/package.json +++ b/packages/capacitor-db-sqlite-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/capacitor-db-sqlite-persistence", - "version": "0.2.37", + "version": "1.0.0-rc.1", "description": "Capacitor SQLite persisted collection adapter for TanStack DB", "author": "TanStack Team", "license": "MIT", diff --git a/packages/cloudflare-durable-objects-db-sqlite-persistence/CHANGELOG.md b/packages/cloudflare-durable-objects-db-sqlite-persistence/CHANGELOG.md index b41cc10004..ed7465c9c5 100644 --- a/packages/cloudflare-durable-objects-db-sqlite-persistence/CHANGELOG.md +++ b/packages/cloudflare-durable-objects-db-sqlite-persistence/CHANGELOG.md @@ -1,5 +1,26 @@ # @tanstack/cloudflare-durable-objects-db-sqlite-persistence +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Patch Changes + +- Updated dependencies [[`45c3329`](https://github.com/TanStack/db/commit/45c33292b2c4f09a63f856a829c1e15ca2b470aa), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`6bf0e86`](https://github.com/TanStack/db/commit/6bf0e86dbc12e903ef28bb6711968ad06b5d5036), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`b052e91`](https://github.com/TanStack/db/commit/b052e91c79201ee376771f99503566e736e3d0dd), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db-sqlite-persistence-core@1.0.0-rc.1 + ## 0.2.37 ### Patch Changes diff --git a/packages/cloudflare-durable-objects-db-sqlite-persistence/package.json b/packages/cloudflare-durable-objects-db-sqlite-persistence/package.json index 8d3f6a0b00..f6104a6b11 100644 --- a/packages/cloudflare-durable-objects-db-sqlite-persistence/package.json +++ b/packages/cloudflare-durable-objects-db-sqlite-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/cloudflare-durable-objects-db-sqlite-persistence", - "version": "0.2.37", + "version": "1.0.0-rc.1", "description": "Cloudflare Durable Object SQLite persisted collection adapter for TanStack DB", "author": "TanStack Team", "license": "MIT", diff --git a/packages/convex-db-collection/CHANGELOG.md b/packages/convex-db-collection/CHANGELOG.md new file mode 100644 index 0000000000..54341360ce --- /dev/null +++ b/packages/convex-db-collection/CHANGELOG.md @@ -0,0 +1,29 @@ +# @tanstack/convex-db-collection + +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Add a Convex collection adapter with typed query subscriptions, full-row sync, automatic reactive pagination with on-demand windows for a fixed ordered query, durable offline mutation replay, optimistic mutation handlers, and support for both Convex JavaScript and React clients. ([#2230](https://github.com/TanStack/db/pull/2230)) + + Add opt-in mutation codecs to the durable outbox while preserving the default wire format and retaining unreadable codec records for recovery. + +### Patch Changes + +- Updated dependencies [[`db476b8`](https://github.com/TanStack/db/commit/db476b8ed9755e0c0b10b833d187354b4c63585c), [`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/offline-transactions@1.2.0 + - @tanstack/db@1.0.0-rc.1 diff --git a/packages/convex-db-collection/package.json b/packages/convex-db-collection/package.json index 4a3c1bbbb8..81bf3a7894 100644 --- a/packages/convex-db-collection/package.json +++ b/packages/convex-db-collection/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/convex-db-collection", - "version": "0.1.0", + "version": "1.0.0-rc.1", "description": "Convex collection for TanStack DB", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/db-ivm/CHANGELOG.md b/packages/db-ivm/CHANGELOG.md index 0397d463ea..b1a3400678 100644 --- a/packages/db-ivm/CHANGELOG.md +++ b/packages/db-ivm/CHANGELOG.md @@ -1,5 +1,31 @@ # @tanstack/db-ivm +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Patch Changes + +- Breaking: Collection keys now always match the declared key type, a string or a number. ([#2266](https://github.com/TanStack/db/pull/2266)) + + - A grouped live query that groups by one field now gives a `null`, `undefined`, boolean, or bigint group value a string key. Before, the key was the raw value, so `$key` was `null` for the `null` group. Read a group's key from its `$key`. String and number group values keep their keys. + - `sync.write` throws `UndefinedKeyError` or `InvalidKeyError` when `getKey` returns a key that is not a string or a number. Optimistic mutations already threw these errors. For a bigint key, the development message now shows the key instead of failing with a `TypeError`. + - `@tanstack/db` no longer exports `SortedMap`, and `SortedMap` no longer has `forEach`. `SortedMap` is the internal ordered map of Collection state. + - When one publication applies 512 or more sync operations, the Collection now merges the changed keys into the existing order. Before, it sorted all rows again. With 50,000 rows, a `compare` option, and 600 operations in each sync transaction, the load takes 181 ms instead of 1,589 ms. + - Keyed `MultiSet.consolidate` groups entries in nested maps. It no longer encodes each value as a string. + ## 0.2.0 ### Minor Changes diff --git a/packages/db-ivm/package.json b/packages/db-ivm/package.json index 2d4a83edcb..c834b2d9ba 100644 --- a/packages/db-ivm/package.json +++ b/packages/db-ivm/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/db-ivm", - "version": "0.2.0", + "version": "1.0.0-rc.1", "description": "Incremental View Maintenance for TanStack DB based on Differential Dataflow", "author": "Sam Willis", "license": "MIT", diff --git a/packages/db-sqlite-persistence-core/CHANGELOG.md b/packages/db-sqlite-persistence-core/CHANGELOG.md index c03fed43aa..ad13025080 100644 --- a/packages/db-sqlite-persistence-core/CHANGELOG.md +++ b/packages/db-sqlite-persistence-core/CHANGELOG.md @@ -1,5 +1,94 @@ # @tanstack/db-sqlite-persistence-core +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Reloaded persisted collections now read their rows before they write a leader election term. A collection still takes its leader lock when it subscribes, but it reserves its durable term only after the database work already queued on the shared scheduler has settled, or as soon as something needs a leader during that election: a local write, a follower request, a sync commit during startup, or `ensureLeadership`. A need that an earlier leader already served does not let a later takeover skip the wait. A tab that takes over treats the departed leader's route as gone, so a sync commit queued behind one of its reads goes to the new leader and settles without waiting out an RPC timeout. The Electron renderer applies the same rule to its own hydrations. The renderer now has a hydration scope, so its startup runs as one hydration, as a Browser tab's does, and a restart keeps its metadata and row reads in one scope, so a term cannot run between them. ([#2219](https://github.com/TanStack/db/pull/2219)) + + `ensureLeadership` now resolves when this node becomes leader, keeps its place in the Web Locks queue instead of replacing its lock request, and rejects if the coordinator is disposed. + + Migration for custom persistence adapters: `runInRegularScope` is now a `RegularScope`, which must also provide `afterQueuedWork()`. It resolves once every operation queued or running on the adapter's scheduler at the call has settled. An adapter without a scheduler can return a promise that settles with its running hydrations. A coordinator now rejects an adapter whose `runInRegularScope` lacks `afterQueuedWork` with `InvalidPersistenceAdapterError`. + +- `initialRender: { strategy: 'network-first' }` now works for on-demand persisted Collections, including Electric's `progressive` mode. Previously the configuration threw `InvalidPersistedCollectionConfigError`. ([#2263](https://github.com/TanStack/db/pull/2263)) + + A subset load that settles online records persisted demand coverage for its exact demand. In a later session, a load of the same demand settles on its rows from SQLite once `networkTimeoutMs` (default 3 seconds) has passed, or at once if the network load fails. The network load keeps running, and its rows publish when they arrive. If it fails after that, the query stays ready. A demand that never settled online still waits for the network. Coverage proves that the rows were complete when they were loaded, not that they are still current. A source truncate, a snapshot transaction, scoped recovery, or a cache-generation rotation clears it. A load that a reset made obsolete, a load that was released before it settled, and a load during the rest of a scoped-recovery sync run record none. Coverage also ends when SQLite holds fewer rows for the demand than when it settled, for example after a source delete or Query DB retention expiry. A `refetch: true` load always waits for the network. An ordered window with a `limit` stays covered only while SQLite holds the same rows for it. + + A query that joins eager and on-demand sources becomes ready when every eager source is ready, which network-first allows from its restored rows after the deadline, and every demand the query reaches on an on-demand source has settled. A network failure alone does not settle an on-demand demand that is not covered. + + This applies only with the default single-process coordinator. With a multi-tab coordinator, such as `BrowserCollectionCoordinator`, on-demand loads still wait for the network. + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Fix type inference for schema-free collection options wrapped with persistedCollectionOptions and passed to createCollection. ([#2259](https://github.com/TanStack/db/pull/2259)) + + Reject caller utilities that use the reserved local persistence names acceptMutations, getLeadershipState, or forceReloadSubset, instead of silently replacing them. + +- Keep a persisted Collection's status when another tab's commit reloads its rows. Before, a reload from durable rows could mark a tab `ready` while its own source was still loading, or move a tab whose initial sync failed from `error` to `ready`. Now only the Collection's own source changes its status. ([#2265](https://github.com/TanStack/db/pull/2265)) + +- Keep a sync transaction that reserved its commit turn from failing when a persisted hydration starts while it is open. Before, only a subset load admitted during the reservation waited for the commit. A subset load admitted earlier, a reload or reset from a peer tab's notice, sequence-gap recovery, or a hydration that a shared scheduler held past its turn advanced the hydration cycle, and the commit then rejected with `a persisted sync transaction cannot cross a hydration cycle`. Electric reserves every stream transaction, so a deploy that made several tabs refetch at once could put their Collections into `error`. Each of these hydrations now waits outside the apply mutex until the reserved transaction commits, then starts. While it waits, readers keep the rows from before it. The `reserveCommitTurn` contract now covers every persisted hydration. ([#2265](https://github.com/TanStack/db/pull/2265)) + + A peer reset now applies in arrival order with peer commit notices, so a commit from before the reset can no longer publish a row that the reset removed. + + Electric now abandons its open transaction when its stream stops for good, so hydrations that wait for that transaction can run. + + An abandoned reservation now releases the subset loads that waited for it, as a commit does, so they run. Before, a load admitted while the turn was reserved rejected with `SyncTransactionAbortedError` when the source abandoned the transaction. + +- Reloads no longer repeat setup that is already complete. A reopened persisted collection checks its tables, indexes, triggers, and bookkeeping rows in the same query that reads its registration, and runs its nine setup statements only when something is missing. Each adapter checks database-wide setup with one query and runs it only when a table, index, or migrated column is missing, instead of about 19 statements on every load. The write-only global `schema_version` row, which adapters with different schema versions overwrote on every load, is no longer created or written. ([#2219](https://github.com/TanStack/db/pull/2219)) + + A tab no longer rereads all of a collection's rows after its own write. It used to record the write's stream position before that write's commit notice arrived, so the notice looked like a gap and triggered `pullSince` and a full row scan. + +- Add `SQLiteConnectionClosedError`. A browser OPFS connection now rejects requests made after close starts with this error instead of `InvalidPersistedCollectionConfigError`. ([#2213](https://github.com/TanStack/db/pull/2213)) + +- Fix sync metadata reads that missed committed sync writes while an optimistic transaction held them. A sync source now reads its own writes in commit order: `metadata.row.get`, `metadata.collection.get`, and `list()` include committed transactions that have not applied yet, then the open transactions. A transaction begun inside an open one is independent, and a hold no longer changes commit order. A source insert over a different source row is a duplicate even when a seed or a hold is present. ([#2262](https://github.com/TanStack/db/pull/2262)) + + Persisted collections treat cached rows as seeds, so a later `DbClient` seed can replace them, also after another tab's notice makes the collection reload from storage. A reload from another tab's notice keeps a seed accepted during a pending transaction, keeps row metadata of rows that do not exist, and keeps a seed's row metadata unless the notice names it. An update over a `DbClient` seed now stores the whole row the collection shows, so a reload or restart keeps the seed's fields. With `rowUpdateMode: 'full'`, an update now replaces its stored row, so a reload or restart no longer brings back fields the update dropped. A reload deletes rows that storage lacks also while a pending transaction holds them. After a notice that requires a full reload, a later notice that names its rows keeps a seed's row metadata again. A schema reset from another tab clears every row and its metadata; in on-demand mode it keeps the `DbClient` seeds the collection holds and still replays demand. Rows that storage holds after a reset keep their metadata, and an equal re-insert of one keeps it too. A commit whose signal aborts before the persisted wrapper applies it no longer takes a `DbClient` seed's place. An insert in the persisted wrapper replaces the row it lands on and writes an `insert` mutation to storage. An equal re-insert keeps the row's metadata without writing it, and the wrapper no longer slows down quadratically with the size of a transaction. + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 + ## 0.4.12 ### Patch Changes diff --git a/packages/db-sqlite-persistence-core/package.json b/packages/db-sqlite-persistence-core/package.json index c4628e7862..604e001544 100644 --- a/packages/db-sqlite-persistence-core/package.json +++ b/packages/db-sqlite-persistence-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/db-sqlite-persistence-core", - "version": "0.4.12", + "version": "1.0.0-rc.1", "description": "SQLite persisted collection core for TanStack DB", "author": "TanStack Team", "license": "MIT", diff --git a/packages/db/CHANGELOG.md b/packages/db/CHANGELOG.md index cbf122ab29..eb6a237739 100644 --- a/packages/db/CHANGELOG.md +++ b/packages/db/CHANGELOG.md @@ -1,5 +1,119 @@ # @tanstack/db +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Collect the helpers the framework adapters share into one adapter layer, exported from `@tanstack/db` and marked unstable for external use. It adds `identifyLiveQuery`, which checks a prepared query's identity and source Collection IDs for a hook that compares query identity, and `bindLiveQueryWindow`, the window binding every `useLiveInfiniteQuery` now uses. The window helpers that binding replaces are no longer exported. ([#2235](https://github.com/TanStack/db/pull/2235)) + + Add `SourceCollectionIdReuseError`, which a mounted hook that compares query identity throws when a different source Collection appears under a Collection ID it already read. + + Add `rejectLiveQueryInput` and `releaseDeferredOnReclaim` for framework hooks. The first releases the sync starts a rejected query deferred and rethrows the rejection. The second releases a render's deferred sync starts when garbage collection reclaims the live query it built, so a render that never commits, because a sibling threw or it suspended, does not keep its sources deferred. Each released source follows its own start policy, so `startSyncImmediate()` or another hook can still start it. + +- Breaking: grouping, includes, and pooling are now opt-in. An app bundles an operator's code only when it imports the value for that operator. Joins do not change. A typical app is about 8 kB smaller after gzip. This app has a query collection, a filtered live query, and React `useLiveQuery`. ([#2232](https://github.com/TanStack/db/pull/2232)) + + - An include needs `include()`, `toArray()`, or `materialize()`. Change `issues: q.from(...)` in `select()` to `issues: include(q.from(...))`. A subquery in `select()` without one of these throws `IncludeOperatorRequiredError`. + - Aggregates such as `count()` need no change. A `groupBy` with no aggregate takes `groupKeys()`: `.groupBy(groupKeys(({ todo }) => todo.status))`. Without it, the query throws `GroupingOperatorRequiredError`. + - Hooks do not pool live queries by default. To share one partition among many equality-filtered queries, pass `pool: pooledLiveQueries` in the hook's query config: `useLiveQuery({ query, pool: pooledLiveQueries })`. Results do not change. Angular's `{ params, query }` form takes `pool` the same way. Any other `pool` value, such as the old boolean, throws `InvalidPoolOptionError`, also for a disabled query. For adapter authors: the `pool` option of `resolveLiveQueryValue` is now `pooledLiveQueries` or `false`, not a boolean. An adapter that reads `pool` from its own options checks it with `configPool` first. + - Code that builds query IR by hand must supply the operator code. `IR.Aggregate` takes `groupingCompiler` as its third argument. `IR.IncludesSubquery` takes `includesRuntime` as its fifth argument, before `parentFilters`. Import both from `@tanstack/db`. IR without them throws `GroupingOperatorRequiredError` or `IncludeOperatorRequiredError` when it compiles, unless another aggregate or `groupKeys()` in the query supplies the grouping compiler. Queries that the query builder builds need no change. + - Operator code is part of query identity. A hook that re-renders a grouped query without `groupKeys()` now throws `GroupingOperatorRequiredError`. Before, React and Preact kept the grouped query. + - Vue: when a changed query fails to compile, `useLiveQuery` no longer shows the rows of the previous query. + +- Breaking: Collection keys now always match the declared key type, a string or a number. ([#2266](https://github.com/TanStack/db/pull/2266)) + + - A grouped live query that groups by one field now gives a `null`, `undefined`, boolean, or bigint group value a string key. Before, the key was the raw value, so `$key` was `null` for the `null` group. Read a group's key from its `$key`. String and number group values keep their keys. + - `sync.write` throws `UndefinedKeyError` or `InvalidKeyError` when `getKey` returns a key that is not a string or a number. Optimistic mutations already threw these errors. For a bigint key, the development message now shows the key instead of failing with a `TypeError`. + - `@tanstack/db` no longer exports `SortedMap`, and `SortedMap` no longer has `forEach`. `SortedMap` is the internal ordered map of Collection state. + - When one publication applies 512 or more sync operations, the Collection now merges the changed keys into the existing order. Before, it sorted all rows again. With 50,000 rows, a `compare` option, and 600 operations in each sync transaction, the load takes 181 ms instead of 1,589 ms. + - Keyed `MultiSet.consolidate` groups entries in nested maps. It no longer encodes each value as a string. + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Garbage collection no longer cleans up a collection while a transaction that touches it is persisting. Cleaning it up dropped the transaction's optimistic rows while its mutation handler still ran, and rejected waits such as Electric's `awaitTxId`, so a write could fail after the screen that made it unmounted. The `gcTime` delay now starts again when the last such transaction completes or fails, cancels obsolete queued idle cleanup, and preserves the remaining startup grace. Rolling back a manual transaction that stayed pending preserves the existing deadline. Explicit `cleanup()` still starts immediately; a transaction that settles afterward no longer restores another transaction's cleared optimistic rows. ([#2258](https://github.com/TanStack/db/pull/2258)) + +- A query that joins and includes the same source has two subscriptions to it. Their truncate replays now share one barrier, so neither publishes while the other still loads. When a lazy demand of either fails while a failed replay of the source holds the query's results, the query keeps its last complete result until a later replay of that source succeeds. Before, retiring the other replay's failed demand could publish the window without that demand's rows. ([#2231](https://github.com/TanStack/db/pull/2231)) + + Some sources refetch and then report that their pages shifted. An ordered window over such a source no longer skips a row tied with the refetched first page's new end. When the report shows that the page's end moved, the window repairs its first page. It no longer trusts a row that an older tie request installed. + + A window move made while a truncate replay holds a live query's results now applies after that replay, even when a newer truncate discards it. Before, the move could reject, and an older move's window stayed. A reload of the query or of a source still ends the move. + + An ordered, limited query over a source without an order index can read too few rows to fill its window. A join that drops rows can cause this. It no longer reads the whole source then. It reads a prefix twice as long instead. It grows again while that adds rows, so every request stays bounded. + +- Keep ordered live queries accurate and loading when source work overlaps. A window with `orderBy` and `limit` no longer stops loading, keeps old rows, or holds acquisitions in these cases: a failed or superseded request, a truncate replay, a source change during a repair, or an on-demand joined source. Recovery after a failure uses one full-source read, and a window move whose load succeeded now resolves. ([#2194](https://github.com/TanStack/db/pull/2194)) + + When an adapter's `unloadSubset` throws, TanStack DB now reports the error as an uncaught error and continues as if the release succeeded. The error is no longer a subset failure. It does not set `lastError` or `lastSubsetError`, fail a truncate replay, reject `setWindow()`, or dispose an Effect. `unsubscribe()`, `releaseSnapshot()`, and Effect `dispose()` no longer throw or reject with it. + + The newest `setWindow()` call now wins. A pending source recovery that defers two calls no longer lets the older one set the window. A superseded call that succeeds now resolves only after the newest call settles, so awaiting it shows the window that won. + +- Keep a sync transaction that reserved its commit turn from failing when a persisted hydration starts while it is open. Before, only a subset load admitted during the reservation waited for the commit. A subset load admitted earlier, a reload or reset from a peer tab's notice, sequence-gap recovery, or a hydration that a shared scheduler held past its turn advanced the hydration cycle, and the commit then rejected with `a persisted sync transaction cannot cross a hydration cycle`. Electric reserves every stream transaction, so a deploy that made several tabs refetch at once could put their Collections into `error`. Each of these hydrations now waits outside the apply mutex until the reserved transaction commits, then starts. While it waits, readers keep the rows from before it. The `reserveCommitTurn` contract now covers every persisted hydration. ([#2265](https://github.com/TanStack/db/pull/2265)) + + A peer reset now applies in arrival order with peer commit notices, so a commit from before the reset can no longer publish a row that the reset removed. + + Electric now abandons its open transaction when its stream stops for good, so hydrations that wait for that transaction can run. + + An abandoned reservation now releases the subset loads that waited for it, as a commit does, so they run. Before, a load admitted while the turn was reserved rejected with `SyncTransactionAbortedError` when the source abandoned the transaction. + +- Start the required Collection sync run when an ordinary subscriber follows an abandoned suspended render. Deferred acquisition still starts no idle source sync run or acquisition attempt. ([#2229](https://github.com/TanStack/db/pull/2229)) + + Ordinary subscription admission and deferred acquisition resumption throw during cleanup, including automatic GC. Effects created then return disposed handles. Failed setup releases partial ownership, and throwing callbacks cannot prevent healthy observers receiving cleanup status. Subscribers surviving cleanup retain demand for an explicit restart. + + SSR captures each reader's rows and Collection status. Hydration preserves that view through browser preloads, runtime errors, sibling commits, and delayed streamed records. Missing records reject when transport ends. Known pending results survive normal record-stream close. A new stream after client cleanup starts independently of prior failures. + + Empty loading SSR needs no preload. Rendering rows or readiness requires matching query preparation or explicit source Collection preparation. Streaming Suspense prepares its result. Unsupported preparation throws with guidance. Prepared non-streaming Suspense remains supported. The DbClient query hash includes an infinite query's initial limit and offset. + + Apps without `DbClient` exclude its SSR implementation. Its API stays unchanged. + + Svelte roots initialized with `hydrate()` must set `hydrating` on `DbProvider`. Nested providers inherit it. Each provider clears initial hydration after mount so new children read live rows. + +- Fix sync metadata reads that missed committed sync writes while an optimistic transaction held them. A sync source now reads its own writes in commit order: `metadata.row.get`, `metadata.collection.get`, and `list()` include committed transactions that have not applied yet, then the open transactions. A transaction begun inside an open one is independent, and a hold no longer changes commit order. A source insert over a different source row is a duplicate even when a seed or a hold is present. ([#2262](https://github.com/TanStack/db/pull/2262)) + + Persisted collections treat cached rows as seeds, so a later `DbClient` seed can replace them, also after another tab's notice makes the collection reload from storage. A reload from another tab's notice keeps a seed accepted during a pending transaction, keeps row metadata of rows that do not exist, and keeps a seed's row metadata unless the notice names it. An update over a `DbClient` seed now stores the whole row the collection shows, so a reload or restart keeps the seed's fields. With `rowUpdateMode: 'full'`, an update now replaces its stored row, so a reload or restart no longer brings back fields the update dropped. A reload deletes rows that storage lacks also while a pending transaction holds them. After a notice that requires a full reload, a later notice that names its rows keeps a seed's row metadata again. A schema reset from another tab clears every row and its metadata; in on-demand mode it keeps the `DbClient` seeds the collection holds and still replays demand. Rows that storage holds after a reset keep their metadata, and an equal re-insert of one keeps it too. A commit whose signal aborts before the persisted wrapper applies it no longer takes a `DbClient` seed's place. An insert in the persisted wrapper replaces the row it lands on and writes an `insert` mutation to storage. An equal re-insert keeps the row's metadata without writing it, and the wrapper no longer slows down quadratically with the size of a transaction. + +- Updated dependencies [[`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb)]: + - @tanstack/db-ivm@1.0.0-rc.1 + ## 0.15.2 ### Patch Changes diff --git a/packages/db/package.json b/packages/db/package.json index 816995a325..05e430c107 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/db", - "version": "0.15.2", + "version": "1.0.0-rc.1", "description": "A reactive client store for building super fast apps on sync", "author": "Kyle Mathews", "license": "MIT", diff --git a/packages/electric-db-collection/CHANGELOG.md b/packages/electric-db-collection/CHANGELOG.md index 5255462e45..34218d94ba 100644 --- a/packages/electric-db-collection/CHANGELOG.md +++ b/packages/electric-db-collection/CHANGELOG.md @@ -1,5 +1,66 @@ # @tanstack/electric-db-collection +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Release the shape stream's visibility listener when a sync run is cleaned up. The Electric client registers a `visibilitychange` listener for each `ShapeStream` (an `AppState` subscription on React Native, from `@electric-sql/client` 1.5.23) and removes it only in `unsubscribeAll()`, so aborting the stream left the listener behind, and the listener kept the stream reachable. An app that cleans up and recreates collections, or whose on-demand cache rotates its provider session, gained one retained stream each time. ([#2257](https://github.com/TanStack/db/pull/2257)) + +- Keep a sync transaction that reserved its commit turn from failing when a persisted hydration starts while it is open. Before, only a subset load admitted during the reservation waited for the commit. A subset load admitted earlier, a reload or reset from a peer tab's notice, sequence-gap recovery, or a hydration that a shared scheduler held past its turn advanced the hydration cycle, and the commit then rejected with `a persisted sync transaction cannot cross a hydration cycle`. Electric reserves every stream transaction, so a deploy that made several tabs refetch at once could put their Collections into `error`. Each of these hydrations now waits outside the apply mutex until the reserved transaction commits, then starts. While it waits, readers keep the rows from before it. The `reserveCommitTurn` contract now covers every persisted hydration. ([#2265](https://github.com/TanStack/db/pull/2265)) + + A peer reset now applies in arrival order with peer commit notices, so a commit from before the reset can no longer publish a row that the reset removed. + + Electric now abandons its open transaction when its stream stops for good, so hydrations that wait for that transaction can run. + + An abandoned reservation now releases the subset loads that waited for it, as a commit does, so they run. Before, a load admitted while the turn was reserved rejected with `SyncTransactionAbortedError` when the source abandoned the transaction. + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 + ## 0.6.3 ### Patch Changes diff --git a/packages/electric-db-collection/package.json b/packages/electric-db-collection/package.json index f7fc2059e3..053273817e 100644 --- a/packages/electric-db-collection/package.json +++ b/packages/electric-db-collection/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/electric-db-collection", - "version": "0.6.3", + "version": "1.0.0-rc.1", "description": "ElectricSQL collection for TanStack DB", "author": "Kyle Mathews", "license": "MIT", diff --git a/packages/electron-db-sqlite-persistence/CHANGELOG.md b/packages/electron-db-sqlite-persistence/CHANGELOG.md index 9464c08b7d..7ea5ef93d3 100644 --- a/packages/electron-db-sqlite-persistence/CHANGELOG.md +++ b/packages/electron-db-sqlite-persistence/CHANGELOG.md @@ -1,5 +1,32 @@ # @tanstack/electron-db-sqlite-persistence +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Patch Changes + +- Reloaded persisted collections now read their rows before they write a leader election term. A collection still takes its leader lock when it subscribes, but it reserves its durable term only after the database work already queued on the shared scheduler has settled, or as soon as something needs a leader during that election: a local write, a follower request, a sync commit during startup, or `ensureLeadership`. A need that an earlier leader already served does not let a later takeover skip the wait. A tab that takes over treats the departed leader's route as gone, so a sync commit queued behind one of its reads goes to the new leader and settles without waiting out an RPC timeout. The Electron renderer applies the same rule to its own hydrations. The renderer now has a hydration scope, so its startup runs as one hydration, as a Browser tab's does, and a restart keeps its metadata and row reads in one scope, so a term cannot run between them. ([#2219](https://github.com/TanStack/db/pull/2219)) + + `ensureLeadership` now resolves when this node becomes leader, keeps its place in the Web Locks queue instead of replacing its lock request, and rejects if the coordinator is disposed. + + Migration for custom persistence adapters: `runInRegularScope` is now a `RegularScope`, which must also provide `afterQueuedWork()`. It resolves once every operation queued or running on the adapter's scheduler at the call has settled. An adapter without a scheduler can return a promise that settles with its running hydrations. A coordinator now rejects an adapter whose `runInRegularScope` lacks `afterQueuedWork` with `InvalidPersistenceAdapterError`. + +- Updated dependencies [[`45c3329`](https://github.com/TanStack/db/commit/45c33292b2c4f09a63f856a829c1e15ca2b470aa), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`6bf0e86`](https://github.com/TanStack/db/commit/6bf0e86dbc12e903ef28bb6711968ad06b5d5036), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`b052e91`](https://github.com/TanStack/db/commit/b052e91c79201ee376771f99503566e736e3d0dd), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db-sqlite-persistence-core@1.0.0-rc.1 + ## 0.2.13 ### Patch Changes diff --git a/packages/electron-db-sqlite-persistence/package.json b/packages/electron-db-sqlite-persistence/package.json index 72e61efa40..fdaea309d1 100644 --- a/packages/electron-db-sqlite-persistence/package.json +++ b/packages/electron-db-sqlite-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/electron-db-sqlite-persistence", - "version": "0.2.13", + "version": "1.0.0-rc.1", "description": "Electron SQLite persisted collection bridge for TanStack DB", "author": "TanStack Team", "license": "MIT", diff --git a/packages/expo-db-sqlite-persistence/CHANGELOG.md b/packages/expo-db-sqlite-persistence/CHANGELOG.md index bffabf87cc..6d57692865 100644 --- a/packages/expo-db-sqlite-persistence/CHANGELOG.md +++ b/packages/expo-db-sqlite-persistence/CHANGELOG.md @@ -1,5 +1,26 @@ # @tanstack/expo-db-sqlite-persistence +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Patch Changes + +- Updated dependencies [[`45c3329`](https://github.com/TanStack/db/commit/45c33292b2c4f09a63f856a829c1e15ca2b470aa), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`6bf0e86`](https://github.com/TanStack/db/commit/6bf0e86dbc12e903ef28bb6711968ad06b5d5036), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`b052e91`](https://github.com/TanStack/db/commit/b052e91c79201ee376771f99503566e736e3d0dd), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db-sqlite-persistence-core@1.0.0-rc.1 + ## 0.2.37 ### Patch Changes diff --git a/packages/expo-db-sqlite-persistence/package.json b/packages/expo-db-sqlite-persistence/package.json index 0d310be2c4..776f876036 100644 --- a/packages/expo-db-sqlite-persistence/package.json +++ b/packages/expo-db-sqlite-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/expo-db-sqlite-persistence", - "version": "0.2.37", + "version": "1.0.0-rc.1", "description": "Expo SQLite persisted collection adapter for TanStack DB", "author": "TanStack Team", "license": "MIT", diff --git a/packages/node-db-sqlite-persistence/CHANGELOG.md b/packages/node-db-sqlite-persistence/CHANGELOG.md index 2c37b1802b..b27e577abd 100644 --- a/packages/node-db-sqlite-persistence/CHANGELOG.md +++ b/packages/node-db-sqlite-persistence/CHANGELOG.md @@ -1,5 +1,26 @@ # @tanstack/node-db-sqlite-persistence +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Patch Changes + +- Updated dependencies [[`45c3329`](https://github.com/TanStack/db/commit/45c33292b2c4f09a63f856a829c1e15ca2b470aa), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`6bf0e86`](https://github.com/TanStack/db/commit/6bf0e86dbc12e903ef28bb6711968ad06b5d5036), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`b052e91`](https://github.com/TanStack/db/commit/b052e91c79201ee376771f99503566e736e3d0dd), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db-sqlite-persistence-core@1.0.0-rc.1 + ## 0.2.37 ### Patch Changes diff --git a/packages/node-db-sqlite-persistence/package.json b/packages/node-db-sqlite-persistence/package.json index d8d8c04e41..56949034a9 100644 --- a/packages/node-db-sqlite-persistence/package.json +++ b/packages/node-db-sqlite-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/node-db-sqlite-persistence", - "version": "0.2.37", + "version": "1.0.0-rc.1", "description": "Node SQLite persisted collection adapter for TanStack DB", "author": "TanStack Team", "license": "MIT", diff --git a/packages/offline-transactions/CHANGELOG.md b/packages/offline-transactions/CHANGELOG.md index fe5f3411b8..e5497679ff 100644 --- a/packages/offline-transactions/CHANGELOG.md +++ b/packages/offline-transactions/CHANGELOG.md @@ -1,5 +1,25 @@ # @tanstack/offline-transactions +## 1.2.0 + +### Minor Changes + +- Add a Convex collection adapter with typed query subscriptions, full-row sync, automatic reactive pagination with on-demand windows for a fixed ordered query, durable offline mutation replay, optimistic mutation handlers, and support for both Convex JavaScript and React clients. ([#2230](https://github.com/TanStack/db/pull/2230)) + + Add opt-in mutation codecs to the durable outbox while preserving the default wire format and retaining unreadable codec records for recovery. + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + ## 1.1.4 ### Patch Changes diff --git a/packages/offline-transactions/package.json b/packages/offline-transactions/package.json index 8da9821867..b4fdb79d6c 100644 --- a/packages/offline-transactions/package.json +++ b/packages/offline-transactions/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/offline-transactions", - "version": "1.1.4", + "version": "1.2.0", "description": "Offline-first transaction capabilities for TanStack DB", "author": "TanStack", "license": "MIT", diff --git a/packages/powersync-db-collection/CHANGELOG.md b/packages/powersync-db-collection/CHANGELOG.md index 0d49dd1a49..d2abacfa8f 100644 --- a/packages/powersync-db-collection/CHANGELOG.md +++ b/packages/powersync-db-collection/CHANGELOG.md @@ -1,5 +1,56 @@ # @tanstack/powersync-db-collection +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 + ## 0.2.13 ### Patch Changes diff --git a/packages/powersync-db-collection/package.json b/packages/powersync-db-collection/package.json index da109832ef..4b32c2687c 100644 --- a/packages/powersync-db-collection/package.json +++ b/packages/powersync-db-collection/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/powersync-db-collection", - "version": "0.2.13", + "version": "1.0.0-rc.1", "description": "PowerSync collection for TanStack DB", "author": "POWERSYNC", "license": "MIT", diff --git a/packages/preact-db/CHANGELOG.md b/packages/preact-db/CHANGELOG.md new file mode 100644 index 0000000000..9594576120 --- /dev/null +++ b/packages/preact-db/CHANGELOG.md @@ -0,0 +1,63 @@ +# @tanstack/preact-db + +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Add `@tanstack/preact-db`, a Preact adapter with `useLiveQuery` and `useLiveInfiniteQuery`. Both compare query identity derived from the query IR on each render, require a `queryKey` for functional query variants, and pass the shared live-query and infinite-query conformance suites. Queries read concrete source Collections; `DbProvider` and collection descriptors are not supported yet. ([#2235](https://github.com/TanStack/db/pull/2235)) + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Breaking: grouping, includes, and pooling are now opt-in. An app bundles an operator's code only when it imports the value for that operator. Joins do not change. A typical app is about 8 kB smaller after gzip. This app has a query collection, a filtered live query, and React `useLiveQuery`. ([#2232](https://github.com/TanStack/db/pull/2232)) + + - An include needs `include()`, `toArray()`, or `materialize()`. Change `issues: q.from(...)` in `select()` to `issues: include(q.from(...))`. A subquery in `select()` without one of these throws `IncludeOperatorRequiredError`. + - Aggregates such as `count()` need no change. A `groupBy` with no aggregate takes `groupKeys()`: `.groupBy(groupKeys(({ todo }) => todo.status))`. Without it, the query throws `GroupingOperatorRequiredError`. + - Hooks do not pool live queries by default. To share one partition among many equality-filtered queries, pass `pool: pooledLiveQueries` in the hook's query config: `useLiveQuery({ query, pool: pooledLiveQueries })`. Results do not change. Angular's `{ params, query }` form takes `pool` the same way. Any other `pool` value, such as the old boolean, throws `InvalidPoolOptionError`, also for a disabled query. For adapter authors: the `pool` option of `resolveLiveQueryValue` is now `pooledLiveQueries` or `false`, not a boolean. An adapter that reads `pool` from its own options checks it with `configPool` first. + - Code that builds query IR by hand must supply the operator code. `IR.Aggregate` takes `groupingCompiler` as its third argument. `IR.IncludesSubquery` takes `includesRuntime` as its fifth argument, before `parentFilters`. Import both from `@tanstack/db`. IR without them throws `GroupingOperatorRequiredError` or `IncludeOperatorRequiredError` when it compiles, unless another aggregate or `groupKeys()` in the query supplies the grouping compiler. Queries that the query builder builds need no change. + - Operator code is part of query identity. A hook that re-renders a grouped query without `groupKeys()` now throws `GroupingOperatorRequiredError`. Before, React and Preact kept the grouped query. + - Vue: when a changed query fails to compile, `useLiveQuery` no longer shows the rows of the previous query. + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 diff --git a/packages/preact-db/package.json b/packages/preact-db/package.json index 117fa5e5c0..88391a3943 100644 --- a/packages/preact-db/package.json +++ b/packages/preact-db/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/preact-db", - "version": "0.0.0", + "version": "1.0.0-rc.1", "description": "Preact integration for @tanstack/db", "author": "Kyle Mathews", "license": "MIT", diff --git a/packages/query-db-collection/CHANGELOG.md b/packages/query-db-collection/CHANGELOG.md index dc387cff6e..4d93ad7c61 100644 --- a/packages/query-db-collection/CHANGELOG.md +++ b/packages/query-db-collection/CHANGELOG.md @@ -1,5 +1,55 @@ # @tanstack/query-db-collection +## 1.5.0 + +### Minor Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Fix sync metadata reads that missed committed sync writes while an optimistic transaction held them. A sync source now reads its own writes in commit order: `metadata.row.get`, `metadata.collection.get`, and `list()` include committed transactions that have not applied yet, then the open transactions. A transaction begun inside an open one is independent, and a hold no longer changes commit order. A source insert over a different source row is a duplicate even when a seed or a hold is present. ([#2262](https://github.com/TanStack/db/pull/2262)) + + Persisted collections treat cached rows as seeds, so a later `DbClient` seed can replace them, also after another tab's notice makes the collection reload from storage. A reload from another tab's notice keeps a seed accepted during a pending transaction, keeps row metadata of rows that do not exist, and keeps a seed's row metadata unless the notice names it. An update over a `DbClient` seed now stores the whole row the collection shows, so a reload or restart keeps the seed's fields. With `rowUpdateMode: 'full'`, an update now replaces its stored row, so a reload or restart no longer brings back fields the update dropped. A reload deletes rows that storage lacks also while a pending transaction holds them. After a notice that requires a full reload, a later notice that names its rows keeps a seed's row metadata again. A schema reset from another tab clears every row and its metadata; in on-demand mode it keeps the `DbClient` seeds the collection holds and still replays demand. Rows that storage holds after a reset keep their metadata, and an equal re-insert of one keeps it too. A commit whose signal aborts before the persisted wrapper applies it no longer takes a `DbClient` seed's place. An insert in the persisted wrapper replaces the row it lands on and writes an `insert` mutation to storage. An equal re-insert keeps the row's metadata without writing it, and the wrapper no longer slows down quadratically with the size of a transaction. + ## 1.4.8 ### Patch Changes diff --git a/packages/query-db-collection/package.json b/packages/query-db-collection/package.json index 379ce387da..e33981c07d 100644 --- a/packages/query-db-collection/package.json +++ b/packages/query-db-collection/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/query-db-collection", - "version": "1.4.8", + "version": "1.5.0", "description": "TanStack Query collection for TanStack DB", "author": "Kyle Mathews", "license": "MIT", diff --git a/packages/react-db/CHANGELOG.md b/packages/react-db/CHANGELOG.md index e064fe3037..8e341865dc 100644 --- a/packages/react-db/CHANGELOG.md +++ b/packages/react-db/CHANGELOG.md @@ -1,5 +1,83 @@ # @tanstack/react-db +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- **Breaking (1.0):** a live query whose IR has no stable identity, such as one using `fn.where`, `fn.select`, or `fn.having`, now throws `UnhashableQueryIRError` unless it supplies a nonempty `queryKey`. It previously warned in development and kept its first compilation. An empty `queryKey` now counts as none, as it already did for a `DbClient` preload, so a hook and a preload agree on the query's identity. A dependency array does not replace `queryKey`: in that mode the hook checks identity and claims source Collection IDs each time it binds a live query, including one that `useLiveSuspenseQuery` takes from its cache. A reused source Collection ID now throws `SourceCollectionIdReuseError`. ([#2235](https://github.com/TanStack/db/pull/2235)) + + A rejected render now releases every sync start it deferred for a `DbClient` descriptor, so a later hook or `startSyncImmediate()` can start that source. A render that never commits, because a sibling threw or it suspended, releases them when its live query is reclaimed. + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Breaking: grouping, includes, and pooling are now opt-in. An app bundles an operator's code only when it imports the value for that operator. Joins do not change. A typical app is about 8 kB smaller after gzip. This app has a query collection, a filtered live query, and React `useLiveQuery`. ([#2232](https://github.com/TanStack/db/pull/2232)) + + - An include needs `include()`, `toArray()`, or `materialize()`. Change `issues: q.from(...)` in `select()` to `issues: include(q.from(...))`. A subquery in `select()` without one of these throws `IncludeOperatorRequiredError`. + - Aggregates such as `count()` need no change. A `groupBy` with no aggregate takes `groupKeys()`: `.groupBy(groupKeys(({ todo }) => todo.status))`. Without it, the query throws `GroupingOperatorRequiredError`. + - Hooks do not pool live queries by default. To share one partition among many equality-filtered queries, pass `pool: pooledLiveQueries` in the hook's query config: `useLiveQuery({ query, pool: pooledLiveQueries })`. Results do not change. Angular's `{ params, query }` form takes `pool` the same way. Any other `pool` value, such as the old boolean, throws `InvalidPoolOptionError`, also for a disabled query. For adapter authors: the `pool` option of `resolveLiveQueryValue` is now `pooledLiveQueries` or `false`, not a boolean. An adapter that reads `pool` from its own options checks it with `configPool` first. + - Code that builds query IR by hand must supply the operator code. `IR.Aggregate` takes `groupingCompiler` as its third argument. `IR.IncludesSubquery` takes `includesRuntime` as its fifth argument, before `parentFilters`. Import both from `@tanstack/db`. IR without them throws `GroupingOperatorRequiredError` or `IncludeOperatorRequiredError` when it compiles, unless another aggregate or `groupKeys()` in the query supplies the grouping compiler. Queries that the query builder builds need no change. + - Operator code is part of query identity. A hook that re-renders a grouped query without `groupKeys()` now throws `GroupingOperatorRequiredError`. Before, React and Preact kept the grouped query. + - Vue: when a changed query fails to compile, `useLiveQuery` no longer shows the rows of the previous query. + +- Production builds no longer include the development warnings of `useLiveQuery`. A typical app's bundle is about 1.6 kB smaller before compression and 0.66 kB smaller after gzip. ([#2227](https://github.com/TanStack/db/pull/2227)) + +- Start the required Collection sync run when an ordinary subscriber follows an abandoned suspended render. Deferred acquisition still starts no idle source sync run or acquisition attempt. ([#2229](https://github.com/TanStack/db/pull/2229)) + + Ordinary subscription admission and deferred acquisition resumption throw during cleanup, including automatic GC. Effects created then return disposed handles. Failed setup releases partial ownership, and throwing callbacks cannot prevent healthy observers receiving cleanup status. Subscribers surviving cleanup retain demand for an explicit restart. + + SSR captures each reader's rows and Collection status. Hydration preserves that view through browser preloads, runtime errors, sibling commits, and delayed streamed records. Missing records reject when transport ends. Known pending results survive normal record-stream close. A new stream after client cleanup starts independently of prior failures. + + Empty loading SSR needs no preload. Rendering rows or readiness requires matching query preparation or explicit source Collection preparation. Streaming Suspense prepares its result. Unsupported preparation throws with guidance. Prepared non-streaming Suspense remains supported. The DbClient query hash includes an infinite query's initial limit and offset. + + Apps without `DbClient` exclude its SSR implementation. Its API stays unchanged. + + Svelte roots initialized with `hydrate()` must set `hydrating` on `DbProvider`. Nested providers inherit it. Each provider clears initial hydration after mount so new children read live rows. + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 + ## 0.5.12 ### Patch Changes diff --git a/packages/react-db/package.json b/packages/react-db/package.json index e8cc6eeee4..6e785603d1 100644 --- a/packages/react-db/package.json +++ b/packages/react-db/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-db", - "version": "0.5.12", + "version": "1.0.0-rc.1", "description": "React integration for @tanstack/db", "author": "Kyle Mathews", "license": "MIT", diff --git a/packages/react-native-db-sqlite-persistence/CHANGELOG.md b/packages/react-native-db-sqlite-persistence/CHANGELOG.md index 21ea7b69eb..832e7daa21 100644 --- a/packages/react-native-db-sqlite-persistence/CHANGELOG.md +++ b/packages/react-native-db-sqlite-persistence/CHANGELOG.md @@ -1,5 +1,26 @@ # @tanstack/react-native-db-sqlite-persistence +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Patch Changes + +- Updated dependencies [[`45c3329`](https://github.com/TanStack/db/commit/45c33292b2c4f09a63f856a829c1e15ca2b470aa), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`6bf0e86`](https://github.com/TanStack/db/commit/6bf0e86dbc12e903ef28bb6711968ad06b5d5036), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`b052e91`](https://github.com/TanStack/db/commit/b052e91c79201ee376771f99503566e736e3d0dd), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db-sqlite-persistence-core@1.0.0-rc.1 + ## 0.2.37 ### Patch Changes diff --git a/packages/react-native-db-sqlite-persistence/package.json b/packages/react-native-db-sqlite-persistence/package.json index 62aa57249e..bec9af1ec5 100644 --- a/packages/react-native-db-sqlite-persistence/package.json +++ b/packages/react-native-db-sqlite-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-native-db-sqlite-persistence", - "version": "0.2.37", + "version": "1.0.0-rc.1", "description": "React Native and Expo SQLite persisted collection adapter for TanStack DB", "author": "TanStack Team", "license": "MIT", diff --git a/packages/react-router-with-db/CHANGELOG.md b/packages/react-router-with-db/CHANGELOG.md index de46d8d59f..7b1dd2b697 100644 --- a/packages/react-router-with-db/CHANGELOG.md +++ b/packages/react-router-with-db/CHANGELOG.md @@ -1,5 +1,38 @@ # @tanstack/react-router-with-db +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Patch Changes + +- Start the required Collection sync run when an ordinary subscriber follows an abandoned suspended render. Deferred acquisition still starts no idle source sync run or acquisition attempt. ([#2229](https://github.com/TanStack/db/pull/2229)) + + Ordinary subscription admission and deferred acquisition resumption throw during cleanup, including automatic GC. Effects created then return disposed handles. Failed setup releases partial ownership, and throwing callbacks cannot prevent healthy observers receiving cleanup status. Subscribers surviving cleanup retain demand for an explicit restart. + + SSR captures each reader's rows and Collection status. Hydration preserves that view through browser preloads, runtime errors, sibling commits, and delayed streamed records. Missing records reject when transport ends. Known pending results survive normal record-stream close. A new stream after client cleanup starts independently of prior failures. + + Empty loading SSR needs no preload. Rendering rows or readiness requires matching query preparation or explicit source Collection preparation. Streaming Suspense prepares its result. Unsupported preparation throws with guidance. Prepared non-streaming Suspense remains supported. The DbClient query hash includes an infinite query's initial limit and offset. + + Apps without `DbClient` exclude its SSR implementation. Its API stays unchanged. + + Svelte roots initialized with `hydrate()` must set `hydrating` on `DbProvider`. Nested providers inherit it. Each provider clears initial hydration after mount so new children read live rows. + +- Updated dependencies [[`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`3920346`](https://github.com/TanStack/db/commit/39203466a73648809fb33161c7319d0c60fbb799), [`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023)]: + - @tanstack/react-db@1.0.0-rc.1 + ## 0.1.0 ### Minor Changes diff --git a/packages/react-router-with-db/package.json b/packages/react-router-with-db/package.json index b0b47d56fc..83fed79bb6 100644 --- a/packages/react-router-with-db/package.json +++ b/packages/react-router-with-db/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-router-with-db", - "version": "0.1.0", + "version": "1.0.0-rc.1", "description": "TanStack Router SSR integration for TanStack DB", "author": "Kyle Mathews", "license": "MIT", @@ -48,7 +48,7 @@ "src" ], "peerDependencies": { - "@tanstack/react-db": ">=0.2.1", + "@tanstack/react-db": ">=1.0.0-rc.1", "@tanstack/react-router": ">=1.43.2", "@tanstack/router-core": ">=1.127.0", "react": ">=18.0.0", diff --git a/packages/rxdb-db-collection/CHANGELOG.md b/packages/rxdb-db-collection/CHANGELOG.md index 0c98ff9c9a..8941378b4e 100644 --- a/packages/rxdb-db-collection/CHANGELOG.md +++ b/packages/rxdb-db-collection/CHANGELOG.md @@ -1,5 +1,56 @@ # @tanstack/rxdb-db-collection +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 + ## 0.1.111 ### Patch Changes diff --git a/packages/rxdb-db-collection/package.json b/packages/rxdb-db-collection/package.json index f0bb54d37a..db17e6cbf1 100644 --- a/packages/rxdb-db-collection/package.json +++ b/packages/rxdb-db-collection/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/rxdb-db-collection", - "version": "0.1.111", + "version": "1.0.0-rc.1", "description": "Reactive, Offline-First adapter for TanStack DB using RxDB. Sync, Replication and Local-First support.", "author": "Kyle Mathews", "license": "MIT", diff --git a/packages/solid-db/CHANGELOG.md b/packages/solid-db/CHANGELOG.md index 73701dfbae..4bf2f96d30 100644 --- a/packages/solid-db/CHANGELOG.md +++ b/packages/solid-db/CHANGELOG.md @@ -1,5 +1,67 @@ # @tanstack/react-db +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Breaking: grouping, includes, and pooling are now opt-in. An app bundles an operator's code only when it imports the value for that operator. Joins do not change. A typical app is about 8 kB smaller after gzip. This app has a query collection, a filtered live query, and React `useLiveQuery`. ([#2232](https://github.com/TanStack/db/pull/2232)) + + - An include needs `include()`, `toArray()`, or `materialize()`. Change `issues: q.from(...)` in `select()` to `issues: include(q.from(...))`. A subquery in `select()` without one of these throws `IncludeOperatorRequiredError`. + - Aggregates such as `count()` need no change. A `groupBy` with no aggregate takes `groupKeys()`: `.groupBy(groupKeys(({ todo }) => todo.status))`. Without it, the query throws `GroupingOperatorRequiredError`. + - Hooks do not pool live queries by default. To share one partition among many equality-filtered queries, pass `pool: pooledLiveQueries` in the hook's query config: `useLiveQuery({ query, pool: pooledLiveQueries })`. Results do not change. Angular's `{ params, query }` form takes `pool` the same way. Any other `pool` value, such as the old boolean, throws `InvalidPoolOptionError`, also for a disabled query. For adapter authors: the `pool` option of `resolveLiveQueryValue` is now `pooledLiveQueries` or `false`, not a boolean. An adapter that reads `pool` from its own options checks it with `configPool` first. + - Code that builds query IR by hand must supply the operator code. `IR.Aggregate` takes `groupingCompiler` as its third argument. `IR.IncludesSubquery` takes `includesRuntime` as its fifth argument, before `parentFilters`. Import both from `@tanstack/db`. IR without them throws `GroupingOperatorRequiredError` or `IncludeOperatorRequiredError` when it compiles, unless another aggregate or `groupKeys()` in the query supplies the grouping compiler. Queries that the query builder builds need no change. + - Operator code is part of query identity. A hook that re-renders a grouped query without `groupKeys()` now throws `GroupingOperatorRequiredError`. Before, React and Preact kept the grouped query. + - Vue: when a changed query fails to compile, `useLiveQuery` no longer shows the rows of the previous query. + +- Cap the `solid-js` peer range at `^1`. The previous open-ended `>=` range would accept Solid 2.0.0 once it is released, but these packages are built against Solid 1 and do not work with Solid 2. ([#2286](https://github.com/TanStack/db/pull/2286)) + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 + ## 0.3.12 ### Patch Changes diff --git a/packages/solid-db/package.json b/packages/solid-db/package.json index 18a922c5fe..95725d6199 100644 --- a/packages/solid-db/package.json +++ b/packages/solid-db/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-db", - "version": "0.3.12", + "version": "1.0.0-rc.1", "description": "Solid integration for @tanstack/db", "author": "Kyle Mathews", "license": "MIT", diff --git a/packages/svelte-db/CHANGELOG.md b/packages/svelte-db/CHANGELOG.md index 4f822e9900..2cfb2e913b 100644 --- a/packages/svelte-db/CHANGELOG.md +++ b/packages/svelte-db/CHANGELOG.md @@ -1,5 +1,81 @@ # @tanstack/svelte-db +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +- **Breaking (1.0):** a `useLiveQuery` backed by a `DbClient` matches queries by identity hash, so it now throws `UnhashableQueryIRError` for a query without a stable IR identity unless it supplies a nonempty `queryKey`. It previously compiled the query without a hydration key. While such a hook is mounted, a different source Collection under a Collection ID it already read throws `SourceCollectionIdReuseError`, and every result property then throws instead of returning the previous query's state. Queries without a `DbClient` are unchanged. ([#2235](https://github.com/TanStack/db/pull/2235)) + + A rejected client-backed query now releases every sync start it deferred, so `startSyncImmediate()` or another hook can still start that source. A setup that throws after the hook returns releases them when its live query is reclaimed. `useLiveInfiniteQuery` now uses the shared window binding from `@tanstack/db`. + +### Patch Changes + +- Breaking: grouping, includes, and pooling are now opt-in. An app bundles an operator's code only when it imports the value for that operator. Joins do not change. A typical app is about 8 kB smaller after gzip. This app has a query collection, a filtered live query, and React `useLiveQuery`. ([#2232](https://github.com/TanStack/db/pull/2232)) + + - An include needs `include()`, `toArray()`, or `materialize()`. Change `issues: q.from(...)` in `select()` to `issues: include(q.from(...))`. A subquery in `select()` without one of these throws `IncludeOperatorRequiredError`. + - Aggregates such as `count()` need no change. A `groupBy` with no aggregate takes `groupKeys()`: `.groupBy(groupKeys(({ todo }) => todo.status))`. Without it, the query throws `GroupingOperatorRequiredError`. + - Hooks do not pool live queries by default. To share one partition among many equality-filtered queries, pass `pool: pooledLiveQueries` in the hook's query config: `useLiveQuery({ query, pool: pooledLiveQueries })`. Results do not change. Angular's `{ params, query }` form takes `pool` the same way. Any other `pool` value, such as the old boolean, throws `InvalidPoolOptionError`, also for a disabled query. For adapter authors: the `pool` option of `resolveLiveQueryValue` is now `pooledLiveQueries` or `false`, not a boolean. An adapter that reads `pool` from its own options checks it with `configPool` first. + - Code that builds query IR by hand must supply the operator code. `IR.Aggregate` takes `groupingCompiler` as its third argument. `IR.IncludesSubquery` takes `includesRuntime` as its fifth argument, before `parentFilters`. Import both from `@tanstack/db`. IR without them throws `GroupingOperatorRequiredError` or `IncludeOperatorRequiredError` when it compiles, unless another aggregate or `groupKeys()` in the query supplies the grouping compiler. Queries that the query builder builds need no change. + - Operator code is part of query identity. A hook that re-renders a grouped query without `groupKeys()` now throws `GroupingOperatorRequiredError`. Before, React and Preact kept the grouped query. + - Vue: when a changed query fails to compile, `useLiveQuery` no longer shows the rows of the previous query. + +- Start the required Collection sync run when an ordinary subscriber follows an abandoned suspended render. Deferred acquisition still starts no idle source sync run or acquisition attempt. ([#2229](https://github.com/TanStack/db/pull/2229)) + + Ordinary subscription admission and deferred acquisition resumption throw during cleanup, including automatic GC. Effects created then return disposed handles. Failed setup releases partial ownership, and throwing callbacks cannot prevent healthy observers receiving cleanup status. Subscribers surviving cleanup retain demand for an explicit restart. + + SSR captures each reader's rows and Collection status. Hydration preserves that view through browser preloads, runtime errors, sibling commits, and delayed streamed records. Missing records reject when transport ends. Known pending results survive normal record-stream close. A new stream after client cleanup starts independently of prior failures. + + Empty loading SSR needs no preload. Rendering rows or readiness requires matching query preparation or explicit source Collection preparation. Streaming Suspense prepares its result. Unsupported preparation throws with guidance. Prepared non-streaming Suspense remains supported. The DbClient query hash includes an infinite query's initial limit and offset. + + Apps without `DbClient` exclude its SSR implementation. Its API stays unchanged. + + Svelte roots initialized with `hydrate()` must set `hydrating` on `DbProvider`. Nested providers inherit it. Each provider clears initial hydration after mount so new children read live rows. + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 + ## 0.5.12 ### Patch Changes diff --git a/packages/svelte-db/package.json b/packages/svelte-db/package.json index 661171de0b..0fd929bfd0 100644 --- a/packages/svelte-db/package.json +++ b/packages/svelte-db/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/svelte-db", - "version": "0.5.12", + "version": "1.0.0-rc.1", "description": "Svelte integration for @tanstack/db", "author": "Kyle Mathews", "license": "MIT", diff --git a/packages/tauri-db-sqlite-persistence/CHANGELOG.md b/packages/tauri-db-sqlite-persistence/CHANGELOG.md index 4d7619529a..90d8ddc436 100644 --- a/packages/tauri-db-sqlite-persistence/CHANGELOG.md +++ b/packages/tauri-db-sqlite-persistence/CHANGELOG.md @@ -1,5 +1,26 @@ # @tanstack/tauri-db-sqlite-persistence +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Patch Changes + +- Updated dependencies [[`45c3329`](https://github.com/TanStack/db/commit/45c33292b2c4f09a63f856a829c1e15ca2b470aa), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`6bf0e86`](https://github.com/TanStack/db/commit/6bf0e86dbc12e903ef28bb6711968ad06b5d5036), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`205ab71`](https://github.com/TanStack/db/commit/205ab7158d81680c3cc4f06cd9ebe62b30911a5a), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`b052e91`](https://github.com/TanStack/db/commit/b052e91c79201ee376771f99503566e736e3d0dd), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db-sqlite-persistence-core@1.0.0-rc.1 + ## 0.2.37 ### Patch Changes diff --git a/packages/tauri-db-sqlite-persistence/package.json b/packages/tauri-db-sqlite-persistence/package.json index 6374e98e0f..ef7eaf0070 100644 --- a/packages/tauri-db-sqlite-persistence/package.json +++ b/packages/tauri-db-sqlite-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/tauri-db-sqlite-persistence", - "version": "0.2.37", + "version": "1.0.0-rc.1", "description": "Tauri SQLite persisted collection adapter for TanStack DB", "author": "TanStack Team", "license": "MIT", diff --git a/packages/trailbase-db-collection/CHANGELOG.md b/packages/trailbase-db-collection/CHANGELOG.md index 7ee6eeb41a..6be79ee261 100644 --- a/packages/trailbase-db-collection/CHANGELOG.md +++ b/packages/trailbase-db-collection/CHANGELOG.md @@ -1,5 +1,56 @@ # @tanstack/trailbase-db-collection +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 + ## 0.1.123 ### Patch Changes diff --git a/packages/trailbase-db-collection/package.json b/packages/trailbase-db-collection/package.json index 0af52d40ee..cb00645aea 100644 --- a/packages/trailbase-db-collection/package.json +++ b/packages/trailbase-db-collection/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/trailbase-db-collection", - "version": "0.1.123", + "version": "1.0.0-rc.1", "description": "TrailBase collection for TanStack DB", "author": "Sebastian Jeltsch", "license": "MIT", diff --git a/packages/vue-db/CHANGELOG.md b/packages/vue-db/CHANGELOG.md index 74fb3918b3..b8841ab951 100644 --- a/packages/vue-db/CHANGELOG.md +++ b/packages/vue-db/CHANGELOG.md @@ -1,5 +1,67 @@ # @tanstack/vue-db +## 1.0.0-rc.1 + +### Major Changes + +- Release the first 1.0 candidate. Remove deprecated pre-1.0 APIs and give ([#2171](https://github.com/TanStack/db/pull/2171)) + published row metadata precedence over colliding selected fields. Structured + source spreads and direct source-row returns keep source attribution; new + functional objects and other projections receive output Collection metadata. + Keep the two packages accidentally released as stable 1.x on their stable + release lines. Both stable minor releases require `@tanstack/db@^1.0.0-rc.0` + for the RC health and restoration settlement APIs; upgrade DB with them. + + Remove Query Collection’s automatic refetch after mutation handlers. Handlers + return `Promise` and must await `collection.utils.refetch()` or write + confirmed data with the `write*` utilities; `{ refetch: false }` is removed. + +### Minor Changes + +- Collections now answer two questions separately: can the data be shown (`status`), and is it still kept up to date (`health`). Once a query has shown data, a network or backend failure never takes it off the screen. ([#2168](https://github.com/TanStack/db/pull/2168)) + + - `status` gains `crashed`: local storage broke (a closed IndexedDB connection, a failed SQLite persistence write or restore, a throwing sync function, or an invariant failure). Nothing recovers it in place, and `reload()` rejects. To recover, call `cleanup({ dependents: true })`, then start the Collection again (for example with `preload()`); it starts with no rows. It reaches every live query and Effect above it. `error` now means only "the first load failed". + - Every Collection has `collection.health`, a health node with `status`, `failureReason` (the adapter is still trying), `error` (the adapter stopped, or the first load failed), `reloading`, and `hasErrors`. A live query's `health` has one node per source alias, in query order, and keeps object identity while unchanged. `health:change` fires when it changes. `findProblems(health)` lists the nodes that have a problem, in query order. Each problem (`HealthProblem`) shows its newest failure in `message`, `cause`, and `at`, and lists every failure still open in `errors`, oldest first: each `reportError()` of the sync run until `reportHealthy()`, or each failed request for more data on a live query's node. One error value is one failure: reporting it again changes nothing, and `reportHealthy(error)` removes just that failure, so a query Collection whose failing Query recovers removes only that Query's failures. After a live query is ready, a failed request for more data (a page, a joined row, or a source reload's replay of its data) is an `error` on the query's own node; the source stays healthy. + - `collection.reload()` starts a new sync run and keeps the rows, status, and error on screen until the reload completes: when the new run's snapshot (`begin({ snapshot: true })`) or `truncate()` applies, or at its `markReady()`, which keeps the rows when no snapshot came. On a live query it reloads every Collection below it that shows an `error`, through nested live queries, then the query itself when its own node has an `error`, including a failed request for more data. It rejects on a `crashed` Collection. When the cleanup of the sync run that a reload retired rejects, the Collection crashes, also if the rejection comes later. A query in `error` stays there until its `reload()`. + - `cleanup()` rejects with `CollectionHasSubscribersError` while a live query with subscribers or an Effect reads the Collection. `cleanup({ dependents: true })` ends them first. `collection.subscribers` lists every dependent. + - A local-only Collection's `reload()` keeps its rows, including the user's writes: `initialData` loads only when the Collection starts, or starts again after cleanup. + - Persisted Collections have one status. With `initialRender: { strategy: 'network-first' }`, restored rows make the Collection `ready` once the deadline passes or the remote fails; an empty restore stays `loading`. Only a local storage failure crashes a persisted Collection: a failed remote subset request is a failure reason, which the next successful remote request clears. + + Breaking changes and migration: + + | Before | After | + | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | + | hook `isError` | `isLoadingError` (first load failed) or `isCrashed` | + | — | `isSyncError`: `ready` and the health tree has a problem | + | `status: 'error'` after a crash | `status: 'crashed'` | + | adapter `markError(error)` | `fail(error)`. After readiness it sets the node's `error` and keeps the rows. Later calls throw. | + | `cleanup()` then `preload()` to recover | `reload()` | + | adapter `begin({ direct: true })` | `begin()`: every write applies on the rows the Collection holds, also during a reload | + | a reload's first commit replaced every row | `begin({ snapshot: true })` or `truncate()` in the new run replaces them | + | adapter `markReady()` after `fail()` threw | it does nothing | + | `cleanup()` while live queries or Effects read the Collection | rejects; unmount first or pass `{ dependents: true }` | + | `persistedStatus`, `isPersistedReady`, `persistedError`, `preloadForInitialRender()`, `PERSISTED_READINESS` | `status` and `health` | + | query-db `utils.lastError`, `utils.isError`, `utils.errorCount`, `utils.clearError()` | `collection.health`, `reload()` | + | infinite-query hooks' `error` (React, Preact, Vue, Svelte) | the root node's `error` in `health`; `fetchNextPage()` still resolves | + + Custom sync adapters: keep the run's readiness in your `sync` function. A reload calls `sync` again while `collection.status` still shows the previous run's status and the Collection still holds the previous run's rows. The new run's writes apply on those rows; it replaces every row only with a snapshot, a transaction begun with `begin({ snapshot: true })`, or with its own `truncate()`. The reload completes when that replacement applies, or at the new run's `markReady()`, which keeps the rows when no snapshot came. So send the new run's full state as a snapshot, or write against the kept rows: an `insert` of a key the Collection holds throws `DuplicateKeySyncError`, during a reload as at any time, so write `update` for a kept row, also from a replayed load after the reload completed. A reload keeps every row its new run does not rewrite: core never deletes kept rows on its own, so removing a row the backend deleted is the adapter's job, through a snapshot, a `delete`, or row ownership ([#2269](https://github.com/TanStack/db/issues/2269)). An on-demand `loadSubset` result is partial and is never a snapshot. A live query's own reload keeps its rows and its window until its new run's result is complete. `reportError()` and `reportHealthy()` throw before the first `markReady()` and after `fail()`. `markReady()` after the run is ready, or after its `fail()`, does nothing, so an adapter needs no flag of its own to guard it. A second `fail()` in the same sync run does nothing. A first-ready callback that throws while `sync` runs is reported uncaught, and the Collection stays ready. `reload()` called from inside `sync` or a `loadSubset` call rejects, unless a reload is already in flight, whose promise it returns. Calls after a crash do nothing. For an on-demand Collection, a reload aborts the retired run's `loadSubset` calls and asks the new run's `loadSubset` for the current demand as soon as `sync` returns. Honor the `signal`: when core aborts a load, that load is over for core, and its later resolve or reject decides nothing, holds no readiness, and no replay waits for it. A `loadSubset` that throws synchronously is a rejection: a failed load, which `requestSnapshot()` and `setWindow()` report without throwing. A truncate's or reload's replay decides every request error of the query's demand: its success clears them all, and its failure replaces them with the replay's failures. `useLiveSuspenseQuery` now throws an Error for a failed first load or a crash: the cause itself when it is an Error, otherwise an Error with the problem's message whose `cause` holds the reported value. + +### Patch Changes + +- Breaking: grouping, includes, and pooling are now opt-in. An app bundles an operator's code only when it imports the value for that operator. Joins do not change. A typical app is about 8 kB smaller after gzip. This app has a query collection, a filtered live query, and React `useLiveQuery`. ([#2232](https://github.com/TanStack/db/pull/2232)) + + - An include needs `include()`, `toArray()`, or `materialize()`. Change `issues: q.from(...)` in `select()` to `issues: include(q.from(...))`. A subquery in `select()` without one of these throws `IncludeOperatorRequiredError`. + - Aggregates such as `count()` need no change. A `groupBy` with no aggregate takes `groupKeys()`: `.groupBy(groupKeys(({ todo }) => todo.status))`. Without it, the query throws `GroupingOperatorRequiredError`. + - Hooks do not pool live queries by default. To share one partition among many equality-filtered queries, pass `pool: pooledLiveQueries` in the hook's query config: `useLiveQuery({ query, pool: pooledLiveQueries })`. Results do not change. Angular's `{ params, query }` form takes `pool` the same way. Any other `pool` value, such as the old boolean, throws `InvalidPoolOptionError`, also for a disabled query. For adapter authors: the `pool` option of `resolveLiveQueryValue` is now `pooledLiveQueries` or `false`, not a boolean. An adapter that reads `pool` from its own options checks it with `configPool` first. + - Code that builds query IR by hand must supply the operator code. `IR.Aggregate` takes `groupingCompiler` as its third argument. `IR.IncludesSubquery` takes `includesRuntime` as its fifth argument, before `parentFilters`. Import both from `@tanstack/db`. IR without them throws `GroupingOperatorRequiredError` or `IncludeOperatorRequiredError` when it compiles, unless another aggregate or `groupKeys()` in the query supplies the grouping compiler. Queries that the query builder builds need no change. + - Operator code is part of query identity. A hook that re-renders a grouped query without `groupKeys()` now throws `GroupingOperatorRequiredError`. Before, React and Preact kept the grouped query. + - Vue: when a changed query fails to compile, `useLiveQuery` no longer shows the rows of the previous query. + +- `useLiveInfiniteQuery` now uses the shared window binding from `@tanstack/db`. A window collection it creates starts syncing when the query compiles, as in the other adapters, and an update that changes nothing keeps the current controller. ([#2235](https://github.com/TanStack/db/pull/2235)) + +- Updated dependencies [[`5649a07`](https://github.com/TanStack/db/commit/5649a07d468117891193c2e4cde9c7706308b1cd), [`43d4ef6`](https://github.com/TanStack/db/commit/43d4ef65cfe5c3cfbce6c56891795cd36a73cc37), [`7538afd`](https://github.com/TanStack/db/commit/7538afd2fa838340aaa63fca8b221154eb0b1572), [`a07cd73`](https://github.com/TanStack/db/commit/a07cd73739c1f135e658f38621de27f336004d11), [`6c1ca8f`](https://github.com/TanStack/db/commit/6c1ca8f8f9efe437d3cea61b5b9d0a086e2a5e34), [`30175be`](https://github.com/TanStack/db/commit/30175be483fa70799da579e2c407fb7ed9f2b435), [`4c39add`](https://github.com/TanStack/db/commit/4c39add293adb65b4f5537628849f97083a31531), [`1640de8`](https://github.com/TanStack/db/commit/1640de834bca0588f91432ea80a0f4569157e9dc), [`367ea7c`](https://github.com/TanStack/db/commit/367ea7c11e7dee5ca48ba524e55da2a6935d55fb), [`7d9ed02`](https://github.com/TanStack/db/commit/7d9ed02e085d11e871e4b6424d47e3c0d7073023), [`45eeef8`](https://github.com/TanStack/db/commit/45eeef81a7c64966473315558f46e8a53b00e462)]: + - @tanstack/db@1.0.0-rc.1 + ## 0.3.12 ### Patch Changes diff --git a/packages/vue-db/package.json b/packages/vue-db/package.json index a6ec622aa0..530d7523b4 100644 --- a/packages/vue-db/package.json +++ b/packages/vue-db/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/vue-db", - "version": "0.3.12", + "version": "1.0.0-rc.1", "description": "Vue integration for @tanstack/db", "author": "Kyle Mathews", "license": "MIT", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 629123ffc0..386af2630a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -168,10 +168,10 @@ importers: specifier: ^20.3.34 version: 20.3.34(@angular/common@20.3.34(@angular/core@20.3.34(@angular/compiler@20.3.34)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.34(@angular/compiler@20.3.34)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.34(@angular/common@20.3.34(@angular/core@20.3.34(@angular/compiler@20.3.34)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.34(@angular/compiler@20.3.34)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) '@tanstack/angular-db': - specifier: ^0.2.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/angular-db '@tanstack/db': - specifier: ^0.15.2 + specifier: ^1.0.0-rc.1 version: link:../../../packages/db rxjs: specifier: ^7.8.2 @@ -208,19 +208,19 @@ importers: examples/electron/offline-first: dependencies: '@tanstack/electron-db-sqlite-persistence': - specifier: ^0.2.13 + specifier: ^1.0.0-rc.1 version: link:../../../packages/electron-db-sqlite-persistence '@tanstack/node-db-sqlite-persistence': - specifier: ^0.2.37 + specifier: ^1.0.0-rc.1 version: link:../../../packages/node-db-sqlite-persistence '@tanstack/offline-transactions': - specifier: ^1.1.4 + specifier: ^1.2.0 version: link:../../../packages/offline-transactions '@tanstack/query-db-collection': - specifier: ^1.4.8 + specifier: ^1.5.0 version: link:../../../packages/query-db-collection '@tanstack/react-db': - specifier: ^0.5.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-db '@tanstack/react-query': specifier: ^5.90.20 @@ -299,19 +299,19 @@ importers: specifier: 11.4.1 version: 11.4.1(react-native@0.79.6(@babel/core@7.29.7)(@types/react@19.2.13)(react@19.0.0)) '@tanstack/db': - specifier: ^0.15.2 + specifier: ^1.0.0-rc.1 version: link:../../../packages/db '@tanstack/offline-transactions': - specifier: ^1.1.4 + specifier: ^1.2.0 version: link:../../../packages/offline-transactions '@tanstack/query-db-collection': - specifier: ^1.4.8 + specifier: ^1.5.0 version: link:../../../packages/query-db-collection '@tanstack/react-db': - specifier: ^0.5.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-db '@tanstack/react-native-db-sqlite-persistence': - specifier: ^0.2.37 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-native-db-sqlite-persistence '@tanstack/react-query': specifier: ^5.90.20 @@ -396,19 +396,19 @@ importers: specifier: 11.4.1 version: 11.4.1(react-native@0.79.6(@babel/core@7.29.7)(@types/react@19.2.13)(react@19.0.0)) '@tanstack/db': - specifier: ^0.15.2 + specifier: ^1.0.0-rc.1 version: link:../../../packages/db '@tanstack/electric-db-collection': - specifier: ^0.6.3 + specifier: ^1.0.0-rc.1 version: link:../../../packages/electric-db-collection '@tanstack/offline-transactions': - specifier: ^1.1.4 + specifier: ^1.2.0 version: link:../../../packages/offline-transactions '@tanstack/react-db': - specifier: ^0.5.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-db '@tanstack/react-native-db-sqlite-persistence': - specifier: ^0.2.37 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-native-db-sqlite-persistence '@tanstack/react-query': specifier: ^5.90.20 @@ -484,10 +484,10 @@ importers: specifier: ^5.90.20 version: 5.90.20 '@tanstack/query-db-collection': - specifier: ^1.4.8 + specifier: ^1.5.0 version: link:../../../packages/query-db-collection '@tanstack/react-db': - specifier: ^0.5.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-db react: specifier: ^19.2.4 @@ -536,10 +536,10 @@ importers: examples/react/next-ssr-e2e: dependencies: '@tanstack/db': - specifier: ^0.15.2 + specifier: ^1.0.0-rc.1 version: link:../../../packages/db '@tanstack/react-db': - specifier: ^0.5.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-db next: specifier: ^16.3.1 @@ -570,19 +570,19 @@ importers: examples/react/offline-transactions: dependencies: '@tanstack/browser-db-sqlite-persistence': - specifier: ^0.2.37 + specifier: ^1.0.0-rc.1 version: link:../../../packages/browser-db-sqlite-persistence '@tanstack/db': - specifier: ^0.15.2 + specifier: ^1.0.0-rc.1 version: link:../../../packages/db '@tanstack/offline-transactions': - specifier: ^1.1.4 + specifier: ^1.2.0 version: link:../../../packages/offline-transactions '@tanstack/query-db-collection': - specifier: ^1.4.8 + specifier: ^1.5.0 version: link:../../../packages/query-db-collection '@tanstack/react-db': - specifier: ^0.5.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-db '@tanstack/react-query': specifier: ^5.90.20 @@ -640,10 +640,10 @@ importers: examples/react/paced-mutations-demo: dependencies: '@tanstack/db': - specifier: ^0.15.2 + specifier: ^1.0.0-rc.1 version: link:../../../packages/db '@tanstack/react-db': - specifier: ^0.5.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-db mitt: specifier: ^3.0.1 @@ -680,10 +680,10 @@ importers: specifier: ^5.90.20 version: 5.90.20 '@tanstack/query-db-collection': - specifier: ^1.4.8 + specifier: ^1.5.0 version: link:../../../packages/query-db-collection '@tanstack/react-db': - specifier: ^0.5.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-db '@tanstack/react-router': specifier: ^1.170.41 @@ -813,13 +813,13 @@ importers: examples/react/start-ssr-e2e: dependencies: '@tanstack/react-db': - specifier: ^0.5.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-db '@tanstack/react-router': specifier: ^1.170.41 version: 1.170.41(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-router-with-db': - specifier: ^0.1.0 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-router-with-db '@tanstack/react-start': specifier: ^1.168.60 @@ -859,16 +859,16 @@ importers: examples/react/todo: dependencies: '@tanstack/electric-db-collection': - specifier: ^0.6.3 + specifier: ^1.0.0-rc.1 version: link:../../../packages/electric-db-collection '@tanstack/query-core': specifier: ^5.90.20 version: 5.90.20 '@tanstack/query-db-collection': - specifier: ^1.4.8 + specifier: ^1.5.0 version: link:../../../packages/query-db-collection '@tanstack/react-db': - specifier: ^0.5.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/react-db '@tanstack/react-router': specifier: ^1.170.41 @@ -877,7 +877,7 @@ importers: specifier: ^1.168.60 version: 1.168.60(esbuild@0.28.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.64.12)(vite-plugin-solid@2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.7(@types/node@25.2.2)(jiti@2.7.0)(lightningcss@1.33.0)(sass@1.90.0)(terser@5.51.2)(tsx@4.21.0)(yaml@2.8.1)))(vite@7.3.7(@types/node@25.2.2)(jiti@2.7.0)(lightningcss@1.33.0)(sass@1.90.0)(terser@5.51.2)(tsx@4.21.0)(yaml@2.8.1))(webpack@5.112.0(esbuild@0.28.1)(lightningcss@1.33.0)) '@tanstack/trailbase-db-collection': - specifier: ^0.1.123 + specifier: ^1.0.0-rc.1 version: link:../../../packages/trailbase-db-collection cors: specifier: ^2.8.6 @@ -980,16 +980,16 @@ importers: examples/solid/todo: dependencies: '@tanstack/electric-db-collection': - specifier: ^0.6.3 + specifier: ^1.0.0-rc.1 version: link:../../../packages/electric-db-collection '@tanstack/query-core': specifier: ^5.90.20 version: 5.90.20 '@tanstack/query-db-collection': - specifier: ^1.4.8 + specifier: ^1.5.0 version: link:../../../packages/query-db-collection '@tanstack/solid-db': - specifier: ^0.3.12 + specifier: ^1.0.0-rc.1 version: link:../../../packages/solid-db '@tanstack/solid-router': specifier: ^1.170.38 @@ -998,7 +998,7 @@ importers: specifier: ^1.168.57 version: 1.168.57(@tanstack/react-router@1.170.41(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(esbuild@0.28.1)(rollup@4.64.12)(solid-js@1.9.11)(vite-plugin-solid@2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.7(@types/node@25.2.2)(jiti@2.7.0)(lightningcss@1.33.0)(sass@1.90.0)(terser@5.51.2)(tsx@4.21.0)(yaml@2.8.1)))(vite@7.3.7(@types/node@25.2.2)(jiti@2.7.0)(lightningcss@1.33.0)(sass@1.90.0)(terser@5.51.2)(tsx@4.21.0)(yaml@2.8.1))(webpack@5.112.0(esbuild@0.28.1)(lightningcss@1.33.0)) '@tanstack/trailbase-db-collection': - specifier: ^0.1.123 + specifier: ^1.0.0-rc.1 version: link:../../../packages/trailbase-db-collection cors: specifier: ^2.8.6 From a978f2a85a99eb44f97e8ef43b9db98932bf26f8 Mon Sep 17 00:00:00 2001 From: Test Date: Thu, 29 Oct 2026 09:11:23 -0600 Subject: [PATCH 2/2] test: align release checks with first RC versions --- packages/react-router-with-db/tests/index.test.ts | 2 +- scripts/version-packages.test.mjs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/react-router-with-db/tests/index.test.ts b/packages/react-router-with-db/tests/index.test.ts index b177ebf94d..d1a107f3e5 100644 --- a/packages/react-router-with-db/tests/index.test.ts +++ b/packages/react-router-with-db/tests/index.test.ts @@ -33,7 +33,7 @@ describe(`routerWithDbClient`, () => { } expect(packageJson.peerDependencies).toMatchObject({ - '@tanstack/react-db': `>=0.2.1`, + '@tanstack/react-db': `>=1.0.0-rc.1`, '@tanstack/router-core': `>=1.127.0`, }) }) diff --git a/scripts/version-packages.test.mjs b/scripts/version-packages.test.mjs index 65d0189352..5628ec14b2 100644 --- a/scripts/version-packages.test.mjs +++ b/scripts/version-packages.test.mjs @@ -60,7 +60,10 @@ test('the first RC changeset covers the current public package inventory', () => ) for (const manifest of publicPackages) { const bump = entries.find((entry) => entry[1] === manifest.name)[2] - assert.equal(bump, manifest.version.startsWith('0.') ? 'major' : 'minor') + // Versioning keeps the first changeset during prerelease mode, so this + // inventory check must recognize candidates after the seed has run too. + const candidate = /^(?:0\.|1\.0\.0-rc\.)/.test(manifest.version) + assert.equal(bump, candidate ? 'major' : 'minor') } })