Skip to content

Commit 766af9c

Browse files
committed
wip devtools - squashed
1 parent bbed2f2 commit 766af9c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+5953
-41
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ out
9090
# Nuxt.js build / generate output
9191
.nuxt
9292
dist
93+
build
9394

9495
# Gatsby files
9596
.cache/

eslint.config.mjs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ import { tanstackConfig } from "@tanstack/config/eslint"
55

66
export default [
77
...tanstackConfig,
8-
{ ignores: [`dist/`] },
8+
{
9+
ignores: [
10+
`**/dist/**`,
11+
`**/.output/**`,
12+
`**/.nitro/**`,
13+
`**/traildepot/**`,
14+
],
15+
},
916
{
1017
plugins: {
1118
stylistic: stylisticPlugin,

examples/react/todo/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,27 @@
33
"private": true,
44
"version": "0.1.1",
55
"dependencies": {
6+
"@tanstack/db-devtools": "workspace:*",
67
"@tanstack/electric-db-collection": "^0.1.0",
78
"@tanstack/query-core": "^5.75.7",
89
"@tanstack/query-db-collection": "^0.2.0",
910
"@tanstack/react-db": "^0.1.0",
11+
"@tanstack/react-db-devtools": "workspace:*",
1012
"@tanstack/react-router": "^1.125.6",
13+
"@tanstack/react-router-devtools": "^1.130.2",
1114
"@tanstack/react-start": "^1.126.1",
1215
"@tanstack/trailbase-db-collection": "^0.1.0",
1316
"cors": "^2.8.5",
1417
"drizzle-orm": "^0.40.1",
15-
"drizzle-zod": "^0.7.0",
18+
"drizzle-zod": "^0.8.3",
1619
"express": "^4.19.2",
1720
"postgres": "^3.4.7",
1821
"react": "^19.1.0",
1922
"react-dom": "^19.1.0",
2023
"tailwindcss": "^4.1.11",
2124
"trailbase": "^0.7.1",
22-
"vite-tsconfig-paths": "^5.1.4"
25+
"vite-tsconfig-paths": "^5.1.4",
26+
"zod": "^4.0.17"
2327
},
2428
"devDependencies": {
2529
"@eslint/js": "^9.22.0",

examples/react/todo/src/db/validation.ts

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,24 @@
11
import { createInsertSchema, createSelectSchema } from "drizzle-zod"
2-
import { z } from "zod"
32
import { config, todos } from "./schema"
3+
import type { z } from "zod"
44

5-
// Date transformation schema - handles Date objects, ISO strings, and parseable date strings
6-
const dateStringToDate = z
7-
.union([
8-
z.date(), // Already a Date object
9-
z
10-
.string()
11-
.datetime()
12-
.transform((str) => new Date(str)), // ISO datetime string
13-
z.string().transform((str) => new Date(str)), // Any parseable date string
14-
])
15-
.optional()
16-
17-
// Auto-generated schemas from Drizzle schema with date transformation
18-
export const insertTodoSchema = createInsertSchema(todos, {
19-
created_at: dateStringToDate,
20-
updated_at: dateStringToDate,
5+
// Auto-generated schemas from Drizzle schema (omit auto-generated fields)
6+
export const insertTodoSchema = createInsertSchema(todos).omit({
7+
id: true,
8+
created_at: true,
9+
updated_at: true,
2110
})
2211
export const selectTodoSchema = createSelectSchema(todos)
2312

2413
// Partial schema for updates
2514
export const updateTodoSchema = insertTodoSchema.partial().strict()
2615

27-
// Config schemas with date transformation
28-
export const insertConfigSchema = createInsertSchema(config, {
29-
created_at: dateStringToDate,
30-
updated_at: dateStringToDate,
31-
}).strict()
16+
// Config schemas (omit auto-generated fields)
17+
export const insertConfigSchema = createInsertSchema(config).omit({
18+
id: true,
19+
created_at: true,
20+
updated_at: true,
21+
})
3222
export const selectConfigSchema = createSelectSchema(config)
3323
export const updateConfigSchema = insertConfigSchema.partial().strict()
3424

examples/react/todo/src/lib/collections.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createCollection } from "@tanstack/react-db"
2+
import { initializeDbDevtools } from "@tanstack/react-db-devtools"
23
import { electricCollectionOptions } from "@tanstack/electric-db-collection"
34
import { queryCollectionOptions } from "@tanstack/query-db-collection"
45
import { trailBaseCollectionOptions } from "@tanstack/trailbase-db-collection"
@@ -11,13 +12,16 @@ import type { SelectConfig, SelectTodo } from "../db/validation"
1112
// Create a query client for query collections
1213
const queryClient = new QueryClient()
1314

15+
// Initialize DB devtools early (idempotent - safe to call multiple times)
16+
initializeDbDevtools()
17+
1418
// Create a TrailBase client.
1519
const trailBaseClient = initClient(`http://localhost:4000`)
1620

1721
// Electric Todo Collection
1822
export const electricTodoCollection = createCollection(
1923
electricCollectionOptions({
20-
id: `todos`,
24+
id: `electric-todos`,
2125
shapeOptions: {
2226
url: `http://localhost:3003/v1/shape`,
2327
params: {
@@ -43,6 +47,9 @@ export const electricTodoCollection = createCollection(
4347
const txids = await Promise.all(
4448
transaction.mutations.map(async (mutation) => {
4549
const { original, changes } = mutation
50+
if (!(`id` in original)) {
51+
throw new Error(`Original todo not found for update`)
52+
}
4653
const response = await api.todos.update(original.id, changes)
4754
return response.txid
4855
})
@@ -53,6 +60,9 @@ export const electricTodoCollection = createCollection(
5360
const txids = await Promise.all(
5461
transaction.mutations.map(async (mutation) => {
5562
const { original } = mutation
63+
if (!(`id` in original)) {
64+
throw new Error(`Original todo not found for delete`)
65+
}
5666
const response = await api.todos.delete(original.id)
5767
return response.txid
5868
})
@@ -65,7 +75,7 @@ export const electricTodoCollection = createCollection(
6575
// Query Todo Collection
6676
export const queryTodoCollection = createCollection(
6777
queryCollectionOptions({
68-
id: `todos`,
78+
id: `query-todos`,
6979
queryKey: [`todos`],
7080
refetchInterval: 3000,
7181
queryFn: async () => {
@@ -92,6 +102,9 @@ export const queryTodoCollection = createCollection(
92102
return await Promise.all(
93103
transaction.mutations.map(async (mutation) => {
94104
const { original, changes } = mutation
105+
if (!(`id` in original)) {
106+
throw new Error(`Original todo not found for update`)
107+
}
95108
return await api.todos.update(original.id, changes)
96109
})
97110
)
@@ -100,6 +113,9 @@ export const queryTodoCollection = createCollection(
100113
return await Promise.all(
101114
transaction.mutations.map(async (mutation) => {
102115
const { original } = mutation
116+
if (!(`id` in original)) {
117+
throw new Error(`Original todo not found for delete`)
118+
}
103119
await api.todos.delete(original.id)
104120
})
105121
)
@@ -118,7 +134,7 @@ type Todo = {
118134
// TrailBase Todo Collection
119135
export const trailBaseTodoCollection = createCollection(
120136
trailBaseCollectionOptions<SelectTodo, Todo>({
121-
id: `todos`,
137+
id: `trailbase-todos`,
122138
getKey: (item) => item.id,
123139
schema: selectTodoSchema,
124140
recordApi: trailBaseClient.records(`todos`),
@@ -137,7 +153,7 @@ export const trailBaseTodoCollection = createCollection(
137153
// Electric Config Collection
138154
export const electricConfigCollection = createCollection(
139155
electricCollectionOptions({
140-
id: `config`,
156+
id: `electric-config`,
141157
shapeOptions: {
142158
url: `http://localhost:3003/v1/shape`,
143159
params: {
@@ -158,6 +174,9 @@ export const electricConfigCollection = createCollection(
158174
const txids = await Promise.all(
159175
transaction.mutations.map(async (mutation) => {
160176
const { original, changes } = mutation
177+
if (!(`id` in original)) {
178+
throw new Error(`Original config not found for update`)
179+
}
161180
const response = await api.config.update(original.id, changes)
162181
return response.txid
163182
})
@@ -170,7 +189,7 @@ export const electricConfigCollection = createCollection(
170189
// Query Config Collection
171190
export const queryConfigCollection = createCollection(
172191
queryCollectionOptions({
173-
id: `config`,
192+
id: `query-config`,
174193
queryKey: [`config`],
175194
refetchInterval: 3000,
176195
queryFn: async () => {
@@ -193,6 +212,9 @@ export const queryConfigCollection = createCollection(
193212
const txids = await Promise.all(
194213
transaction.mutations.map(async (mutation) => {
195214
const { original, changes } = mutation
215+
if (!(`id` in original)) {
216+
throw new Error(`Original config not found for update`)
217+
}
196218
const response = await api.config.update(original.id, changes)
197219
return response.txid
198220
})
@@ -213,7 +235,7 @@ type Config = {
213235
// TrailBase Config Collection
214236
export const trailBaseConfigCollection = createCollection(
215237
trailBaseCollectionOptions<SelectConfig, Config>({
216-
id: `config`,
238+
id: `trailbase-config`,
217239
getKey: (item) => item.id,
218240
schema: selectConfigSchema,
219241
recordApi: trailBaseClient.records(`config`),

examples/react/todo/src/routes/__root.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import {
44
Scripts,
55
createRootRoute,
66
} from "@tanstack/react-router"
7+
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
8+
import { TanStackReactDbDevtools } from "@tanstack/react-db-devtools"
79

810
import appCss from "../styles.css?url"
911

@@ -32,6 +34,8 @@ export const Route = createRootRoute({
3234
component: () => (
3335
<RootDocument>
3436
<Outlet />
37+
<TanStackRouterDevtools />
38+
<TanStackReactDbDevtools position="bottom-right" />
3539
</RootDocument>
3640
),
3741
})

examples/react/todo/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"baseUrl": ".",
55
"module": "ES2022",
66
"moduleResolution": "bundler",
7+
"jsx": "react-jsx",
78
"paths": {
89
"@/*": ["./src/*"]
910
}

0 commit comments

Comments
 (0)