query-optimistic 0.1.1 → 0.3.0
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 +9 -9
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +30 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +30 -6
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +30 -9
- package/dist/react/index.d.ts +30 -9
- package/dist/react/index.js +30 -6
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +30 -6
- package/dist/react/index.mjs.map +1 -1
- package/dist/{types-BRxQA1mR.d.mts → types-BOq5W_Qm.d.mts} +1 -1
- package/dist/{types-BRxQA1mR.d.ts → types-BOq5W_Qm.d.ts} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ useMutation({
|
|
|
53
53
|
// After: query-optimistic
|
|
54
54
|
useMutation(createTodo, {
|
|
55
55
|
optimistic: (channel, todo) => {
|
|
56
|
-
channel(todosCollection).append(todo, {
|
|
56
|
+
channel(todosCollection).append(todo, { reconcile: true })
|
|
57
57
|
}
|
|
58
58
|
})
|
|
59
59
|
```
|
|
@@ -117,7 +117,7 @@ function TodoApp() {
|
|
|
117
117
|
id: `temp-${Date.now()}`,
|
|
118
118
|
title: params.title,
|
|
119
119
|
completed: false,
|
|
120
|
-
}, {
|
|
120
|
+
}, { reconcile: true })
|
|
121
121
|
}
|
|
122
122
|
})
|
|
123
123
|
|
|
@@ -197,7 +197,7 @@ function TodoList() {
|
|
|
197
197
|
title: params.title,
|
|
198
198
|
completed: false,
|
|
199
199
|
createdAt: new Date().toISOString()
|
|
200
|
-
}, {
|
|
200
|
+
}, { reconcile: true })
|
|
201
201
|
}
|
|
202
202
|
})
|
|
203
203
|
|
|
@@ -669,7 +669,7 @@ const { mutate, mutateAsync, isPending, isError, error, data, reset } = useMutat
|
|
|
669
669
|
createUser,
|
|
670
670
|
{
|
|
671
671
|
optimistic: (channel, params) => {
|
|
672
|
-
channel(usersCollection).append(params, {
|
|
672
|
+
channel(usersCollection).append(params, { reconcile: true })
|
|
673
673
|
},
|
|
674
674
|
onSuccess: (data) => console.log('Created:', data),
|
|
675
675
|
onError: (error) => console.error('Failed:', error)
|
|
@@ -698,8 +698,8 @@ optimistic: (channel, params) => {
|
|
|
698
698
|
const ch = channel(usersCollection)
|
|
699
699
|
|
|
700
700
|
// Add items
|
|
701
|
-
ch.prepend(newItem, {
|
|
702
|
-
ch.append(newItem, {
|
|
701
|
+
ch.prepend(newItem, { reconcile: true }) // Add to beginning
|
|
702
|
+
ch.append(newItem, { reconcile: true }) // Add to end
|
|
703
703
|
|
|
704
704
|
// Update by ID
|
|
705
705
|
ch.update(id, item => ({ ...item, name: newName }))
|
|
@@ -732,16 +732,16 @@ optimistic: (channel, params) => {
|
|
|
732
732
|
}
|
|
733
733
|
```
|
|
734
734
|
|
|
735
|
-
####
|
|
735
|
+
#### Reconcile Option
|
|
736
736
|
|
|
737
|
-
Use `{
|
|
737
|
+
Use `{ reconcile: true }` when the server response should replace the optimistic data:
|
|
738
738
|
|
|
739
739
|
```typescript
|
|
740
740
|
// The temp ID will be replaced with the server's real ID
|
|
741
741
|
channel(todosCollection).append({
|
|
742
742
|
id: `temp-${Date.now()}`,
|
|
743
743
|
title: 'New todo'
|
|
744
|
-
}, {
|
|
744
|
+
}, { reconcile: true })
|
|
745
745
|
```
|
|
746
746
|
|
|
747
747
|
---
|
package/dist/core/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as IdGetter, C as CollectionDef, E as EntityDef, M as MutationDef,
|
|
2
|
-
export { A as AnyDef,
|
|
1
|
+
import { I as IdGetter, C as CollectionDef, E as EntityDef, M as MutationDef, O as Optimistic } from '../types-BOq5W_Qm.mjs';
|
|
2
|
+
export { A as AnyDef, a as OptimisticAction, b as OptimisticInstruction, c as OptimisticStatus, P as PaginatedOptions, Q as QueryOptions } from '../types-BOq5W_Qm.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Define a collection query for fetching arrays of items
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as IdGetter, C as CollectionDef, E as EntityDef, M as MutationDef,
|
|
2
|
-
export { A as AnyDef,
|
|
1
|
+
import { I as IdGetter, C as CollectionDef, E as EntityDef, M as MutationDef, O as Optimistic } from '../types-BOq5W_Qm.js';
|
|
2
|
+
export { A as AnyDef, a as OptimisticAction, b as OptimisticInstruction, c as OptimisticStatus, P as PaginatedOptions, Q as QueryOptions } from '../types-BOq5W_Qm.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Define a collection query for fetching arrays of items
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { A as AnyDef, C as CollectionDef, E as EntityDef, I as IdGetter, M as MutationDef,
|
|
1
|
+
export { A as AnyDef, C as CollectionDef, E as EntityDef, I as IdGetter, M as MutationDef, O as Optimistic, a as OptimisticAction, b as OptimisticInstruction, c as OptimisticStatus, P as PaginatedOptions, Q as QueryOptions } from './types-BOq5W_Qm.mjs';
|
|
2
2
|
export { Channel, CollectionChannel, EntityChannel, OptimisticTransaction, RegisteredCollection, RegisteredEntity, RegisteredEntry, RegisteredPaginatedCollection, channel, defineCollection, defineEntity, defineMutation, registry } from './core/index.mjs';
|
|
3
3
|
export { EntityResult, MutationResult, OptimisticConfig, PaginatedQueryResult, PaginationState, QueryResult, QueryState, UseMutationOptions, UseQueryHookOptions, useMutation, useQuery } from './react/index.mjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { A as AnyDef, C as CollectionDef, E as EntityDef, I as IdGetter, M as MutationDef,
|
|
1
|
+
export { A as AnyDef, C as CollectionDef, E as EntityDef, I as IdGetter, M as MutationDef, O as Optimistic, a as OptimisticAction, b as OptimisticInstruction, c as OptimisticStatus, P as PaginatedOptions, Q as QueryOptions } from './types-BOq5W_Qm.js';
|
|
2
2
|
export { Channel, CollectionChannel, EntityChannel, OptimisticTransaction, RegisteredCollection, RegisteredEntity, RegisteredEntry, RegisteredPaginatedCollection, channel, defineCollection, defineEntity, defineMutation, registry } from './core/index.js';
|
|
3
3
|
export { EntityResult, MutationResult, OptimisticConfig, PaginatedQueryResult, PaginationState, QueryResult, QueryState, UseMutationOptions, UseQueryHookOptions, useMutation, useQuery } from './react/index.js';
|
package/dist/index.js
CHANGED
|
@@ -272,8 +272,16 @@ function useQuery(def, options) {
|
|
|
272
272
|
{
|
|
273
273
|
isLoading: query2.isLoading,
|
|
274
274
|
isFetching: query2.isFetching,
|
|
275
|
+
isSuccess: query2.isSuccess,
|
|
275
276
|
isError: query2.isError,
|
|
277
|
+
isPending: query2.isPending,
|
|
278
|
+
status: query2.status,
|
|
276
279
|
error: query2.error,
|
|
280
|
+
dataUpdatedAt: query2.dataUpdatedAt,
|
|
281
|
+
errorUpdatedAt: query2.errorUpdatedAt,
|
|
282
|
+
failureCount: query2.failureCount,
|
|
283
|
+
isStale: query2.isStale,
|
|
284
|
+
isPlaceholderData: query2.isPlaceholderData,
|
|
277
285
|
refetch: query2.refetch
|
|
278
286
|
}
|
|
279
287
|
];
|
|
@@ -319,8 +327,16 @@ function useQuery(def, options) {
|
|
|
319
327
|
{
|
|
320
328
|
isLoading: infiniteQuery.isLoading,
|
|
321
329
|
isFetching: infiniteQuery.isFetching,
|
|
330
|
+
isSuccess: infiniteQuery.isSuccess,
|
|
322
331
|
isError: infiniteQuery.isError,
|
|
332
|
+
isPending: infiniteQuery.isPending,
|
|
333
|
+
status: infiniteQuery.status,
|
|
323
334
|
error: infiniteQuery.error,
|
|
335
|
+
dataUpdatedAt: infiniteQuery.dataUpdatedAt,
|
|
336
|
+
errorUpdatedAt: infiniteQuery.errorUpdatedAt,
|
|
337
|
+
failureCount: infiniteQuery.failureCount,
|
|
338
|
+
isStale: infiniteQuery.isStale,
|
|
339
|
+
isPlaceholderData: infiniteQuery.isPlaceholderData,
|
|
324
340
|
refetch: infiniteQuery.refetch
|
|
325
341
|
},
|
|
326
342
|
{
|
|
@@ -358,8 +374,16 @@ function useQuery(def, options) {
|
|
|
358
374
|
{
|
|
359
375
|
isLoading: query.isLoading,
|
|
360
376
|
isFetching: query.isFetching,
|
|
377
|
+
isSuccess: query.isSuccess,
|
|
361
378
|
isError: query.isError,
|
|
379
|
+
isPending: query.isPending,
|
|
380
|
+
status: query.status,
|
|
362
381
|
error: query.error,
|
|
382
|
+
dataUpdatedAt: query.dataUpdatedAt,
|
|
383
|
+
errorUpdatedAt: query.errorUpdatedAt,
|
|
384
|
+
failureCount: query.failureCount,
|
|
385
|
+
isStale: query.isStale,
|
|
386
|
+
isPlaceholderData: query.isPlaceholderData,
|
|
363
387
|
refetch: query.refetch
|
|
364
388
|
}
|
|
365
389
|
];
|
|
@@ -374,7 +398,7 @@ var BatchedCollectionChannel = class {
|
|
|
374
398
|
target: this.target,
|
|
375
399
|
action: "prepend",
|
|
376
400
|
data,
|
|
377
|
-
|
|
401
|
+
reconcile: options?.reconcile
|
|
378
402
|
});
|
|
379
403
|
return this;
|
|
380
404
|
}
|
|
@@ -383,7 +407,7 @@ var BatchedCollectionChannel = class {
|
|
|
383
407
|
target: this.target,
|
|
384
408
|
action: "append",
|
|
385
409
|
data,
|
|
386
|
-
|
|
410
|
+
reconcile: options?.reconcile
|
|
387
411
|
});
|
|
388
412
|
return this;
|
|
389
413
|
}
|
|
@@ -393,7 +417,7 @@ var BatchedCollectionChannel = class {
|
|
|
393
417
|
action: "update",
|
|
394
418
|
id,
|
|
395
419
|
update: updateFn,
|
|
396
|
-
|
|
420
|
+
reconcile: options?.reconcile
|
|
397
421
|
});
|
|
398
422
|
return this;
|
|
399
423
|
}
|
|
@@ -416,7 +440,7 @@ var BatchedEntityChannel = class {
|
|
|
416
440
|
target: this.target,
|
|
417
441
|
action: "update",
|
|
418
442
|
update: updateFn,
|
|
419
|
-
|
|
443
|
+
reconcile: options?.reconcile
|
|
420
444
|
});
|
|
421
445
|
return this;
|
|
422
446
|
}
|
|
@@ -425,7 +449,7 @@ var BatchedEntityChannel = class {
|
|
|
425
449
|
target: this.target,
|
|
426
450
|
action: "replace",
|
|
427
451
|
data,
|
|
428
|
-
|
|
452
|
+
reconcile: options?.reconcile
|
|
429
453
|
});
|
|
430
454
|
return this;
|
|
431
455
|
}
|
|
@@ -472,7 +496,7 @@ function useMutation(def, options) {
|
|
|
472
496
|
onSuccess: (data, params, context) => {
|
|
473
497
|
if (context?.transactions) {
|
|
474
498
|
for (const tx of context.transactions) {
|
|
475
|
-
if (tx.
|
|
499
|
+
if (tx.reconcile && data) {
|
|
476
500
|
registry.applyUpdate(tx.target.name, "update", {
|
|
477
501
|
where: (item) => item._optimistic?.id === context?.optimisticId,
|
|
478
502
|
update: () => data
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/define.ts","../src/core/registry.ts","../src/core/channel.ts","../src/react/use-query.ts","../src/react/use-mutation.ts"],"names":["nanoid","useQueryClient","useMemo","query","useTanstackQuery","useEffect","useInfiniteQuery","channel","useTanstackMutation"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n CollectionDef,\n EntityDef,\n MutationDef,\n IdGetter,\n} from './types';\n\n/**\n * Define a collection query for fetching arrays of items\n *\n * @example\n * const postsQuery = defineCollection({\n * name: 'posts',\n * id: (post) => post._id,\n * fetch: ({ page }) => api.get(`/posts?page=${page}`).json()\n * })\n */\nexport function defineCollection<TData, TParams = void>(config: {\n name: string;\n id: IdGetter<TData>;\n fetch: (params: TParams) => Promise<TData[]>;\n}): CollectionDef<TData, TParams> {\n return {\n _type: 'collection',\n name: config.name,\n id: config.id,\n fetch: config.fetch,\n };\n}\n\n/**\n * Define an entity for fetching single items\n *\n * @example\n * const userEntity = defineEntity({\n * name: 'user',\n * fetch: (userId) => api.get(`/users/${userId}`).json()\n * })\n */\nexport function defineEntity<TData, TParams = void>(config: {\n name: string;\n fetch: (params: TParams) => Promise<TData>;\n}): EntityDef<TData, TParams> {\n return {\n _type: 'entity',\n name: config.name,\n fetch: config.fetch,\n };\n}\n\n/**\n * Define a mutation for writing data\n *\n * @example\n * const createPost = defineMutation({\n * name: 'createPost',\n * mutate: (data) => api.post('/posts', { json: data }).json()\n * })\n */\nexport function defineMutation<TParams, TResponse = void>(config: {\n name?: string;\n mutate: (params: TParams) => Promise<TResponse>;\n}): MutationDef<TParams, TResponse> {\n return {\n _type: 'mutation',\n name: config.name,\n mutate: config.mutate,\n };\n}\n","import type { CollectionDef, EntityDef, Optimistic } from './types';\n\n/** Registered collection entry */\nexport interface RegisteredCollection<T = any> {\n kind: 'collection';\n name: string;\n queryKey: readonly unknown[];\n def: CollectionDef<T, any>;\n getData: () => T[] | undefined;\n setData: (updater: (prev: T[] | undefined) => T[] | undefined) => void;\n}\n\n/** Registered entity entry */\nexport interface RegisteredEntity<T = any> {\n kind: 'entity';\n name: string;\n queryKey: readonly unknown[];\n def: EntityDef<T, any>;\n getData: () => T | undefined;\n setData: (updater: (prev: T | undefined) => T | undefined) => void;\n}\n\n/** Registered paginated collection entry */\nexport interface RegisteredPaginatedCollection<T = any> {\n kind: 'paginated';\n name: string;\n queryKey: readonly unknown[];\n def: CollectionDef<T, any>;\n getData: () => { pages: T[][]; pageParams: unknown[] } | undefined;\n setData: (\n updater: (\n prev: { pages: T[][]; pageParams: unknown[] } | undefined\n ) => { pages: T[][]; pageParams: unknown[] } | undefined\n ) => void;\n}\n\nexport type RegisteredEntry =\n | RegisteredCollection\n | RegisteredEntity\n | RegisteredPaginatedCollection;\n\n/**\n * Internal registry for tracking active queries\n * Used by optimistic updates to broadcast changes\n */\nclass QueryRegistry {\n private entries = new Map<string, Set<RegisteredEntry>>();\n\n /** Register an active query */\n register(entry: RegisteredEntry): void {\n if (!this.entries.has(entry.name)) {\n this.entries.set(entry.name, new Set());\n }\n this.entries.get(entry.name)!.add(entry);\n }\n\n /** Unregister a query when component unmounts */\n unregister(entry: RegisteredEntry): void {\n const set = this.entries.get(entry.name);\n if (set) {\n set.delete(entry);\n if (set.size === 0) {\n this.entries.delete(entry.name);\n }\n }\n }\n\n /** Get all registered entries for a query name */\n getByName(name: string): RegisteredEntry[] {\n return Array.from(this.entries.get(name) ?? []);\n }\n\n /** Apply an optimistic update to all queries with given name */\n applyUpdate<T>(\n name: string,\n action: 'prepend' | 'append' | 'update' | 'delete' | 'replace',\n payload: {\n data?: Partial<Optimistic<T>>;\n id?: string;\n where?: (item: T) => boolean;\n update?: (item: T) => T;\n }\n ): (() => void)[] {\n const entries = this.getByName(name);\n const rollbacks: (() => void)[] = [];\n\n for (const entry of entries) {\n if (entry.kind === 'collection') {\n const previous = entry.getData();\n const rollback = () => entry.setData(() => previous);\n rollbacks.push(rollback);\n\n entry.setData((prev) => {\n if (!prev) return prev;\n return this.applyCollectionUpdate(prev, action, payload, entry.def.id);\n });\n } else if (entry.kind === 'paginated') {\n const previous = entry.getData();\n const rollback = () => entry.setData(() => previous);\n rollbacks.push(rollback);\n\n entry.setData((prev) => {\n if (!prev) return prev;\n return {\n ...prev,\n pages: prev.pages.map((page, i) =>\n i === 0\n ? this.applyCollectionUpdate(page, action, payload, entry.def.id)\n : page\n ),\n };\n });\n } else if (entry.kind === 'entity') {\n const previous = entry.getData();\n const rollback = () => entry.setData(() => previous);\n rollbacks.push(rollback);\n\n if (action === 'update' && payload.update) {\n entry.setData((prev) => (prev ? payload.update!(prev as T) : prev));\n } else if (action === 'replace' && payload.data) {\n entry.setData(() => payload.data as T);\n }\n }\n }\n\n return rollbacks;\n }\n\n private applyCollectionUpdate<T>(\n items: T[],\n action: string,\n payload: {\n data?: Partial<Optimistic<T>>;\n id?: string;\n where?: (item: T) => boolean;\n update?: (item: T) => T;\n },\n getId: (item: T) => string\n ): T[] {\n switch (action) {\n case 'prepend':\n return payload.data ? [payload.data as T, ...items] : items;\n\n case 'append':\n return payload.data ? [...items, payload.data as T] : items;\n\n case 'update':\n return items.map((item) => {\n const matches = payload.id\n ? getId(item) === payload.id\n : payload.where?.(item);\n if (matches && payload.update) {\n return payload.update(item);\n }\n if (matches && payload.data) {\n return { ...item, ...payload.data };\n }\n return item;\n });\n\n case 'delete':\n return items.filter((item) => {\n if (payload.id) return getId(item) !== payload.id;\n if (payload.where) return !payload.where(item);\n return true;\n });\n\n case 'replace':\n return items.map((item) => {\n const matches = payload.id\n ? getId(item) === payload.id\n : payload.where?.(item);\n return matches && payload.data ? (payload.data as T) : item;\n });\n\n default:\n return items;\n }\n }\n}\n\n/** Singleton registry instance */\nexport const registry = new QueryRegistry();\n","import { nanoid } from 'nanoid';\nimport type { CollectionDef, EntityDef, Optimistic } from './types';\nimport { registry } from './registry';\n\n/** Transaction returned from channel methods */\nexport interface OptimisticTransaction {\n target: CollectionDef<any, any> | EntityDef<any, any>;\n action: 'prepend' | 'append' | 'update' | 'delete' | 'replace';\n data?: any;\n id?: string;\n where?: (item: any) => boolean;\n update?: (item: any) => any;\n sync?: boolean;\n rollback: () => void;\n}\n\n/** Channel for a collection - provides typed optimistic mutation methods */\nexport class CollectionChannel<TEntity> {\n private readonly optimisticId = nanoid();\n\n constructor(private readonly target: CollectionDef<TEntity, any>) {}\n\n /**\n * Prepend an item to the collection\n * @returns Rollback function to undo the change\n */\n prepend(data: TEntity, options?: { sync?: boolean }): () => void {\n const optimisticData = {\n ...data,\n _optimistic: { id: this.optimisticId, status: 'pending' as const },\n };\n\n const rollbacks = registry.applyUpdate(this.target.name, 'prepend', {\n data: optimisticData,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Append an item to the collection\n * @returns Rollback function to undo the change\n */\n append(data: TEntity, options?: { sync?: boolean }): () => void {\n const optimisticData = {\n ...data,\n _optimistic: { id: this.optimisticId, status: 'pending' as const },\n };\n\n const rollbacks = registry.applyUpdate(this.target.name, 'append', {\n data: optimisticData,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Update an item in the collection by ID\n * @returns Rollback function to undo the change\n */\n update(\n id: string,\n updateFn: (item: TEntity) => TEntity,\n options?: { sync?: boolean }\n ): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'update', {\n id,\n update: updateFn,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Update items matching a predicate\n * @returns Rollback function to undo the change\n */\n updateWhere(\n where: (item: TEntity) => boolean,\n updateFn: (item: TEntity) => TEntity\n ): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'update', {\n where,\n update: updateFn,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Delete an item from the collection by ID\n * @returns Rollback function to undo the change\n */\n delete(id: string): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'delete', {\n id,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Delete items matching a predicate\n * @returns Rollback function to undo the change\n */\n deleteWhere(where: (item: TEntity) => boolean): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'delete', {\n where,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n}\n\n/** Channel for an entity - provides typed optimistic mutation methods */\nexport class EntityChannel<TEntity> {\n constructor(private readonly target: EntityDef<TEntity, any>) {}\n\n /**\n * Update the entity\n * @returns Rollback function to undo the change\n */\n update(updateFn: (item: TEntity) => TEntity, options?: { sync?: boolean }): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'update', {\n update: updateFn,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Replace the entity with new data\n * @returns Rollback function to undo the change\n */\n replace(data: TEntity, options?: { sync?: boolean }): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'replace', {\n data: data as any,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n}\n\n/**\n * Channel function for optimistic mutations.\n * Call with a collection or entity to get typed mutation methods.\n *\n * @example\n * // Standalone usage\n * const rollback = channel(usersCollection).prepend({ id: '1', name: 'John' });\n * // Later, to undo:\n * rollback();\n *\n * @example\n * // Update an entity\n * channel(userEntity).update(user => ({ ...user, name: 'Jane' }));\n */\nexport interface Channel {\n <TEntity>(target: CollectionDef<TEntity, any>): CollectionChannel<TEntity>;\n <TEntity>(target: EntityDef<TEntity, any>): EntityChannel<TEntity>;\n}\n\n/**\n * Create a channel for optimistic mutations.\n * Use this to apply immediate UI updates that can be rolled back.\n *\n * @example\n * const rollback = channel(usersCollection).prepend(newUser);\n * try {\n * await api.createUser(newUser);\n * } catch (error) {\n * rollback(); // Undo the optimistic update\n * }\n */\nexport const channel: Channel = (<TEntity>(\n target: CollectionDef<TEntity, any> | EntityDef<TEntity, any>\n): CollectionChannel<TEntity> | EntityChannel<TEntity> => {\n if (target._type === 'collection') {\n return new CollectionChannel(target);\n } else {\n return new EntityChannel(target);\n }\n}) as Channel;\n","import { useEffect, useMemo, useCallback } from 'react';\nimport {\n useQuery as useTanstackQuery,\n useInfiniteQuery,\n useQueryClient,\n type UseQueryOptions,\n type UseInfiniteQueryOptions,\n} from '@tanstack/react-query';\nimport type {\n CollectionDef,\n EntityDef,\n Optimistic,\n QueryOptions,\n PaginatedOptions,\n} from '../core/types';\nimport { registry } from '../core/registry';\n\n/** Options for useQuery hook */\nexport interface UseQueryHookOptions<TParams> extends QueryOptions {\n /** Parameters to pass to the fetch function */\n params?: TParams;\n /** Enable pagination mode (infinite query) */\n paginated?: boolean;\n /** For paginated: get params for each page */\n getPageParams?: (context: { pageParam: number }) => TParams;\n /** Custom query key (defaults to [def.name, params]) */\n queryKey?: readonly unknown[];\n}\n\n/** Query state object (second element of tuple) */\nexport interface QueryState {\n isLoading: boolean;\n isFetching: boolean;\n isError: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\n/** Pagination state object (third element of paginated tuple) */\nexport interface PaginationState {\n hasNextPage: boolean;\n fetchNextPage: () => void;\n isFetchingNextPage: boolean;\n}\n\n/** Return type for collection queries: [data, queryState] */\nexport type QueryResult<T> = [\n Optimistic<T>[] | undefined,\n QueryState\n];\n\n/** Return type for paginated queries: [data, queryState, paginationState] */\nexport type PaginatedQueryResult<T> = [\n Optimistic<T>[] | undefined,\n QueryState,\n PaginationState\n];\n\n/** Return type for entity queries: [data, queryState] */\nexport type EntityResult<T> = [\n Optimistic<T> | undefined,\n QueryState\n];\n\n/**\n * Unified query hook for fetching data\n *\n * @example\n * // Simple collection query\n * const [data, query] = useQuery(postsQuery, { params: { limit: 10 } })\n *\n * @example\n * // Paginated query\n * const [data, query, pagination] = useQuery(postsQuery, {\n * paginated: true,\n * getPageParams: ({ pageParam }) => ({ page: pageParam, limit: 10 })\n * })\n * // pagination.fetchNextPage(), pagination.hasNextPage\n *\n * @example\n * // Entity query\n * const [user, query] = useQuery(userEntity, { params: userId })\n */\nexport function useQuery<TData, TParams>(\n def: CollectionDef<TData, TParams>,\n options?: UseQueryHookOptions<TParams> & { paginated: true }\n): PaginatedQueryResult<TData>;\n\nexport function useQuery<TData, TParams>(\n def: CollectionDef<TData, TParams>,\n options?: UseQueryHookOptions<TParams>\n): QueryResult<TData>;\n\nexport function useQuery<TData, TParams>(\n def: EntityDef<TData, TParams>,\n options?: UseQueryHookOptions<TParams>\n): EntityResult<TData>;\n\nexport function useQuery<TData, TParams>(\n def: CollectionDef<TData, TParams> | EntityDef<TData, TParams>,\n options?: UseQueryHookOptions<TParams>\n): QueryResult<TData> | PaginatedQueryResult<TData> | EntityResult<TData> {\n const queryClient = useQueryClient();\n const { params, paginated, getPageParams, queryKey: customQueryKey, ...queryOptions } = options ?? {};\n\n // Build query key\n const queryKey = useMemo(\n () => customQueryKey ?? [def.name, params].filter(Boolean),\n [customQueryKey, def.name, params]\n );\n\n // Entity query\n if (def._type === 'entity') {\n const entityDef = def as EntityDef<TData, TParams>;\n const query = useTanstackQuery({\n queryKey,\n queryFn: () => entityDef.fetch(params as TParams),\n enabled: queryOptions.enabled,\n staleTime: queryOptions.staleTime,\n gcTime: queryOptions.cacheTime,\n refetchOnMount: queryOptions.refetchOnMount,\n refetchOnWindowFocus: queryOptions.refetchOnWindowFocus,\n refetchInterval: queryOptions.refetchInterval,\n });\n\n // Register for optimistic updates\n useEffect(() => {\n if (query.status !== 'success' || !query.data) return;\n\n const entry = {\n kind: 'entity' as const,\n name: def.name,\n queryKey,\n def: entityDef,\n getData: () => queryClient.getQueryData<TData>(queryKey),\n setData: (updater: (prev: TData | undefined) => TData | undefined) =>\n queryClient.setQueryData<TData>(queryKey, updater),\n };\n\n registry.register(entry);\n return () => registry.unregister(entry);\n }, [def.name, queryKey, query.status, query.data, queryClient]);\n\n return [\n query.data as Optimistic<TData> | undefined,\n {\n isLoading: query.isLoading,\n isFetching: query.isFetching,\n isError: query.isError,\n error: query.error,\n refetch: query.refetch,\n },\n ];\n }\n\n const collectionDef = def as CollectionDef<TData, TParams>;\n\n // Paginated collection\n if (paginated) {\n const infiniteQuery = useInfiniteQuery({\n queryKey,\n queryFn: ({ pageParam }) => {\n const pageParams = getPageParams\n ? getPageParams({ pageParam: pageParam as number })\n : ({ pageParam } as TParams);\n return collectionDef.fetch(pageParams);\n },\n initialPageParam: 1,\n getNextPageParam: (lastPage, allPages) =>\n lastPage.length > 0 ? allPages.length + 1 : undefined,\n enabled: queryOptions.enabled,\n staleTime: queryOptions.staleTime,\n gcTime: queryOptions.cacheTime,\n refetchOnMount: queryOptions.refetchOnMount,\n refetchOnWindowFocus: queryOptions.refetchOnWindowFocus,\n refetchInterval: queryOptions.refetchInterval,\n });\n\n const flatData = useMemo(\n () => infiniteQuery.data?.pages.flat() as Optimistic<TData>[] | undefined,\n [infiniteQuery.data]\n );\n\n // Register for optimistic updates\n useEffect(() => {\n if (infiniteQuery.status !== 'success' || !infiniteQuery.data) return;\n\n const entry = {\n kind: 'paginated' as const,\n name: def.name,\n queryKey,\n def: collectionDef,\n getData: () =>\n queryClient.getQueryData<{ pages: TData[][]; pageParams: unknown[] }>(\n queryKey\n ),\n setData: (\n updater: (\n prev: { pages: TData[][]; pageParams: unknown[] } | undefined\n ) => { pages: TData[][]; pageParams: unknown[] } | undefined\n ) =>\n queryClient.setQueryData<{\n pages: TData[][];\n pageParams: unknown[];\n }>(queryKey, updater),\n };\n\n registry.register(entry);\n return () => registry.unregister(entry);\n }, [def.name, queryKey, infiniteQuery.status, infiniteQuery.data, queryClient]);\n\n return [\n flatData,\n {\n isLoading: infiniteQuery.isLoading,\n isFetching: infiniteQuery.isFetching,\n isError: infiniteQuery.isError,\n error: infiniteQuery.error,\n refetch: infiniteQuery.refetch,\n },\n {\n hasNextPage: infiniteQuery.hasNextPage ?? false,\n fetchNextPage: infiniteQuery.fetchNextPage,\n isFetchingNextPage: infiniteQuery.isFetchingNextPage,\n },\n ];\n }\n\n // Simple collection query\n const query = useTanstackQuery({\n queryKey,\n queryFn: () => collectionDef.fetch(params as TParams),\n enabled: queryOptions.enabled,\n staleTime: queryOptions.staleTime,\n gcTime: queryOptions.cacheTime,\n refetchOnMount: queryOptions.refetchOnMount,\n refetchOnWindowFocus: queryOptions.refetchOnWindowFocus,\n refetchInterval: queryOptions.refetchInterval,\n });\n\n // Register for optimistic updates\n useEffect(() => {\n if (query.status !== 'success' || !query.data) return;\n\n const entry = {\n kind: 'collection' as const,\n name: def.name,\n queryKey,\n def: collectionDef,\n getData: () => queryClient.getQueryData<TData[]>(queryKey),\n setData: (updater: (prev: TData[] | undefined) => TData[] | undefined) =>\n queryClient.setQueryData<TData[]>(queryKey, updater),\n };\n\n registry.register(entry);\n return () => registry.unregister(entry);\n }, [def.name, queryKey, query.status, query.data, queryClient]);\n\n return [\n query.data as Optimistic<TData>[] | undefined,\n {\n isLoading: query.isLoading,\n isFetching: query.isFetching,\n isError: query.isError,\n error: query.error,\n refetch: query.refetch,\n },\n ];\n}\n","import { useMutation as useTanstackMutation } from '@tanstack/react-query';\nimport { nanoid } from 'nanoid';\nimport type {\n MutationDef,\n CollectionDef,\n EntityDef,\n} from '../core/types';\nimport { registry } from '../core/registry';\nimport {\n channel as coreChannel,\n type Channel,\n type CollectionChannel,\n type EntityChannel,\n} from '../core/channel';\n\n/** Extract entity type from a collection or entity definition */\ntype InferEntity<T> = T extends CollectionDef<infer TData, any>\n ? TData & {}\n : T extends EntityDef<infer TData, any>\n ? TData & {}\n : never;\n\n/** Base optimistic config with shared properties */\ninterface OptimisticConfigBase<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> {\n /** Target collection/entity to update */\n target: TTarget;\n /** Whether to sync with server response (replace optimistic with real data) */\n sync?: boolean;\n}\n\n/** Config for prepend/append actions - requires full entity */\ninterface OptimisticPrependAppendConfig<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> extends OptimisticConfigBase<TTarget, TParams> {\n action: 'prepend' | 'append';\n /** Data to prepend/append - must be a full entity */\n data: (params: TParams) => NoInfer<InferEntity<TTarget>>;\n}\n\n/** Config for replace action */\ninterface OptimisticReplaceConfig<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> extends OptimisticConfigBase<TTarget, TParams> {\n action: 'replace';\n /** Data for replacement */\n data: (params: TParams) => NoInfer<InferEntity<TTarget>>;\n /** ID of item to replace */\n id?: string | ((params: TParams) => string);\n /** Filter function to find items to replace */\n where?: (item: NoInfer<InferEntity<TTarget>>) => boolean;\n}\n\n/** Config for update action */\ninterface OptimisticUpdateConfig<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> extends OptimisticConfigBase<TTarget, TParams> {\n action: 'update';\n /** Partial data for update */\n data?: (params: TParams) => Partial<NoInfer<InferEntity<TTarget>>>;\n /** ID of item to update */\n id?: string | ((params: TParams) => string);\n /** Filter function to find items to update */\n where?: (item: NoInfer<InferEntity<TTarget>>) => boolean;\n /** Update function */\n update?: (item: NoInfer<InferEntity<TTarget>>, params: TParams) => NoInfer<InferEntity<TTarget>>;\n}\n\n/** Config for delete action */\ninterface OptimisticDeleteConfig<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> extends OptimisticConfigBase<TTarget, TParams> {\n action: 'delete';\n /** ID of item to delete */\n id?: string | ((params: TParams) => string);\n /** Filter function to find items to delete */\n where?: (item: NoInfer<InferEntity<TTarget>>) => boolean;\n}\n\n/** Optimistic update configuration - type inferred from target */\nexport type OptimisticConfig<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> =\n | OptimisticPrependAppendConfig<TTarget, TParams>\n | OptimisticReplaceConfig<TTarget, TParams>\n | OptimisticUpdateConfig<TTarget, TParams>\n | OptimisticDeleteConfig<TTarget, TParams>;\n\n/** Internal transaction type for batched mutations */\ninterface MutationTransaction {\n target: CollectionDef<any, any> | EntityDef<any, any>;\n action: 'prepend' | 'append' | 'update' | 'delete' | 'replace';\n data?: any;\n id?: string;\n where?: (item: any) => boolean;\n update?: (item: any) => any;\n sync?: boolean;\n}\n\n/** Internal collection channel for batched mutations */\nclass BatchedCollectionChannel<TEntity> {\n constructor(\n private readonly target: CollectionDef<TEntity, any>,\n private readonly transactions: MutationTransaction[]\n ) {}\n\n prepend(data: TEntity, options?: { sync?: boolean }): this {\n this.transactions.push({\n target: this.target,\n action: 'prepend',\n data,\n sync: options?.sync,\n });\n return this;\n }\n\n append(data: TEntity, options?: { sync?: boolean }): this {\n this.transactions.push({\n target: this.target,\n action: 'append',\n data,\n sync: options?.sync,\n });\n return this;\n }\n\n update(id: string, updateFn: (item: TEntity) => TEntity, options?: { sync?: boolean }): this {\n this.transactions.push({\n target: this.target,\n action: 'update',\n id,\n update: updateFn,\n sync: options?.sync,\n });\n return this;\n }\n\n delete(id: string): this {\n this.transactions.push({\n target: this.target,\n action: 'delete',\n id,\n });\n return this;\n }\n}\n\n/** Internal entity channel for batched mutations */\nclass BatchedEntityChannel<TEntity> {\n constructor(\n private readonly target: EntityDef<TEntity, any>,\n private readonly transactions: MutationTransaction[]\n ) {}\n\n update(updateFn: (item: TEntity) => TEntity, options?: { sync?: boolean }): this {\n this.transactions.push({\n target: this.target,\n action: 'update',\n update: updateFn,\n sync: options?.sync,\n });\n return this;\n }\n\n replace(data: TEntity, options?: { sync?: boolean }): this {\n this.transactions.push({\n target: this.target,\n action: 'replace',\n data,\n sync: options?.sync,\n });\n return this;\n }\n}\n\n/** Internal batched channel type */\ninterface BatchedChannel {\n <TEntity>(target: CollectionDef<TEntity, any>): BatchedCollectionChannel<TEntity>;\n <TEntity>(target: EntityDef<TEntity, any>): BatchedEntityChannel<TEntity>;\n}\n\n/** Creates a batched channel for collecting mutations */\nfunction createBatchedChannel(transactions: MutationTransaction[]): BatchedChannel {\n function channel<TEntity>(target: CollectionDef<TEntity, any>): BatchedCollectionChannel<TEntity>;\n function channel<TEntity>(target: EntityDef<TEntity, any>): BatchedEntityChannel<TEntity>;\n function channel<TEntity>(\n target: CollectionDef<TEntity, any> | EntityDef<TEntity, any>\n ): BatchedCollectionChannel<TEntity> | BatchedEntityChannel<TEntity> {\n if (target._type === 'collection') {\n return new BatchedCollectionChannel(target, transactions);\n } else {\n return new BatchedEntityChannel(target, transactions);\n }\n }\n return channel;\n}\n\n\n/** Options for useMutation hook */\nexport interface UseMutationOptions<TParams, TResponse> {\n /** Called when mutation starts */\n onMutate?: (params: TParams) => void;\n /** Called on success */\n onSuccess?: (data: TResponse, params: TParams) => void;\n /** Called on error */\n onError?: (error: Error, params: TParams) => void;\n}\n\n/** Return type for useMutation */\nexport interface MutationResult<TParams, TResponse> {\n mutate: (params: TParams) => void;\n mutateAsync: (params: TParams) => Promise<TResponse>;\n isLoading: boolean;\n isPending: boolean;\n isError: boolean;\n isSuccess: boolean;\n error: Error | null;\n data: TResponse | undefined;\n reset: () => void;\n}\n\n/**\n * Mutation hook with simplified optimistic updates\n *\n * @example\n * // Simple mutation\n * const { mutate } = useMutation(createPost)\n *\n * @example\n * // With optimistic update\n * const { mutate } = useMutation(createPost, {\n * optimistic: {\n * target: postsQuery,\n * action: 'prepend',\n * data: (params) => ({ ...params, _id: 'temp-id' })\n * }\n * })\n *\n * @example\n * // Multiple optimistic updates\n * const { mutate } = useMutation(deletePost, {\n * optimistic: [\n * { target: postsQuery, action: 'delete', id: (p) => p.postId },\n * { target: userStatsEntity, action: 'update', update: (stats) => ({ ...stats, postCount: stats.postCount - 1 }) }\n * ]\n * })\n */\nexport function useMutation<\n TParams,\n TResponse,\n>(\n def: MutationDef<TParams, TResponse>,\n options?: UseMutationOptions<TParams, TResponse> & {\n /** Optimistic update configuration - receives channel and params */\n optimistic?: (channel: BatchedChannel, params: TParams) => void;\n }\n): MutationResult<TParams, TResponse> {\n const mutation = useTanstackMutation<\n TResponse,\n Error,\n TParams,\n { rollbacks: (() => void)[]; optimisticId: string; transactions: MutationTransaction[] }\n >({\n mutationKey: def.name ? [def.name] : undefined,\n mutationFn: def.mutate,\n\n onMutate: async (params) => {\n const rollbacks: (() => void)[] = [];\n const optimisticId = nanoid();\n const transactions: MutationTransaction[] = [];\n\n // Apply optimistic updates via channel\n if (options?.optimistic) {\n const channel = createBatchedChannel(transactions);\n options.optimistic(channel, params);\n\n for (const tx of transactions) {\n const { target, action, data, id, where, update } = tx;\n\n // Add optimistic metadata to data\n const optimisticData = data\n ? {\n ...data,\n _optimistic: { id: optimisticId, status: 'pending' as const },\n }\n : undefined;\n\n const updateRollbacks = registry.applyUpdate(target.name, action, {\n data: optimisticData,\n id,\n where,\n update: update\n ? (item: any) => update(item)\n : optimisticData\n ? (item: any) => ({ ...item, ...optimisticData })\n : undefined,\n });\n\n rollbacks.push(...updateRollbacks);\n }\n }\n\n options?.onMutate?.(params);\n return { rollbacks, optimisticId, transactions };\n },\n\n onSuccess: (data, params, context) => {\n // If sync is enabled, replace optimistic data with server response\n if (context?.transactions) {\n for (const tx of context.transactions) {\n if (tx.sync && data) {\n // Replace optimistic item with real server data\n registry.applyUpdate(tx.target.name, 'update', {\n where: (item: any) =>\n item._optimistic?.id === context?.optimisticId,\n update: () => data as any,\n });\n }\n }\n }\n\n options?.onSuccess?.(data, params);\n },\n\n onError: (error, params, context) => {\n // Rollback all optimistic updates\n context?.rollbacks.forEach((rollback) => rollback());\n options?.onError?.(error, params);\n },\n });\n\n return {\n mutate: mutation.mutate,\n mutateAsync: mutation.mutateAsync,\n isLoading: mutation.isPending,\n isPending: mutation.isPending,\n isError: mutation.isError,\n isSuccess: mutation.isSuccess,\n error: mutation.error,\n data: mutation.data,\n reset: mutation.reset,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/define.ts","../src/core/registry.ts","../src/core/channel.ts","../src/react/use-query.ts","../src/react/use-mutation.ts"],"names":["nanoid","useQueryClient","useMemo","query","useTanstackQuery","useEffect","useInfiniteQuery","channel","useTanstackMutation"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n CollectionDef,\n EntityDef,\n MutationDef,\n IdGetter,\n} from './types';\n\n/**\n * Define a collection query for fetching arrays of items\n *\n * @example\n * const postsQuery = defineCollection({\n * name: 'posts',\n * id: (post) => post._id,\n * fetch: ({ page }) => api.get(`/posts?page=${page}`).json()\n * })\n */\nexport function defineCollection<TData, TParams = void>(config: {\n name: string;\n id: IdGetter<TData>;\n fetch: (params: TParams) => Promise<TData[]>;\n}): CollectionDef<TData, TParams> {\n return {\n _type: 'collection',\n name: config.name,\n id: config.id,\n fetch: config.fetch,\n };\n}\n\n/**\n * Define an entity for fetching single items\n *\n * @example\n * const userEntity = defineEntity({\n * name: 'user',\n * fetch: (userId) => api.get(`/users/${userId}`).json()\n * })\n */\nexport function defineEntity<TData, TParams = void>(config: {\n name: string;\n fetch: (params: TParams) => Promise<TData>;\n}): EntityDef<TData, TParams> {\n return {\n _type: 'entity',\n name: config.name,\n fetch: config.fetch,\n };\n}\n\n/**\n * Define a mutation for writing data\n *\n * @example\n * const createPost = defineMutation({\n * name: 'createPost',\n * mutate: (data) => api.post('/posts', { json: data }).json()\n * })\n */\nexport function defineMutation<TParams, TResponse = void>(config: {\n name?: string;\n mutate: (params: TParams) => Promise<TResponse>;\n}): MutationDef<TParams, TResponse> {\n return {\n _type: 'mutation',\n name: config.name,\n mutate: config.mutate,\n };\n}\n","import type { CollectionDef, EntityDef, Optimistic } from './types';\n\n/** Registered collection entry */\nexport interface RegisteredCollection<T = any> {\n kind: 'collection';\n name: string;\n queryKey: readonly unknown[];\n def: CollectionDef<T, any>;\n getData: () => T[] | undefined;\n setData: (updater: (prev: T[] | undefined) => T[] | undefined) => void;\n}\n\n/** Registered entity entry */\nexport interface RegisteredEntity<T = any> {\n kind: 'entity';\n name: string;\n queryKey: readonly unknown[];\n def: EntityDef<T, any>;\n getData: () => T | undefined;\n setData: (updater: (prev: T | undefined) => T | undefined) => void;\n}\n\n/** Registered paginated collection entry */\nexport interface RegisteredPaginatedCollection<T = any> {\n kind: 'paginated';\n name: string;\n queryKey: readonly unknown[];\n def: CollectionDef<T, any>;\n getData: () => { pages: T[][]; pageParams: unknown[] } | undefined;\n setData: (\n updater: (\n prev: { pages: T[][]; pageParams: unknown[] } | undefined\n ) => { pages: T[][]; pageParams: unknown[] } | undefined\n ) => void;\n}\n\nexport type RegisteredEntry =\n | RegisteredCollection\n | RegisteredEntity\n | RegisteredPaginatedCollection;\n\n/**\n * Internal registry for tracking active queries\n * Used by optimistic updates to broadcast changes\n */\nclass QueryRegistry {\n private entries = new Map<string, Set<RegisteredEntry>>();\n\n /** Register an active query */\n register(entry: RegisteredEntry): void {\n if (!this.entries.has(entry.name)) {\n this.entries.set(entry.name, new Set());\n }\n this.entries.get(entry.name)!.add(entry);\n }\n\n /** Unregister a query when component unmounts */\n unregister(entry: RegisteredEntry): void {\n const set = this.entries.get(entry.name);\n if (set) {\n set.delete(entry);\n if (set.size === 0) {\n this.entries.delete(entry.name);\n }\n }\n }\n\n /** Get all registered entries for a query name */\n getByName(name: string): RegisteredEntry[] {\n return Array.from(this.entries.get(name) ?? []);\n }\n\n /** Apply an optimistic update to all queries with given name */\n applyUpdate<T>(\n name: string,\n action: 'prepend' | 'append' | 'update' | 'delete' | 'replace',\n payload: {\n data?: Partial<Optimistic<T>>;\n id?: string;\n where?: (item: T) => boolean;\n update?: (item: T) => T;\n }\n ): (() => void)[] {\n const entries = this.getByName(name);\n const rollbacks: (() => void)[] = [];\n\n for (const entry of entries) {\n if (entry.kind === 'collection') {\n const previous = entry.getData();\n const rollback = () => entry.setData(() => previous);\n rollbacks.push(rollback);\n\n entry.setData((prev) => {\n if (!prev) return prev;\n return this.applyCollectionUpdate(prev, action, payload, entry.def.id);\n });\n } else if (entry.kind === 'paginated') {\n const previous = entry.getData();\n const rollback = () => entry.setData(() => previous);\n rollbacks.push(rollback);\n\n entry.setData((prev) => {\n if (!prev) return prev;\n return {\n ...prev,\n pages: prev.pages.map((page, i) =>\n i === 0\n ? this.applyCollectionUpdate(page, action, payload, entry.def.id)\n : page\n ),\n };\n });\n } else if (entry.kind === 'entity') {\n const previous = entry.getData();\n const rollback = () => entry.setData(() => previous);\n rollbacks.push(rollback);\n\n if (action === 'update' && payload.update) {\n entry.setData((prev) => (prev ? payload.update!(prev as T) : prev));\n } else if (action === 'replace' && payload.data) {\n entry.setData(() => payload.data as T);\n }\n }\n }\n\n return rollbacks;\n }\n\n private applyCollectionUpdate<T>(\n items: T[],\n action: string,\n payload: {\n data?: Partial<Optimistic<T>>;\n id?: string;\n where?: (item: T) => boolean;\n update?: (item: T) => T;\n },\n getId: (item: T) => string\n ): T[] {\n switch (action) {\n case 'prepend':\n return payload.data ? [payload.data as T, ...items] : items;\n\n case 'append':\n return payload.data ? [...items, payload.data as T] : items;\n\n case 'update':\n return items.map((item) => {\n const matches = payload.id\n ? getId(item) === payload.id\n : payload.where?.(item);\n if (matches && payload.update) {\n return payload.update(item);\n }\n if (matches && payload.data) {\n return { ...item, ...payload.data };\n }\n return item;\n });\n\n case 'delete':\n return items.filter((item) => {\n if (payload.id) return getId(item) !== payload.id;\n if (payload.where) return !payload.where(item);\n return true;\n });\n\n case 'replace':\n return items.map((item) => {\n const matches = payload.id\n ? getId(item) === payload.id\n : payload.where?.(item);\n return matches && payload.data ? (payload.data as T) : item;\n });\n\n default:\n return items;\n }\n }\n}\n\n/** Singleton registry instance */\nexport const registry = new QueryRegistry();\n","import { nanoid } from 'nanoid';\nimport type { CollectionDef, EntityDef, Optimistic } from './types';\nimport { registry } from './registry';\n\n/** Transaction returned from channel methods */\nexport interface OptimisticTransaction {\n target: CollectionDef<any, any> | EntityDef<any, any>;\n action: 'prepend' | 'append' | 'update' | 'delete' | 'replace';\n data?: any;\n id?: string;\n where?: (item: any) => boolean;\n update?: (item: any) => any;\n sync?: boolean;\n rollback: () => void;\n}\n\n/** Channel for a collection - provides typed optimistic mutation methods */\nexport class CollectionChannel<TEntity> {\n private readonly optimisticId = nanoid();\n\n constructor(private readonly target: CollectionDef<TEntity, any>) {}\n\n /**\n * Prepend an item to the collection\n * @returns Rollback function to undo the change\n */\n prepend(data: TEntity, options?: { sync?: boolean }): () => void {\n const optimisticData = {\n ...data,\n _optimistic: { id: this.optimisticId, status: 'pending' as const },\n };\n\n const rollbacks = registry.applyUpdate(this.target.name, 'prepend', {\n data: optimisticData,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Append an item to the collection\n * @returns Rollback function to undo the change\n */\n append(data: TEntity, options?: { sync?: boolean }): () => void {\n const optimisticData = {\n ...data,\n _optimistic: { id: this.optimisticId, status: 'pending' as const },\n };\n\n const rollbacks = registry.applyUpdate(this.target.name, 'append', {\n data: optimisticData,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Update an item in the collection by ID\n * @returns Rollback function to undo the change\n */\n update(\n id: string,\n updateFn: (item: TEntity) => TEntity,\n options?: { sync?: boolean }\n ): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'update', {\n id,\n update: updateFn,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Update items matching a predicate\n * @returns Rollback function to undo the change\n */\n updateWhere(\n where: (item: TEntity) => boolean,\n updateFn: (item: TEntity) => TEntity\n ): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'update', {\n where,\n update: updateFn,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Delete an item from the collection by ID\n * @returns Rollback function to undo the change\n */\n delete(id: string): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'delete', {\n id,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Delete items matching a predicate\n * @returns Rollback function to undo the change\n */\n deleteWhere(where: (item: TEntity) => boolean): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'delete', {\n where,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n}\n\n/** Channel for an entity - provides typed optimistic mutation methods */\nexport class EntityChannel<TEntity> {\n constructor(private readonly target: EntityDef<TEntity, any>) {}\n\n /**\n * Update the entity\n * @returns Rollback function to undo the change\n */\n update(updateFn: (item: TEntity) => TEntity, options?: { sync?: boolean }): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'update', {\n update: updateFn,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n\n /**\n * Replace the entity with new data\n * @returns Rollback function to undo the change\n */\n replace(data: TEntity, options?: { sync?: boolean }): () => void {\n const rollbacks = registry.applyUpdate(this.target.name, 'replace', {\n data: data as any,\n });\n\n return () => rollbacks.forEach((rb) => rb());\n }\n}\n\n/**\n * Channel function for optimistic mutations.\n * Call with a collection or entity to get typed mutation methods.\n *\n * @example\n * // Standalone usage\n * const rollback = channel(usersCollection).prepend({ id: '1', name: 'John' });\n * // Later, to undo:\n * rollback();\n *\n * @example\n * // Update an entity\n * channel(userEntity).update(user => ({ ...user, name: 'Jane' }));\n */\nexport interface Channel {\n <TEntity>(target: CollectionDef<TEntity, any>): CollectionChannel<TEntity>;\n <TEntity>(target: EntityDef<TEntity, any>): EntityChannel<TEntity>;\n}\n\n/**\n * Create a channel for optimistic mutations.\n * Use this to apply immediate UI updates that can be rolled back.\n *\n * @example\n * const rollback = channel(usersCollection).prepend(newUser);\n * try {\n * await api.createUser(newUser);\n * } catch (error) {\n * rollback(); // Undo the optimistic update\n * }\n */\nexport const channel: Channel = (<TEntity>(\n target: CollectionDef<TEntity, any> | EntityDef<TEntity, any>\n): CollectionChannel<TEntity> | EntityChannel<TEntity> => {\n if (target._type === 'collection') {\n return new CollectionChannel(target);\n } else {\n return new EntityChannel(target);\n }\n}) as Channel;\n","import { useEffect, useMemo, useCallback } from 'react';\nimport {\n useQuery as useTanstackQuery,\n useInfiniteQuery,\n useQueryClient,\n type UseQueryOptions,\n type UseInfiniteQueryOptions,\n} from '@tanstack/react-query';\nimport type {\n CollectionDef,\n EntityDef,\n Optimistic,\n QueryOptions,\n PaginatedOptions,\n} from '../core/types';\nimport { registry } from '../core/registry';\n\n/** Options for useQuery hook */\nexport interface UseQueryHookOptions<TParams> extends QueryOptions {\n /** Parameters to pass to the fetch function */\n params?: TParams;\n /** Enable pagination mode (infinite query) */\n paginated?: boolean;\n /** For paginated: get params for each page */\n getPageParams?: (context: { pageParam: number }) => TParams;\n /** Custom query key (defaults to [def.name, params]) */\n queryKey?: readonly unknown[];\n}\n\n/** Query state object (second element of tuple) */\nexport interface QueryState {\n /** True when fetching for the first time (no data yet) */\n isLoading: boolean;\n /** True when any fetch is in progress (including background refetches) */\n isFetching: boolean;\n /** True when the query has successfully fetched data */\n isSuccess: boolean;\n /** True when the query has encountered an error */\n isError: boolean;\n /** Alias for isLoading (TanStack Query v5 naming) */\n isPending: boolean;\n /** The current status: 'pending' | 'error' | 'success' */\n status: 'pending' | 'error' | 'success';\n /** The error object if isError is true */\n error: Error | null;\n /** Timestamp of when the data was last updated */\n dataUpdatedAt: number;\n /** Timestamp of when the error was last updated */\n errorUpdatedAt: number;\n /** Number of times the query has failed */\n failureCount: number;\n /** True if data is considered stale */\n isStale: boolean;\n /** True if data is from the cache (placeholder while fetching) */\n isPlaceholderData: boolean;\n /** Manually refetch the query */\n refetch: () => void;\n}\n\n/** Pagination state object (third element of paginated tuple) */\nexport interface PaginationState {\n hasNextPage: boolean;\n fetchNextPage: () => void;\n isFetchingNextPage: boolean;\n}\n\n/** Return type for collection queries: [data, queryState] */\nexport type QueryResult<T> = [\n Optimistic<T>[] | undefined,\n QueryState\n];\n\n/** Return type for paginated queries: [data, queryState, paginationState] */\nexport type PaginatedQueryResult<T> = [\n Optimistic<T>[] | undefined,\n QueryState,\n PaginationState\n];\n\n/** Return type for entity queries: [data, queryState] */\nexport type EntityResult<T> = [\n Optimistic<T> | undefined,\n QueryState\n];\n\n/**\n * Unified query hook for fetching data\n *\n * @example\n * // Simple collection query\n * const [data, query] = useQuery(postsQuery, { params: { limit: 10 } })\n *\n * @example\n * // Paginated query\n * const [data, query, pagination] = useQuery(postsQuery, {\n * paginated: true,\n * getPageParams: ({ pageParam }) => ({ page: pageParam, limit: 10 })\n * })\n * // pagination.fetchNextPage(), pagination.hasNextPage\n *\n * @example\n * // Entity query\n * const [user, query] = useQuery(userEntity, { params: userId })\n */\nexport function useQuery<TData, TParams>(\n def: CollectionDef<TData, TParams>,\n options?: UseQueryHookOptions<TParams> & { paginated: true }\n): PaginatedQueryResult<TData>;\n\nexport function useQuery<TData, TParams>(\n def: CollectionDef<TData, TParams>,\n options?: UseQueryHookOptions<TParams>\n): QueryResult<TData>;\n\nexport function useQuery<TData, TParams>(\n def: EntityDef<TData, TParams>,\n options?: UseQueryHookOptions<TParams>\n): EntityResult<TData>;\n\nexport function useQuery<TData, TParams>(\n def: CollectionDef<TData, TParams> | EntityDef<TData, TParams>,\n options?: UseQueryHookOptions<TParams>\n): QueryResult<TData> | PaginatedQueryResult<TData> | EntityResult<TData> {\n const queryClient = useQueryClient();\n const { params, paginated, getPageParams, queryKey: customQueryKey, ...queryOptions } = options ?? {};\n\n // Build query key\n const queryKey = useMemo(\n () => customQueryKey ?? [def.name, params].filter(Boolean),\n [customQueryKey, def.name, params]\n );\n\n // Entity query\n if (def._type === 'entity') {\n const entityDef = def as EntityDef<TData, TParams>;\n const query = useTanstackQuery({\n queryKey,\n queryFn: () => entityDef.fetch(params as TParams),\n enabled: queryOptions.enabled,\n staleTime: queryOptions.staleTime,\n gcTime: queryOptions.cacheTime,\n refetchOnMount: queryOptions.refetchOnMount,\n refetchOnWindowFocus: queryOptions.refetchOnWindowFocus,\n refetchInterval: queryOptions.refetchInterval,\n });\n\n // Register for optimistic updates\n useEffect(() => {\n if (query.status !== 'success' || !query.data) return;\n\n const entry = {\n kind: 'entity' as const,\n name: def.name,\n queryKey,\n def: entityDef,\n getData: () => queryClient.getQueryData<TData>(queryKey),\n setData: (updater: (prev: TData | undefined) => TData | undefined) =>\n queryClient.setQueryData<TData>(queryKey, updater),\n };\n\n registry.register(entry);\n return () => registry.unregister(entry);\n }, [def.name, queryKey, query.status, query.data, queryClient]);\n\n return [\n query.data as Optimistic<TData> | undefined,\n {\n isLoading: query.isLoading,\n isFetching: query.isFetching,\n isSuccess: query.isSuccess,\n isError: query.isError,\n isPending: query.isPending,\n status: query.status,\n error: query.error,\n dataUpdatedAt: query.dataUpdatedAt,\n errorUpdatedAt: query.errorUpdatedAt,\n failureCount: query.failureCount,\n isStale: query.isStale,\n isPlaceholderData: query.isPlaceholderData,\n refetch: query.refetch,\n },\n ];\n }\n\n const collectionDef = def as CollectionDef<TData, TParams>;\n\n // Paginated collection\n if (paginated) {\n const infiniteQuery = useInfiniteQuery({\n queryKey,\n queryFn: ({ pageParam }) => {\n const pageParams = getPageParams\n ? getPageParams({ pageParam: pageParam as number })\n : ({ pageParam } as TParams);\n return collectionDef.fetch(pageParams);\n },\n initialPageParam: 1,\n getNextPageParam: (lastPage, allPages) =>\n lastPage.length > 0 ? allPages.length + 1 : undefined,\n enabled: queryOptions.enabled,\n staleTime: queryOptions.staleTime,\n gcTime: queryOptions.cacheTime,\n refetchOnMount: queryOptions.refetchOnMount,\n refetchOnWindowFocus: queryOptions.refetchOnWindowFocus,\n refetchInterval: queryOptions.refetchInterval,\n });\n\n const flatData = useMemo(\n () => infiniteQuery.data?.pages.flat() as Optimistic<TData>[] | undefined,\n [infiniteQuery.data]\n );\n\n // Register for optimistic updates\n useEffect(() => {\n if (infiniteQuery.status !== 'success' || !infiniteQuery.data) return;\n\n const entry = {\n kind: 'paginated' as const,\n name: def.name,\n queryKey,\n def: collectionDef,\n getData: () =>\n queryClient.getQueryData<{ pages: TData[][]; pageParams: unknown[] }>(\n queryKey\n ),\n setData: (\n updater: (\n prev: { pages: TData[][]; pageParams: unknown[] } | undefined\n ) => { pages: TData[][]; pageParams: unknown[] } | undefined\n ) =>\n queryClient.setQueryData<{\n pages: TData[][];\n pageParams: unknown[];\n }>(queryKey, updater),\n };\n\n registry.register(entry);\n return () => registry.unregister(entry);\n }, [def.name, queryKey, infiniteQuery.status, infiniteQuery.data, queryClient]);\n\n return [\n flatData,\n {\n isLoading: infiniteQuery.isLoading,\n isFetching: infiniteQuery.isFetching,\n isSuccess: infiniteQuery.isSuccess,\n isError: infiniteQuery.isError,\n isPending: infiniteQuery.isPending,\n status: infiniteQuery.status,\n error: infiniteQuery.error,\n dataUpdatedAt: infiniteQuery.dataUpdatedAt,\n errorUpdatedAt: infiniteQuery.errorUpdatedAt,\n failureCount: infiniteQuery.failureCount,\n isStale: infiniteQuery.isStale,\n isPlaceholderData: infiniteQuery.isPlaceholderData,\n refetch: infiniteQuery.refetch,\n },\n {\n hasNextPage: infiniteQuery.hasNextPage ?? false,\n fetchNextPage: infiniteQuery.fetchNextPage,\n isFetchingNextPage: infiniteQuery.isFetchingNextPage,\n },\n ];\n }\n\n // Simple collection query\n const query = useTanstackQuery({\n queryKey,\n queryFn: () => collectionDef.fetch(params as TParams),\n enabled: queryOptions.enabled,\n staleTime: queryOptions.staleTime,\n gcTime: queryOptions.cacheTime,\n refetchOnMount: queryOptions.refetchOnMount,\n refetchOnWindowFocus: queryOptions.refetchOnWindowFocus,\n refetchInterval: queryOptions.refetchInterval,\n });\n\n // Register for optimistic updates\n useEffect(() => {\n if (query.status !== 'success' || !query.data) return;\n\n const entry = {\n kind: 'collection' as const,\n name: def.name,\n queryKey,\n def: collectionDef,\n getData: () => queryClient.getQueryData<TData[]>(queryKey),\n setData: (updater: (prev: TData[] | undefined) => TData[] | undefined) =>\n queryClient.setQueryData<TData[]>(queryKey, updater),\n };\n\n registry.register(entry);\n return () => registry.unregister(entry);\n }, [def.name, queryKey, query.status, query.data, queryClient]);\n\n return [\n query.data as Optimistic<TData>[] | undefined,\n {\n isLoading: query.isLoading,\n isFetching: query.isFetching,\n isSuccess: query.isSuccess,\n isError: query.isError,\n isPending: query.isPending,\n status: query.status,\n error: query.error,\n dataUpdatedAt: query.dataUpdatedAt,\n errorUpdatedAt: query.errorUpdatedAt,\n failureCount: query.failureCount,\n isStale: query.isStale,\n isPlaceholderData: query.isPlaceholderData,\n refetch: query.refetch,\n },\n ];\n}\n","import { useMutation as useTanstackMutation } from '@tanstack/react-query';\nimport { nanoid } from 'nanoid';\nimport type {\n MutationDef,\n CollectionDef,\n EntityDef,\n} from '../core/types';\nimport { registry } from '../core/registry';\nimport {\n channel as coreChannel,\n type Channel,\n type CollectionChannel,\n type EntityChannel,\n} from '../core/channel';\n\n/** Extract entity type from a collection or entity definition */\ntype InferEntity<T> = T extends CollectionDef<infer TData, any>\n ? TData & {}\n : T extends EntityDef<infer TData, any>\n ? TData & {}\n : never;\n\n/** Base optimistic config with shared properties */\ninterface OptimisticConfigBase<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> {\n /** Target collection/entity to update */\n target: TTarget;\n /** Whether to reconcile with server response (replace optimistic with real data) */\n reconcile?: boolean;\n}\n\n/** Config for prepend/append actions - requires full entity */\ninterface OptimisticPrependAppendConfig<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> extends OptimisticConfigBase<TTarget, TParams> {\n action: 'prepend' | 'append';\n /** Data to prepend/append - must be a full entity */\n data: (params: TParams) => NoInfer<InferEntity<TTarget>>;\n}\n\n/** Config for replace action */\ninterface OptimisticReplaceConfig<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> extends OptimisticConfigBase<TTarget, TParams> {\n action: 'replace';\n /** Data for replacement */\n data: (params: TParams) => NoInfer<InferEntity<TTarget>>;\n /** ID of item to replace */\n id?: string | ((params: TParams) => string);\n /** Filter function to find items to replace */\n where?: (item: NoInfer<InferEntity<TTarget>>) => boolean;\n}\n\n/** Config for update action */\ninterface OptimisticUpdateConfig<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> extends OptimisticConfigBase<TTarget, TParams> {\n action: 'update';\n /** Partial data for update */\n data?: (params: TParams) => Partial<NoInfer<InferEntity<TTarget>>>;\n /** ID of item to update */\n id?: string | ((params: TParams) => string);\n /** Filter function to find items to update */\n where?: (item: NoInfer<InferEntity<TTarget>>) => boolean;\n /** Update function */\n update?: (item: NoInfer<InferEntity<TTarget>>, params: TParams) => NoInfer<InferEntity<TTarget>>;\n}\n\n/** Config for delete action */\ninterface OptimisticDeleteConfig<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> extends OptimisticConfigBase<TTarget, TParams> {\n action: 'delete';\n /** ID of item to delete */\n id?: string | ((params: TParams) => string);\n /** Filter function to find items to delete */\n where?: (item: NoInfer<InferEntity<TTarget>>) => boolean;\n}\n\n/** Optimistic update configuration - type inferred from target */\nexport type OptimisticConfig<\n TTarget extends CollectionDef<any, any> | EntityDef<any, any>,\n TParams\n> =\n | OptimisticPrependAppendConfig<TTarget, TParams>\n | OptimisticReplaceConfig<TTarget, TParams>\n | OptimisticUpdateConfig<TTarget, TParams>\n | OptimisticDeleteConfig<TTarget, TParams>;\n\n/** Internal transaction type for batched mutations */\ninterface MutationTransaction {\n target: CollectionDef<any, any> | EntityDef<any, any>;\n action: 'prepend' | 'append' | 'update' | 'delete' | 'replace';\n data?: any;\n id?: string;\n where?: (item: any) => boolean;\n update?: (item: any) => any;\n reconcile?: boolean;\n}\n\n/** Internal collection channel for batched mutations */\nclass BatchedCollectionChannel<TEntity> {\n constructor(\n private readonly target: CollectionDef<TEntity, any>,\n private readonly transactions: MutationTransaction[]\n ) {}\n\n prepend(data: TEntity, options?: { reconcile?: boolean }): this {\n this.transactions.push({\n target: this.target,\n action: 'prepend',\n data,\n reconcile: options?.reconcile,\n });\n return this;\n }\n\n append(data: TEntity, options?: { reconcile?: boolean }): this {\n this.transactions.push({\n target: this.target,\n action: 'append',\n data,\n reconcile: options?.reconcile,\n });\n return this;\n }\n\n update(id: string, updateFn: (item: TEntity) => TEntity, options?: { reconcile?: boolean }): this {\n this.transactions.push({\n target: this.target,\n action: 'update',\n id,\n update: updateFn,\n reconcile: options?.reconcile,\n });\n return this;\n }\n\n delete(id: string): this {\n this.transactions.push({\n target: this.target,\n action: 'delete',\n id,\n });\n return this;\n }\n}\n\n/** Internal entity channel for batched mutations */\nclass BatchedEntityChannel<TEntity> {\n constructor(\n private readonly target: EntityDef<TEntity, any>,\n private readonly transactions: MutationTransaction[]\n ) {}\n\n update(updateFn: (item: TEntity) => TEntity, options?: { reconcile?: boolean }): this {\n this.transactions.push({\n target: this.target,\n action: 'update',\n update: updateFn,\n reconcile: options?.reconcile,\n });\n return this;\n }\n\n replace(data: TEntity, options?: { reconcile?: boolean }): this {\n this.transactions.push({\n target: this.target,\n action: 'replace',\n data,\n reconcile: options?.reconcile,\n });\n return this;\n }\n}\n\n/** Internal batched channel type */\ninterface BatchedChannel {\n <TEntity>(target: CollectionDef<TEntity, any>): BatchedCollectionChannel<TEntity>;\n <TEntity>(target: EntityDef<TEntity, any>): BatchedEntityChannel<TEntity>;\n}\n\n/** Creates a batched channel for collecting mutations */\nfunction createBatchedChannel(transactions: MutationTransaction[]): BatchedChannel {\n function channel<TEntity>(target: CollectionDef<TEntity, any>): BatchedCollectionChannel<TEntity>;\n function channel<TEntity>(target: EntityDef<TEntity, any>): BatchedEntityChannel<TEntity>;\n function channel<TEntity>(\n target: CollectionDef<TEntity, any> | EntityDef<TEntity, any>\n ): BatchedCollectionChannel<TEntity> | BatchedEntityChannel<TEntity> {\n if (target._type === 'collection') {\n return new BatchedCollectionChannel(target, transactions);\n } else {\n return new BatchedEntityChannel(target, transactions);\n }\n }\n return channel;\n}\n\n\n/** Options for useMutation hook */\nexport interface UseMutationOptions<TParams, TResponse> {\n /** Called when mutation starts */\n onMutate?: (params: TParams) => void;\n /** Called on success */\n onSuccess?: (data: TResponse, params: TParams) => void;\n /** Called on error */\n onError?: (error: Error, params: TParams) => void;\n}\n\n/** Return type for useMutation */\nexport interface MutationResult<TParams, TResponse> {\n mutate: (params: TParams) => void;\n mutateAsync: (params: TParams) => Promise<TResponse>;\n isLoading: boolean;\n isPending: boolean;\n isError: boolean;\n isSuccess: boolean;\n error: Error | null;\n data: TResponse | undefined;\n reset: () => void;\n}\n\n/**\n * Mutation hook with simplified optimistic updates\n *\n * @example\n * // Simple mutation\n * const { mutate } = useMutation(createPost)\n *\n * @example\n * // With optimistic update\n * const { mutate } = useMutation(createPost, {\n * optimistic: {\n * target: postsQuery,\n * action: 'prepend',\n * data: (params) => ({ ...params, _id: 'temp-id' })\n * }\n * })\n *\n * @example\n * // Multiple optimistic updates\n * const { mutate } = useMutation(deletePost, {\n * optimistic: [\n * { target: postsQuery, action: 'delete', id: (p) => p.postId },\n * { target: userStatsEntity, action: 'update', update: (stats) => ({ ...stats, postCount: stats.postCount - 1 }) }\n * ]\n * })\n */\nexport function useMutation<\n TParams,\n TResponse,\n>(\n def: MutationDef<TParams, TResponse>,\n options?: UseMutationOptions<TParams, TResponse> & {\n /** Optimistic update configuration - receives channel and params */\n optimistic?: (channel: BatchedChannel, params: TParams) => void;\n }\n): MutationResult<TParams, TResponse> {\n const mutation = useTanstackMutation<\n TResponse,\n Error,\n TParams,\n { rollbacks: (() => void)[]; optimisticId: string; transactions: MutationTransaction[] }\n >({\n mutationKey: def.name ? [def.name] : undefined,\n mutationFn: def.mutate,\n\n onMutate: async (params) => {\n const rollbacks: (() => void)[] = [];\n const optimisticId = nanoid();\n const transactions: MutationTransaction[] = [];\n\n // Apply optimistic updates via channel\n if (options?.optimistic) {\n const channel = createBatchedChannel(transactions);\n options.optimistic(channel, params);\n\n for (const tx of transactions) {\n const { target, action, data, id, where, update } = tx;\n\n // Add optimistic metadata to data\n const optimisticData = data\n ? {\n ...data,\n _optimistic: { id: optimisticId, status: 'pending' as const },\n }\n : undefined;\n\n const updateRollbacks = registry.applyUpdate(target.name, action, {\n data: optimisticData,\n id,\n where,\n update: update\n ? (item: any) => update(item)\n : optimisticData\n ? (item: any) => ({ ...item, ...optimisticData })\n : undefined,\n });\n\n rollbacks.push(...updateRollbacks);\n }\n }\n\n options?.onMutate?.(params);\n return { rollbacks, optimisticId, transactions };\n },\n\n onSuccess: (data, params, context) => {\n // If reconcile is enabled, replace optimistic data with server response\n if (context?.transactions) {\n for (const tx of context.transactions) {\n if (tx.reconcile && data) {\n // Replace optimistic item with real server data\n registry.applyUpdate(tx.target.name, 'update', {\n where: (item: any) =>\n item._optimistic?.id === context?.optimisticId,\n update: () => data as any,\n });\n }\n }\n }\n\n options?.onSuccess?.(data, params);\n },\n\n onError: (error, params, context) => {\n // Rollback all optimistic updates\n context?.rollbacks.forEach((rollback) => rollback());\n options?.onError?.(error, params);\n },\n });\n\n return {\n mutate: mutation.mutate,\n mutateAsync: mutation.mutateAsync,\n isLoading: mutation.isPending,\n isPending: mutation.isPending,\n isError: mutation.isError,\n isSuccess: mutation.isSuccess,\n error: mutation.error,\n data: mutation.data,\n reset: mutation.reset,\n };\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -270,8 +270,16 @@ function useQuery(def, options) {
|
|
|
270
270
|
{
|
|
271
271
|
isLoading: query2.isLoading,
|
|
272
272
|
isFetching: query2.isFetching,
|
|
273
|
+
isSuccess: query2.isSuccess,
|
|
273
274
|
isError: query2.isError,
|
|
275
|
+
isPending: query2.isPending,
|
|
276
|
+
status: query2.status,
|
|
274
277
|
error: query2.error,
|
|
278
|
+
dataUpdatedAt: query2.dataUpdatedAt,
|
|
279
|
+
errorUpdatedAt: query2.errorUpdatedAt,
|
|
280
|
+
failureCount: query2.failureCount,
|
|
281
|
+
isStale: query2.isStale,
|
|
282
|
+
isPlaceholderData: query2.isPlaceholderData,
|
|
275
283
|
refetch: query2.refetch
|
|
276
284
|
}
|
|
277
285
|
];
|
|
@@ -317,8 +325,16 @@ function useQuery(def, options) {
|
|
|
317
325
|
{
|
|
318
326
|
isLoading: infiniteQuery.isLoading,
|
|
319
327
|
isFetching: infiniteQuery.isFetching,
|
|
328
|
+
isSuccess: infiniteQuery.isSuccess,
|
|
320
329
|
isError: infiniteQuery.isError,
|
|
330
|
+
isPending: infiniteQuery.isPending,
|
|
331
|
+
status: infiniteQuery.status,
|
|
321
332
|
error: infiniteQuery.error,
|
|
333
|
+
dataUpdatedAt: infiniteQuery.dataUpdatedAt,
|
|
334
|
+
errorUpdatedAt: infiniteQuery.errorUpdatedAt,
|
|
335
|
+
failureCount: infiniteQuery.failureCount,
|
|
336
|
+
isStale: infiniteQuery.isStale,
|
|
337
|
+
isPlaceholderData: infiniteQuery.isPlaceholderData,
|
|
322
338
|
refetch: infiniteQuery.refetch
|
|
323
339
|
},
|
|
324
340
|
{
|
|
@@ -356,8 +372,16 @@ function useQuery(def, options) {
|
|
|
356
372
|
{
|
|
357
373
|
isLoading: query.isLoading,
|
|
358
374
|
isFetching: query.isFetching,
|
|
375
|
+
isSuccess: query.isSuccess,
|
|
359
376
|
isError: query.isError,
|
|
377
|
+
isPending: query.isPending,
|
|
378
|
+
status: query.status,
|
|
360
379
|
error: query.error,
|
|
380
|
+
dataUpdatedAt: query.dataUpdatedAt,
|
|
381
|
+
errorUpdatedAt: query.errorUpdatedAt,
|
|
382
|
+
failureCount: query.failureCount,
|
|
383
|
+
isStale: query.isStale,
|
|
384
|
+
isPlaceholderData: query.isPlaceholderData,
|
|
361
385
|
refetch: query.refetch
|
|
362
386
|
}
|
|
363
387
|
];
|
|
@@ -372,7 +396,7 @@ var BatchedCollectionChannel = class {
|
|
|
372
396
|
target: this.target,
|
|
373
397
|
action: "prepend",
|
|
374
398
|
data,
|
|
375
|
-
|
|
399
|
+
reconcile: options?.reconcile
|
|
376
400
|
});
|
|
377
401
|
return this;
|
|
378
402
|
}
|
|
@@ -381,7 +405,7 @@ var BatchedCollectionChannel = class {
|
|
|
381
405
|
target: this.target,
|
|
382
406
|
action: "append",
|
|
383
407
|
data,
|
|
384
|
-
|
|
408
|
+
reconcile: options?.reconcile
|
|
385
409
|
});
|
|
386
410
|
return this;
|
|
387
411
|
}
|
|
@@ -391,7 +415,7 @@ var BatchedCollectionChannel = class {
|
|
|
391
415
|
action: "update",
|
|
392
416
|
id,
|
|
393
417
|
update: updateFn,
|
|
394
|
-
|
|
418
|
+
reconcile: options?.reconcile
|
|
395
419
|
});
|
|
396
420
|
return this;
|
|
397
421
|
}
|
|
@@ -414,7 +438,7 @@ var BatchedEntityChannel = class {
|
|
|
414
438
|
target: this.target,
|
|
415
439
|
action: "update",
|
|
416
440
|
update: updateFn,
|
|
417
|
-
|
|
441
|
+
reconcile: options?.reconcile
|
|
418
442
|
});
|
|
419
443
|
return this;
|
|
420
444
|
}
|
|
@@ -423,7 +447,7 @@ var BatchedEntityChannel = class {
|
|
|
423
447
|
target: this.target,
|
|
424
448
|
action: "replace",
|
|
425
449
|
data,
|
|
426
|
-
|
|
450
|
+
reconcile: options?.reconcile
|
|
427
451
|
});
|
|
428
452
|
return this;
|
|
429
453
|
}
|
|
@@ -470,7 +494,7 @@ function useMutation(def, options) {
|
|
|
470
494
|
onSuccess: (data, params, context) => {
|
|
471
495
|
if (context?.transactions) {
|
|
472
496
|
for (const tx of context.transactions) {
|
|
473
|
-
if (tx.
|
|
497
|
+
if (tx.reconcile && data) {
|
|
474
498
|
registry.applyUpdate(tx.target.name, "update", {
|
|
475
499
|
where: (item) => item._optimistic?.id === context?.optimisticId,
|
|
476
500
|
update: () => data
|