Skip to content

Conversation

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented Dec 30, 2025

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

@tanstack/angular-db@0.1.43

Patch Changes

@tanstack/db@0.5.17

Patch Changes

  • Export QueryResult helper type for easily extracting query result types (similar to Zod's z.infer). (#1096)

    import { Query, QueryResult } from '@tanstack/db'
    
    const myQuery = new Query()
      .from({ users })
      .select(({ users }) => ({ name: users.name }))
    
    // Extract the result type - clean and simple!
    type MyQueryResult = QueryResult<typeof myQuery>

    Also exports ExtractContext for advanced use cases where you need the full context type.

  • Add validation for where() and having() expressions to catch JavaScript operator usage (#1082)

    When users accidentally use JavaScript's comparison operators (===, !==, <, >, etc.) in where() or having() callbacks instead of query builder functions (eq, gt, etc.), the query builder now throws a helpful InvalidWhereExpressionError with clear guidance.

    Previously, this mistake would result in a confusing "Unknown expression type: undefined" error at query compilation time. Now users get immediate feedback with an example of the correct syntax:

    ❌ .where(({ user }) => user.id === 'abc')
    ✅ .where(({ user }) => eq(user.id, 'abc'))
    
  • Fix asymmetric behavior in deepEquals when comparing different special types (Date, RegExp, Map, Set, TypedArray, Temporal, Array). Previously, comparing values like deepEquals(Date, Temporal.Duration) could return a different result than deepEquals(Temporal.Duration, Date). Now both directions correctly return false for mismatched types, ensuring deepEquals is a proper equivalence relation. (#1018)

  • Add where callback option to subscribeChanges for ergonomic filtering (#943)

    Instead of manually constructing IR with PropRef:

    import { eq, PropRef } from '@tanstack/db'
    collection.subscribeChanges(callback, {
      whereExpression: eq(new PropRef(['status']), 'active'),
    })

    You can now use a callback with query builder functions:

    import { eq } from '@tanstack/db'
    collection.subscribeChanges(callback, {
      where: (row) => eq(row.status, 'active'),
    })

@tanstack/electric-db-collection@0.2.21

Patch Changes

  • Fix orphan transactions after must-refetch in progressive sync mode (#1069)

    When a must-refetch message was received in progressive mode, it started a transaction with truncate() but reset hasReceivedUpToDate, causing subsequent messages to be buffered instead of written to the existing transaction. On up-to-date, the atomic swap code would create a new transaction, leaving the first one uncommitted forever. This caused collections to become corrupted with undefined values.

    The fix ensures that when a transaction is already started (e.g., from must-refetch), messages are written directly to it instead of being buffered for atomic swap.

  • Fix duplicate key error when overlapping subset queries return the same row with different values. (#1070)

    When multiple subset queries return the same row (e.g., different WHERE clauses that both match the same record), the server sends insert operations for each response. If the row's data changed between requests (e.g., timestamp field updated), this caused a DuplicateKeySyncError. The adapter now tracks synced keys and converts subsequent inserts to updates.

  • Updated dependencies [f795a67, d542667, 6503c09, b1cc4a7]:

    • @tanstack/db@0.5.17

@tanstack/offline-transactions@1.0.7

Patch Changes

  • Fix race condition that caused double replay of offline transactions on page load. The issue occurred when WebLocksLeader's async lock acquisition triggered the leadership callback after requestLeadership() had already returned, causing loadAndReplayTransactions() to be called twice. (#1046)

  • Updated dependencies [f795a67, d542667, 6503c09, b1cc4a7]:

    • @tanstack/db@0.5.17

@tanstack/powersync-db-collection@0.1.21

Patch Changes

  • Added support for tracking collection operation metadata in PowerSync CrudEntry operations. (#999)

    // Schema config
    const APP_SCHEMA = new Schema({
      documents: new Table(
        {
          name: column.text,
    
          created_at: column.text,
        },
        {
          // Metadata tracking must be enabled on the PowerSync table
          trackMetadata: true,
        },
      ),
    })
    
    // ... Other config
    
    // Collection operations which specify metadata
    await collection.insert(
      {
        id,
        name: `document`,
      },
      // The string version of this will be present in PowerSync `CrudEntry`s during uploads
      {
        metadata: {
          extraInfo: 'Info',
        },
      },
    )
  • Updated dependencies [f795a67, d542667, 6503c09, b1cc4a7]:

    • @tanstack/db@0.5.17

@tanstack/query-db-collection@1.0.13

Patch Changes

@tanstack/react-db@0.1.61

Patch Changes

  • Improve runtime error message and documentation when useLiveSuspenseQuery receives undefined from query callback. (#860)

    Following TanStack Query's useSuspenseQuery design, useLiveSuspenseQuery intentionally does not support disabled queries (when callback returns undefined or null). This maintains the type guarantee that data is always T (not T | undefined), which is a core benefit of using Suspense.

    What changed:

    1. Improved runtime error message with clear guidance:

      useLiveSuspenseQuery does not support disabled queries (callback returned undefined/null).
      The Suspense pattern requires data to always be defined (T, not T | undefined).
      Solutions:

      1. Use conditional rendering - don't render the component until the condition is met.
      2. Use useLiveQuery instead, which supports disabled queries with the 'isEnabled' flag.
    2. Enhanced JSDoc documentation with detailed @remarks section explaining the design decision, showing both incorrect (❌) and correct (✅) patterns

    Why this matters:

    // ❌ This pattern doesn't work with Suspense queries:
    const { data } = useLiveSuspenseQuery(
      (q) => userId
        ? q.from({ users }).where(({ users }) => eq(users.id, userId)).findOne()
        : undefined,
      [userId]
    )
    
    // ✅ Instead, use conditional rendering:
    function UserProfile({ userId }: { userId: string }) {
      const { data } = useLiveSuspenseQuery(
        (q) => q.from({ users }).where(({ users }) => eq(users.id, userId)).findOne(),
        [userId]
      )
      return <div>{data.name}</div> // data is guaranteed non-undefined
    }
    
    function App({ userId }: { userId?: string }) {
      if (!userId) return <div>No user selected</div>
      return <UserProfile userId={userId} />
    }
    
    // ✅ Or use useLiveQuery for conditional queries:
    const { data, isEnabled } = useLiveQuery(
      (q) => userId
        ? q.from({ users }).where(({ users }) => eq(users.id, userId)).findOne()
        : undefined,
      [userId]
    )

    This aligns with TanStack Query's philosophy where Suspense queries prioritize type safety and proper component composition over flexibility.

  • Updated dependencies [f795a67, d542667, 6503c09, b1cc4a7]:

    • @tanstack/db@0.5.17

@tanstack/rxdb-db-collection@0.1.49

Patch Changes

@tanstack/solid-db@0.1.60

Patch Changes

@tanstack/svelte-db@0.1.60

Patch Changes

  • Add findOne() / SingleResult support to useLiveQuery hook. (#1001)

    When using .findOne() in a query, the data property is now correctly typed as T | undefined instead of Array<T>, matching the React implementation.

    Example:

    const query = useLiveQuery((q) =>
      q
        .from({ users: usersCollection })
        .where(({ users }) => eq(users.id, userId))
        .findOne(),
    )
    
    // query.data is now typed as User | undefined (not User[])

    This works with all query patterns:

    • Query functions: useLiveQuery((q) => q.from(...).findOne())
    • Config objects: useLiveQuery({ query: (q) => q.from(...).findOne() })
    • Pre-created collections with SingleResult
  • Updated dependencies [f795a67, d542667, 6503c09, b1cc4a7]:

    • @tanstack/db@0.5.17

@tanstack/trailbase-db-collection@0.1.61

Patch Changes

@tanstack/vue-db@0.0.93

Patch Changes

@github-actions github-actions bot force-pushed the changeset-release/main branch 5 times, most recently from a234611 to 3a20f75 Compare January 6, 2026 16:47
@github-actions github-actions bot force-pushed the changeset-release/main branch 2 times, most recently from b9ff26d to 0fd874f Compare January 7, 2026 15:58
@github-actions github-actions bot force-pushed the changeset-release/main branch from 0fd874f to 580d0af Compare January 7, 2026 16:46
@KyleAMathews KyleAMathews merged commit 9dba727 into main Jan 7, 2026
@KyleAMathews KyleAMathews deleted the changeset-release/main branch January 7, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants