Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/add-playbook-skills.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@tanstack/db': patch
'@tanstack/react-db': patch
'@tanstack/vue-db': patch
'@tanstack/svelte-db': patch
'@tanstack/solid-db': patch
'@tanstack/angular-db': patch
---

Add playbook SKILL.md files for AI coding agents. Core skills (collection setup, live queries, mutations, sync) ship with @tanstack/db. Framework-specific skills ship with each adapter package. Covers 33 validated failure modes across 10 skill files.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix"
],
"*.md": [
"prettier --write"
]
}
}
3 changes: 2 additions & 1 deletion packages/angular-db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"sideEffects": false,
"files": [
"dist",
"src"
"src",
"skills"
],
"dependencies": {
"@tanstack/db": "workspace:*"
Expand Down
176 changes: 176 additions & 0 deletions packages/angular-db/skills/angular-db/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
---
name: angular-db
description: >
Angular bindings for TanStack DB. Covers injectLiveQuery with Angular
signals. Static queries and reactive params with signal-based parameters.
Return shape (data, state, collection, status, isLoading, isReady,
isError) as Angular Signals. Angular 16.0.0+ compatibility.
type: framework
library: db
framework: angular
library_version: '0.5.29'
requires:
- db-core
---

This skill builds on db-core. Read db-core first for collection setup,
query builder syntax, operators, mutations, and sync concepts.

# TanStack DB — Angular

## Setup

```bash
npm install @tanstack/db @tanstack/angular-db
```

Requires Angular 16.0.0+ (signals).

Collections are created outside components in a dedicated module:

```typescript
// collections/todos.ts
import { createCollection, eq } from '@tanstack/db'
import { queryCollectionOptions } from '@tanstack/query-db-collection'

export const todosCollection = createCollection(
queryCollectionOptions({
queryKey: ['todos'],
queryFn: () => fetch('/api/todos').then((r) => r.json()),
getKey: (todo) => todo.id,
onUpdate: async ({ transaction }) => {
const { original, changes } = transaction.mutations[0]
await fetch(`/api/todos/${original.id}`, {
method: 'PATCH',
body: JSON.stringify(changes),
})
},
}),
)
```

## Hooks and Components

### injectLiveQuery — static query

```typescript
import { Component } from '@angular/core'
import { injectLiveQuery } from '@tanstack/angular-db'
import { eq } from '@tanstack/db'
import { todosCollection } from '../collections/todos'

@Component({
selector: 'app-todo-list',
template: `
@if (query.isLoading()) {
<div>Loading...</div>
} @else if (query.isError()) {
<div>Error loading todos</div>
} @else {
<ul>
@for (todo of query.data(); track todo.id) {
<li (click)="toggle(todo.id)">{{ todo.text }}</li>
}
</ul>
}
`,
})
export class TodoListComponent {
query = injectLiveQuery((q) =>
q.from({ t: todosCollection }).where(({ t }) => eq(t.completed, false)),
)

toggle(id: string) {
todosCollection.update(id, (draft) => {
draft.completed = !draft.completed
})
}
}
```

All return values (`data`, `state`, `collection`, `status`, `isLoading`,
`isReady`, `isIdle`, `isError`, `isCleanedUp`) are Angular Signals.

### injectLiveQuery — reactive parameters with signals

Use the object form with `params` for reactive query parameters:

```typescript
import { Component, signal } from '@angular/core'
import { injectLiveQuery } from '@tanstack/angular-db'
import { eq, gte, and } from '@tanstack/db'

@Component({
selector: 'app-filtered-todos',
template: `
<select (change)="status.set($any($event.target).value)">
<option value="active">Active</option>
<option value="done">Done</option>
</select>

<ul>
@for (todo of query.data(); track todo.id) {
<li>{{ todo.text }}</li>
}
</ul>
`,
})
export class FilteredTodosComponent {
status = signal('active')
minPriority = signal(0)

query = injectLiveQuery({
params: () => ({
status: this.status(),
minPriority: this.minPriority(),
}),
query: ({ params, q }) =>
q
.from({ t: todosCollection })
.where(({ t }) =>
and(eq(t.status, params.status), gte(t.priority, params.minPriority)),
),
})
}
```

The `params` function is a computed signal — the query re-runs whenever
any signal read inside `params` changes.

## Angular-Specific Patterns

### Using with Angular services

Collections can be provided through Angular services for dependency
injection:

```typescript
import { Injectable } from '@angular/core'
import { createCollection } from '@tanstack/db'
import { queryCollectionOptions } from '@tanstack/query-db-collection'

@Injectable({ providedIn: 'root' })
export class TodoService {
readonly collection = createCollection(
queryCollectionOptions({
queryKey: ['todos'],
queryFn: () => fetch('/api/todos').then((r) => r.json()),
getKey: (todo) => todo.id,
}),
)

toggle(id: string) {
this.collection.update(id, (draft) => {
draft.completed = !draft.completed
})
}
}
```

## Common Mistakes

No Angular-specific silent failure modes beyond those covered in db-core.
The Angular adapter's signal-based approach handles reactivity tracking
through the `params` function. See db-core/live-queries and
db-core/mutations-optimistic for common mistakes that apply across all
frameworks.
3 changes: 2 additions & 1 deletion packages/db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"sideEffects": false,
"files": [
"dist",
"src"
"src",
"skills"
],
"dependencies": {
"@standard-schema/spec": "^1.1.0",
Expand Down
58 changes: 58 additions & 0 deletions packages/db/skills/db-core/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
name: db-core
description: >
Reactive client store with normalized collections, sub-millisecond live
queries via differential dataflow, and instant optimistic mutations.
Covers createCollection, query builder (from/where/join/select/groupBy/
orderBy/limit), operators (eq/gt/lt/like/inArray), aggregates (count/sum/
avg/min/max), createTransaction, createOptimisticAction, sync adapters.
Framework-agnostic core for @tanstack/db.
type: core
library: db
library_version: '0.5.29'
source_repository: 'https://github.com/TanStack/db'
---

# TanStack DB — Core Concepts

TanStack DB is a reactive client-side data store that normalizes data into
typed collections, provides sub-millisecond live queries powered by
differential dataflow (d2ts), and gives instant optimistic mutations with
automatic rollback. It connects to any backend through sync adapters
(TanStack Query, ElectricSQL, PowerSync, RxDB, TrailBase) or runs purely
local.

## Sub-Skills

| Need to... | Read |
| ---------------------------------------------------------- | ------------------------------------- |
| Create and configure collections from any data source | db-core/collection-setup/SKILL.md |
| Build reactive queries with filters, joins, aggregations | db-core/live-queries/SKILL.md |
| Write data with optimistic updates and transactions | db-core/mutations-optimistic/SKILL.md |
| Configure sync, offline support, or build a custom adapter | db-core/sync-connectivity/SKILL.md |

## Quick Decision Tree

- Creating a collection or choosing which adapter to use? → db-core/collection-setup
- Querying, filtering, joining, or aggregating collection data? → db-core/live-queries
- Inserting, updating, or deleting items? → db-core/mutations-optimistic
- Configuring sync modes, offline, or building a custom adapter? → db-core/sync-connectivity
- Wiring queries into React components? → react-db/SKILL.md
- Wiring queries into Vue/Svelte/Solid/Angular? → [framework]-db/SKILL.md

## Architecture

Data flows in one direction:

1. **Optimistic state** — mutations apply instantly to the local collection
2. **Persist** — mutation handler sends changes to the backend
3. **Sync** — backend confirms and streams updated state back
4. **Reconcile** — optimistic state is replaced by confirmed server state

Live queries subscribe to collection changes and incrementally recompute
results via d2ts differential dataflow. A single-row update in a sorted
100k-item collection takes ~0.7ms (M1 Pro).

## Version

Targets @tanstack/db v0.5.29.
Loading
Loading