@rippledb/client-query 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,9 +5,11 @@ Final DX package combining:
5
5
  - `@rippledb/client-controllers` (CRUD controllers)
6
6
  - `@rippledb/bind-tanstack-query` (TanStack Query invalidation wiring)
7
7
 
8
- This package is intended to be the ergonomic “one import” for client apps using RippleDB + TanStack Query.
8
+ This package is intended to be the ergonomic “one import” for client apps using
9
+ RippleDB + TanStack Query.
9
10
 
10
- 📚 **Documentation:** [rippledb.dev/docs/reference/client-query](https://rippledb.dev/docs/reference/client-query)
11
+ 📚 **Documentation:**
12
+ [rippledb.dev/docs/reference/client-query](https://rippledb.dev/docs/reference/client-query)
11
13
 
12
14
  ## Installation
13
15
 
@@ -15,19 +17,20 @@ This package is intended to be the ergonomic “one import” for client apps us
15
17
  pnpm add @rippledb/client-query @tanstack/query-core
16
18
  ```
17
19
 
18
- If you use a framework adapter (e.g. `@tanstack/react-query`), you already have `@tanstack/query-core`.
20
+ If you use a framework adapter (e.g. `@tanstack/react-query`), you already have
21
+ `@tanstack/query-core`.
19
22
 
20
23
  ## Usage
21
24
 
22
25
  ```ts
23
- import { QueryClient } from '@tanstack/query-core';
24
- import { MemoryStore } from '@rippledb/store-memory';
25
- import { defineSchema } from '@rippledb/core';
26
- import { createClientQueryApi } from '@rippledb/client-query';
26
+ import { createClientQueryApi } from "@rippledb/client-query";
27
+ import { defineSchema } from "@rippledb/core";
28
+ import { MemoryStore } from "@rippledb/store-memory";
29
+ import { QueryClient } from "@tanstack/query-core";
27
30
 
28
31
  type Schema = {
29
- todos: { id: string; title: string; done: boolean };
30
- users: { id: string; name: string; email: string };
32
+ todos: { id: string; title: string; done: boolean; };
33
+ users: { id: string; name: string; email: string; };
31
34
  };
32
35
 
33
36
  const store = new MemoryStore<Schema>();
@@ -35,44 +38,50 @@ const queryClient = new QueryClient();
35
38
 
36
39
  // Runtime descriptor (entity + field discovery)
37
40
  const schema = defineSchema({
38
- todos: { id: '', title: '', done: false },
39
- users: { id: '', name: '', email: '' },
41
+ todos: { id: "", title: "", done: false },
42
+ users: { id: "", name: "", email: "" },
40
43
  });
41
44
 
42
45
  const api = createClientQueryApi({
43
46
  store,
44
- stream: 'user-123',
47
+ stream: "user-123",
45
48
  queryClient,
46
49
  schema,
47
50
  });
48
51
 
49
52
  // CRUD via dynamic controllers
50
- const todo = await api.todos.create({ title: 'Buy milk', done: false });
53
+ const todo = await api.todos.create({ title: "Buy milk", done: false });
51
54
  await api.todos.update(todo.id, { done: true });
52
55
 
53
56
  // Cached query helper + automatic invalidation
54
57
  const todos = await api.query({
55
- key: ['todos'],
56
- deps: ['todos'],
57
- fn: () => api.todos.list({ entity: 'todos' }),
58
+ key: ["todos"],
59
+ deps: ["todos"],
60
+ fn: () => api.todos.list({ entity: "todos" }),
58
61
  });
59
62
  ```
60
63
 
61
64
  ## Query registry
62
65
 
63
- If you want to register “list queries” up-front (recommended), build a registry and pass it in:
66
+ If you want to register “list queries” up-front (recommended), build a registry
67
+ and pass it in:
64
68
 
65
69
  ```ts
66
- import { defineListRegistry } from '@rippledb/bind-tanstack-query';
70
+ import { defineListRegistry } from "@rippledb/bind-tanstack-query";
67
71
 
68
72
  const registry = defineListRegistry()
69
- .list(['todos'], { deps: ['todos'] })
70
- .list(['dashboard'], { deps: ['todos', 'users'] });
73
+ .list(["todos"], { deps: ["todos"] })
74
+ .list(["dashboard"], { deps: ["todos", "users"] });
71
75
 
72
- const api = createClientQueryApi({ store, stream, queryClient, schema, registry });
76
+ const api = createClientQueryApi({
77
+ store,
78
+ stream,
79
+ queryClient,
80
+ schema,
81
+ registry,
82
+ });
73
83
  ```
74
84
 
75
85
  ## License
76
86
 
77
87
  MIT
78
-
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  // src/index.ts
2
- import { createEntityController } from "@rippledb/client-controllers";
3
- import { wireTanstackInvalidation } from "@rippledb/bind-tanstack-query";
2
+ import {
3
+ wireTanstackInvalidation
4
+ } from "@rippledb/bind-tanstack-query";
5
+ import {
6
+ createEntityController
7
+ } from "@rippledb/client-controllers";
4
8
  function createClientQueryApi(options) {
5
9
  const {
6
10
  store,
@@ -11,7 +15,8 @@ function createClientQueryApi(options) {
11
15
  debounceMs = 50
12
16
  } = options;
13
17
  const controllers = {};
14
- for (const entity of schema.entities) {
18
+ for (const entityName of schema.entities) {
19
+ const entity = entityName;
15
20
  controllers[entity] = createEntityController({
16
21
  store,
17
22
  entity,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Store } from '@rippledb/client';\nimport type { RippleSchema, EntityName, SchemaDescriptor } from '@rippledb/core';\nimport type { QueryClient } from '@tanstack/query-core';\nimport { createEntityController, type EntityController } from '@rippledb/client-controllers';\nimport { wireTanstackInvalidation, type ListRegistry } from '@rippledb/bind-tanstack-query';\n\n/**\n * Query helper options for registering list queries with automatic invalidation.\n */\nexport type QueryOptions<\n S extends RippleSchema = RippleSchema,\n T = unknown,\n> = {\n /**\n * The query key prefix to invalidate (e.g. ['todos'], ['todoList']).\n */\n key: readonly unknown[];\n /**\n * Entity names this query depends on.\n * When a DbEvent for any of these entities fires, the query is invalidated.\n */\n deps: readonly EntityName<S>[];\n /**\n * The query function to execute.\n */\n fn: () => Promise<T>;\n};\n\n/**\n * Client Query API that combines controllers with TanStack Query invalidation.\n * \n * Provides:\n * - Dynamic entity controllers (api.todos, api.users, etc.)\n * - Automatic cache invalidation\n * - Query helpers with dependency tracking\n * \n * @example\n * ```ts\n * const api = createClientQueryApi({\n * store,\n * stream: 'user-123',\n * queryClient,\n * schema: schemaDescriptor,\n * });\n * \n * // CRUD operations\n * const todo = await api.todos.create({ title: 'Buy milk' });\n * const fetched = await api.todos.read('todo-1');\n * \n * // Query helpers with automatic invalidation\n * const todos = await api.query({\n * key: ['todos'],\n * deps: ['todos'],\n * fn: () => api.todos.list({ entity: 'todos' }),\n * });\n * ```\n */\nexport type ClientQueryApi<\n S extends RippleSchema = RippleSchema,\n ListQuery = unknown,\n> = {\n /**\n * Entity controllers, dynamically created from schema.entities.\n * Each entity gets a controller with CRUD operations.\n */\n [K in EntityName<S>]: EntityController<S, K, ListQuery>;\n} & {\n /**\n * Query helper that registers a query with automatic invalidation.\n * \n * @param options - Query options with key, deps, and fn\n * @returns The result of the query function\n */\n query<T>(options: QueryOptions<S, T>): Promise<T>;\n \n /**\n * Cleanup function to unsubscribe from invalidation events.\n */\n cleanup(): void;\n};\n\nexport type CreateClientQueryApiOptions<\n S extends RippleSchema = RippleSchema,\n ListQuery = unknown,\n> = {\n /**\n * The Store instance to operate on.\n */\n store: Store<S, ListQuery>;\n \n /**\n * The stream ID for all changes created by controllers.\n */\n stream: string;\n \n /**\n * TanStack QueryClient instance.\n */\n queryClient: QueryClient;\n \n /**\n * Schema descriptor for runtime entity discovery.\n */\n schema: SchemaDescriptor<S>;\n \n /**\n * Optional list registry for custom query key mappings.\n * If not provided, a default registry is created from query() calls.\n */\n registry?: ListRegistry;\n \n /**\n * Debounce time in milliseconds for invalidation coalescing.\n * @default 50\n */\n debounceMs?: number;\n};\n\n/**\n * Creates a Client Query API that combines controllers with TanStack Query invalidation.\n * \n * The API dynamically creates entity controllers from the schema descriptor,\n * allowing you to use `api.todos`, `api.users`, etc. without manually creating\n * controllers for each entity.\n * \n * @example\n * ```ts\n * import { defineSchema } from '@rippledb/core';\n * import { createClientQueryApi } from '@rippledb/client-query';\n * \n * const schema = defineSchema({\n * todos: { id: '', title: '', done: false },\n * users: { id: '', name: '', email: '' },\n * });\n * \n * const api = createClientQueryApi({\n * store,\n * stream: 'user-123',\n * queryClient,\n * schema,\n * });\n * \n * // Use dynamic controllers\n * const todo = await api.todos.create({ title: 'Buy milk' });\n * const user = await api.users.read('user-1');\n * ```\n */\nexport function createClientQueryApi<\n S extends RippleSchema = RippleSchema,\n ListQuery = unknown,\n>(options: CreateClientQueryApiOptions<S, ListQuery>): ClientQueryApi<S, ListQuery> {\n const {\n store,\n stream,\n queryClient,\n schema,\n registry: providedRegistry,\n debounceMs = 50,\n } = options;\n\n // Create controllers for each entity dynamically\n const controllers = {} as Record<EntityName<S>, EntityController<S, EntityName<S>, ListQuery>>;\n \n for (const entity of schema.entities) {\n controllers[entity] = createEntityController({\n store,\n entity,\n stream,\n });\n }\n\n // If the caller doesn't provide a registry, we create a new mutable registry.\n // If a registry *is* provided, it is expected to be mutable and `api.query()`\n // will add entries to it dynamically (so invalidation works automatically).\n const registry: ListRegistry = providedRegistry ?? { entries: [] };\n\n // Wire up invalidation once\n const cleanup = wireTanstackInvalidation({\n queryClient,\n store,\n registry,\n debounceMs,\n });\n\n const registerQueryIfNeeded = (opts: QueryOptions<S, unknown>) => {\n // Avoid duplicate registrations for identical query keys (shallow compare)\n const exists = registry.entries.some((e) => {\n if (e.queryKey.length !== opts.key.length) return false;\n for (let i = 0; i < e.queryKey.length; i += 1) {\n if (!Object.is(e.queryKey[i], opts.key[i])) return false;\n }\n return true;\n });\n if (!exists) {\n registry.entries.push({\n queryKey: opts.key,\n deps: opts.deps as readonly string[],\n });\n }\n };\n\n // Create the API object with dynamic entity controllers\n const api = {\n ...controllers,\n \n async query<T>(queryOptions: QueryOptions<S, T>): Promise<T> {\n registerQueryIfNeeded(queryOptions);\n\n // Use TanStack Query for caching + consistent invalidation\n return await queryClient.fetchQuery({\n // TanStack queryKey expects readonly unknown[]; our key matches.\n queryKey: queryOptions.key,\n queryFn: async () => queryOptions.fn(),\n });\n },\n \n cleanup,\n } as ClientQueryApi<S, ListQuery>;\n\n return api;\n}\n\n// Re-export types for convenience\nexport type { EntityController } from '@rippledb/client-controllers';\nexport type { ListRegistry } from '@rippledb/bind-tanstack-query';\n"],"mappings":";AAGA,SAAS,8BAAqD;AAC9D,SAAS,gCAAmD;AA+IrD,SAAS,qBAGd,SAAkF;AAClF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,aAAa;AAAA,EACf,IAAI;AAGJ,QAAM,cAAc,CAAC;AAErB,aAAW,UAAU,OAAO,UAAU;AACpC,gBAAY,MAAM,IAAI,uBAAuB;AAAA,MAC3C;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAKA,QAAM,WAAyB,oBAAoB,EAAE,SAAS,CAAC,EAAE;AAGjE,QAAM,UAAU,yBAAyB;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,wBAAwB,CAAC,SAAmC;AAEhE,UAAM,SAAS,SAAS,QAAQ,KAAK,CAAC,MAAM;AAC1C,UAAI,EAAE,SAAS,WAAW,KAAK,IAAI,OAAQ,QAAO;AAClD,eAAS,IAAI,GAAG,IAAI,EAAE,SAAS,QAAQ,KAAK,GAAG;AAC7C,YAAI,CAAC,OAAO,GAAG,EAAE,SAAS,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,EAAG,QAAO;AAAA,MACrD;AACA,aAAO;AAAA,IACT,CAAC;AACD,QAAI,CAAC,QAAQ;AACX,eAAS,QAAQ,KAAK;AAAA,QACpB,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,MAAM;AAAA,IACV,GAAG;AAAA,IAEH,MAAM,MAAS,cAA8C;AAC3D,4BAAsB,YAAY;AAGlC,aAAO,MAAM,YAAY,WAAW;AAAA;AAAA,QAElC,UAAU,aAAa;AAAA,QACvB,SAAS,YAAY,aAAa,GAAG;AAAA,MACvC,CAAC;AAAA,IACH;AAAA,IAEA;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n type ListRegistry,\n wireTanstackInvalidation,\n} from \"@rippledb/bind-tanstack-query\";\nimport type { Store } from \"@rippledb/client\";\nimport {\n createEntityController,\n type EntityController,\n} from \"@rippledb/client-controllers\";\nimport type {\n DescriptorSchema,\n EntityName,\n InferSchema,\n RippleSchema,\n SchemaDescriptor,\n} from \"@rippledb/core\";\nimport type { QueryClient } from \"@tanstack/query-core\";\n\n/**\n * Query helper options for registering list queries with automatic invalidation.\n */\nexport type QueryOptions<S extends RippleSchema = RippleSchema, T = unknown> = {\n /**\n * The query key prefix to invalidate (e.g. ['todos'], ['todoList']).\n */\n key: readonly unknown[];\n /**\n * Entity names this query depends on.\n * When a DbEvent for any of these entities fires, the query is invalidated.\n */\n deps: readonly EntityName<S>[];\n /**\n * The query function to execute.\n */\n fn: () => Promise<T>;\n};\n\n/**\n * Client Query API that combines controllers with TanStack Query invalidation.\n *\n * Provides:\n * - Dynamic entity controllers (api.todos, api.users, etc.)\n * - Automatic cache invalidation\n * - Query helpers with dependency tracking\n *\n * @example\n * ```ts\n * const api = createClientQueryApi({\n * store,\n * stream: 'user-123',\n * queryClient,\n * schema: schemaDescriptor,\n * });\n *\n * // CRUD operations\n * const todo = await api.todos.create({ title: 'Buy milk' });\n * const fetched = await api.todos.read('todo-1');\n *\n * // Query helpers with automatic invalidation\n * const todos = await api.query({\n * key: ['todos'],\n * deps: ['todos'],\n * fn: () => api.todos.list({ entity: 'todos' }),\n * });\n * ```\n */\n/**\n * Client Query API that combines controllers with TanStack Query invalidation.\n * Optimized: single type definition instead of intersection for better performance.\n */\nexport type ClientQueryApi<\n S extends RippleSchema = RippleSchema,\n ListQuery = unknown,\n> =\n & {\n /**\n * Entity controllers, dynamically created from schema.entities.\n * Each entity gets a controller with CRUD operations.\n */\n [K in EntityName<S>]: EntityController<S, K, ListQuery>;\n }\n & {\n /**\n * Query helper that registers a query with automatic invalidation.\n *\n * @param options - Query options with key, deps, and fn\n * @returns The result of the query function\n */\n query<T>(options: QueryOptions<S, T>): Promise<T>;\n\n /**\n * Cleanup function to unsubscribe from invalidation events.\n */\n cleanup(): void;\n };\n\nexport type CreateClientQueryApiOptions<\n D extends DescriptorSchema = DescriptorSchema,\n ListQuery = unknown,\n> = {\n /**\n * The Store instance to operate on.\n * Must be typed with the inferred schema type.\n */\n store: Store<InferSchema<SchemaDescriptor<D>>, ListQuery>;\n\n /**\n * The stream ID for all changes created by controllers.\n */\n stream: string;\n\n /**\n * TanStack QueryClient instance.\n */\n queryClient: QueryClient;\n\n /**\n * Schema descriptor for runtime entity discovery.\n */\n schema: SchemaDescriptor<D>;\n\n /**\n * Optional list registry for custom query key mappings.\n * If not provided, a default registry is created from query() calls.\n */\n registry?: ListRegistry;\n\n /**\n * Debounce time in milliseconds for invalidation coalescing.\n * @default 50\n */\n debounceMs?: number;\n};\n\n/**\n * Creates a Client Query API that combines controllers with TanStack Query invalidation.\n *\n * The API dynamically creates entity controllers from the schema descriptor,\n * allowing you to use `api.todos`, `api.users`, etc. without manually creating\n * controllers for each entity.\n *\n * @example\n * ```ts\n * import { defineSchema, s, InferSchema } from '@rippledb/core';\n * import { createClientQueryApi } from '@rippledb/client-query';\n *\n * const schema = defineSchema({\n * todos: {\n * id: s.string(),\n * title: s.string(),\n * done: s.boolean(),\n * },\n * users: {\n * id: s.string(),\n * name: s.string(),\n * email: s.string(),\n * },\n * });\n *\n * type MySchema = InferSchema<typeof schema>;\n * const store = new MemoryStore<MySchema>();\n *\n * const api = createClientQueryApi({\n * store,\n * stream: 'user-123',\n * queryClient,\n * schema,\n * });\n *\n * // Use dynamic controllers\n * const todo = await api.todos.create({ title: 'Buy milk' });\n * const user = await api.users.read('user-1');\n * ```\n */\nexport function createClientQueryApi<\n D extends DescriptorSchema,\n ListQuery = unknown,\n>(\n options: CreateClientQueryApiOptions<D, ListQuery>,\n): ClientQueryApi<InferSchema<SchemaDescriptor<D>>, ListQuery> {\n type S = InferSchema<SchemaDescriptor<D>>;\n\n const {\n store,\n stream,\n queryClient,\n schema,\n registry: providedRegistry,\n debounceMs = 50,\n } = options;\n\n // Create controllers for each entity dynamically\n const controllers = {} as Record<\n EntityName<S>,\n EntityController<S, EntityName<S>, ListQuery>\n >;\n\n for (const entityName of schema.entities) {\n // Cast entity name to the correct type\n const entity = entityName as EntityName<S>;\n controllers[entity] = createEntityController({\n store,\n entity,\n stream,\n });\n }\n\n // If the caller doesn't provide a registry, we create a new mutable registry.\n // If a registry *is* provided, it is expected to be mutable and `api.query()`\n // will add entries to it dynamically (so invalidation works automatically).\n const registry: ListRegistry = providedRegistry ?? { entries: [] };\n\n // Wire up invalidation once\n const cleanup = wireTanstackInvalidation({\n queryClient,\n store,\n registry,\n debounceMs,\n });\n\n const registerQueryIfNeeded = (opts: QueryOptions<S, unknown>) => {\n // Avoid duplicate registrations for identical query keys (shallow compare)\n const exists = registry.entries.some(e => {\n if (e.queryKey.length !== opts.key.length) return false;\n for (let i = 0; i < e.queryKey.length; i += 1) {\n if (!Object.is(e.queryKey[i], opts.key[i])) return false;\n }\n return true;\n });\n if (!exists) {\n registry.entries.push({\n queryKey: opts.key,\n deps: opts.deps as readonly string[],\n });\n }\n };\n\n // Create the API object with dynamic entity controllers\n const api = {\n ...controllers,\n\n async query<T>(queryOptions: QueryOptions<S, T>): Promise<T> {\n registerQueryIfNeeded(queryOptions);\n\n // Use TanStack Query for caching + consistent invalidation\n return await queryClient.fetchQuery({\n // TanStack queryKey expects readonly unknown[]; our key matches.\n queryKey: queryOptions.key,\n queryFn: async () => queryOptions.fn(),\n });\n },\n\n cleanup,\n } as ClientQueryApi<S, ListQuery>;\n\n return api;\n}\n\n// Re-export types for convenience\nexport type { ListRegistry } from \"@rippledb/bind-tanstack-query\";\nexport type { EntityController } from \"@rippledb/client-controllers\";\n"],"mappings":";AAAA;AAAA,EAEE;AAAA,OACK;AAEP;AAAA,EACE;AAAA,OAEK;AAsKA,SAAS,qBAId,SAC6D;AAG7D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,aAAa;AAAA,EACf,IAAI;AAGJ,QAAM,cAAc,CAAC;AAKrB,aAAW,cAAc,OAAO,UAAU;AAExC,UAAM,SAAS;AACf,gBAAY,MAAM,IAAI,uBAAuB;AAAA,MAC3C;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAKA,QAAM,WAAyB,oBAAoB,EAAE,SAAS,CAAC,EAAE;AAGjE,QAAM,UAAU,yBAAyB;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,wBAAwB,CAAC,SAAmC;AAEhE,UAAM,SAAS,SAAS,QAAQ,KAAK,OAAK;AACxC,UAAI,EAAE,SAAS,WAAW,KAAK,IAAI,OAAQ,QAAO;AAClD,eAAS,IAAI,GAAG,IAAI,EAAE,SAAS,QAAQ,KAAK,GAAG;AAC7C,YAAI,CAAC,OAAO,GAAG,EAAE,SAAS,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,EAAG,QAAO;AAAA,MACrD;AACA,aAAO;AAAA,IACT,CAAC;AACD,QAAI,CAAC,QAAQ;AACX,eAAS,QAAQ,KAAK;AAAA,QACpB,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,MAAM;AAAA,IACV,GAAG;AAAA,IAEH,MAAM,MAAS,cAA8C;AAC3D,4BAAsB,YAAY;AAGlC,aAAO,MAAM,YAAY,WAAW;AAAA;AAAA,QAElC,UAAU,aAAa;AAAA,QACvB,SAAS,YAAY,aAAa,GAAG;AAAA,MACvC,CAAC;AAAA,IACH;AAAA,IAEA;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rippledb/client-query",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -29,10 +29,10 @@
29
29
  "dist"
30
30
  ],
31
31
  "dependencies": {
32
- "@rippledb/core": "0.1.1",
33
- "@rippledb/client": "0.1.1",
34
- "@rippledb/client-controllers": "0.1.0",
35
- "@rippledb/bind-tanstack-query": "0.1.1"
32
+ "@rippledb/client-controllers": "0.1.2",
33
+ "@rippledb/client": "0.1.3",
34
+ "@rippledb/core": "0.3.0",
35
+ "@rippledb/bind-tanstack-query": "0.1.3"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@tanstack/query-core": "^5.0.0"
@@ -43,7 +43,7 @@
43
43
  "tsup": "^8.5.0",
44
44
  "typescript": "^5.9.3",
45
45
  "vitest": "^3.2.4",
46
- "@rippledb/store-memory": "0.1.1"
46
+ "@rippledb/store-memory": "0.1.3"
47
47
  },
48
48
  "tsup": {
49
49
  "entry": [