@tanstack/query-db-collection 0.2.15 → 0.2.17

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.
@@ -1,177 +1,31 @@
1
1
  import { QueryClient, QueryFunctionContext, QueryKey, QueryObserverOptions } from '@tanstack/query-core';
2
- import { CollectionConfig, DeleteMutationFn, InsertMutationFn, UpdateMutationFn, UtilsRecord } from '@tanstack/db';
2
+ import { BaseCollectionConfig, CollectionConfig, UtilsRecord } from '@tanstack/db';
3
3
  import { StandardSchemaV1 } from '@standard-schema/spec';
4
4
  export type { SyncOperation } from './manual-sync.js';
5
5
  type InferSchemaOutput<T> = T extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<T> extends object ? StandardSchemaV1.InferOutput<T> : Record<string, unknown> : Record<string, unknown>;
6
- type InferQueryFnOutput<TQueryFn> = TQueryFn extends (context: QueryFunctionContext<any>) => Promise<Array<infer TItem>> ? TItem extends object ? TItem : Record<string, unknown> : Record<string, unknown>;
7
- type ResolveType<TExplicit extends object | unknown = unknown, TSchema extends StandardSchemaV1 = never, TQueryFn = unknown> = unknown extends TExplicit ? [TSchema] extends [never] ? InferQueryFnOutput<TQueryFn> : InferSchemaOutput<TSchema> : TExplicit;
6
+ type InferSchemaInput<T> = T extends StandardSchemaV1 ? StandardSchemaV1.InferInput<T> extends object ? StandardSchemaV1.InferInput<T> : Record<string, unknown> : Record<string, unknown>;
8
7
  /**
9
8
  * Configuration options for creating a Query Collection
10
- * @template TExplicit - The explicit type of items stored in the collection (highest priority)
11
- * @template TSchema - The schema type for validation and type inference (second priority)
12
- * @template TQueryFn - The queryFn type for inferring return type (third priority)
9
+ * @template T - The explicit type of items stored in the collection
10
+ * @template TQueryFn - The queryFn type
13
11
  * @template TError - The type of errors that can occur during queries
14
12
  * @template TQueryKey - The type of the query key
13
+ * @template TKey - The type of the item keys
14
+ * @template TSchema - The schema type for validation
15
15
  */
16
- export interface QueryCollectionConfig<TExplicit extends object = object, TSchema extends StandardSchemaV1 = never, TQueryFn extends (context: QueryFunctionContext<any>) => Promise<Array<any>> = (context: QueryFunctionContext<any>) => Promise<Array<any>>, TError = unknown, TQueryKey extends QueryKey = QueryKey> {
16
+ export interface QueryCollectionConfig<T extends object = object, TQueryFn extends (context: QueryFunctionContext<any>) => Promise<Array<any>> = (context: QueryFunctionContext<any>) => Promise<Array<any>>, TError = unknown, TQueryKey extends QueryKey = QueryKey, TKey extends string | number = string | number, TSchema extends StandardSchemaV1 = never> extends BaseCollectionConfig<T, TKey, TSchema> {
17
17
  /** The query key used by TanStack Query to identify this query */
18
18
  queryKey: TQueryKey;
19
19
  /** Function that fetches data from the server. Must return the complete collection state */
20
- queryFn: TQueryFn extends (context: QueryFunctionContext<TQueryKey>) => Promise<Array<any>> ? TQueryFn : (context: QueryFunctionContext<TQueryKey>) => Promise<Array<ResolveType<TExplicit, TSchema, TQueryFn>>>;
20
+ queryFn: TQueryFn extends (context: QueryFunctionContext<TQueryKey>) => Promise<Array<any>> ? TQueryFn : (context: QueryFunctionContext<TQueryKey>) => Promise<Array<T>>;
21
21
  /** The TanStack Query client instance */
22
22
  queryClient: QueryClient;
23
23
  /** Whether the query should automatically run (default: true) */
24
24
  enabled?: boolean;
25
- refetchInterval?: QueryObserverOptions<Array<ResolveType<TExplicit, TSchema, TQueryFn>>, TError, Array<ResolveType<TExplicit, TSchema, TQueryFn>>, Array<ResolveType<TExplicit, TSchema, TQueryFn>>, TQueryKey>[`refetchInterval`];
26
- retry?: QueryObserverOptions<Array<ResolveType<TExplicit, TSchema, TQueryFn>>, TError, Array<ResolveType<TExplicit, TSchema, TQueryFn>>, Array<ResolveType<TExplicit, TSchema, TQueryFn>>, TQueryKey>[`retry`];
27
- retryDelay?: QueryObserverOptions<Array<ResolveType<TExplicit, TSchema, TQueryFn>>, TError, Array<ResolveType<TExplicit, TSchema, TQueryFn>>, Array<ResolveType<TExplicit, TSchema, TQueryFn>>, TQueryKey>[`retryDelay`];
28
- staleTime?: QueryObserverOptions<Array<ResolveType<TExplicit, TSchema, TQueryFn>>, TError, Array<ResolveType<TExplicit, TSchema, TQueryFn>>, Array<ResolveType<TExplicit, TSchema, TQueryFn>>, TQueryKey>[`staleTime`];
29
- /** Unique identifier for the collection */
30
- id?: string;
31
- /** Function to extract the unique key from an item */
32
- getKey: CollectionConfig<ResolveType<TExplicit, TSchema, TQueryFn>>[`getKey`];
33
- /** Schema for validating items */
34
- schema?: TSchema;
35
- sync?: CollectionConfig<ResolveType<TExplicit, TSchema, TQueryFn>>[`sync`];
36
- startSync?: CollectionConfig<ResolveType<TExplicit, TSchema, TQueryFn>>[`startSync`];
37
- /**
38
- * Optional asynchronous handler function called before an insert operation
39
- * @param params Object containing transaction and collection information
40
- * @returns Promise resolving to void or { refetch?: boolean } to control refetching
41
- * @example
42
- * // Basic query collection insert handler
43
- * onInsert: async ({ transaction }) => {
44
- * const newItem = transaction.mutations[0].modified
45
- * await api.createTodo(newItem)
46
- * // Automatically refetches query after insert
47
- * }
48
- *
49
- * @example
50
- * // Insert handler with refetch control
51
- * onInsert: async ({ transaction }) => {
52
- * const newItem = transaction.mutations[0].modified
53
- * await api.createTodo(newItem)
54
- * return { refetch: false } // Skip automatic refetch
55
- * }
56
- *
57
- * @example
58
- * // Insert handler with multiple items
59
- * onInsert: async ({ transaction }) => {
60
- * const items = transaction.mutations.map(m => m.modified)
61
- * await api.createTodos(items)
62
- * // Will refetch query to get updated data
63
- * }
64
- *
65
- * @example
66
- * // Insert handler with error handling
67
- * onInsert: async ({ transaction }) => {
68
- * try {
69
- * const newItem = transaction.mutations[0].modified
70
- * await api.createTodo(newItem)
71
- * } catch (error) {
72
- * console.error('Insert failed:', error)
73
- * throw error // Transaction will rollback optimistic changes
74
- * }
75
- * }
76
- */
77
- onInsert?: InsertMutationFn<ResolveType<TExplicit, TSchema, TQueryFn>>;
78
- /**
79
- * Optional asynchronous handler function called before an update operation
80
- * @param params Object containing transaction and collection information
81
- * @returns Promise resolving to void or { refetch?: boolean } to control refetching
82
- * @example
83
- * // Basic query collection update handler
84
- * onUpdate: async ({ transaction }) => {
85
- * const mutation = transaction.mutations[0]
86
- * await api.updateTodo(mutation.original.id, mutation.changes)
87
- * // Automatically refetches query after update
88
- * }
89
- *
90
- * @example
91
- * // Update handler with multiple items
92
- * onUpdate: async ({ transaction }) => {
93
- * const updates = transaction.mutations.map(m => ({
94
- * id: m.key,
95
- * changes: m.changes
96
- * }))
97
- * await api.updateTodos(updates)
98
- * // Will refetch query to get updated data
99
- * }
100
- *
101
- * @example
102
- * // Update handler with manual refetch
103
- * onUpdate: async ({ transaction, collection }) => {
104
- * const mutation = transaction.mutations[0]
105
- * await api.updateTodo(mutation.original.id, mutation.changes)
106
- *
107
- * // Manually trigger refetch
108
- * await collection.utils.refetch()
109
- *
110
- * return { refetch: false } // Skip automatic refetch
111
- * }
112
- *
113
- * @example
114
- * // Update handler with related collection refetch
115
- * onUpdate: async ({ transaction, collection }) => {
116
- * const mutation = transaction.mutations[0]
117
- * await api.updateTodo(mutation.original.id, mutation.changes)
118
- *
119
- * // Refetch related collections when this item changes
120
- * await Promise.all([
121
- * collection.utils.refetch(), // Refetch this collection
122
- * usersCollection.utils.refetch(), // Refetch users
123
- * tagsCollection.utils.refetch() // Refetch tags
124
- * ])
125
- *
126
- * return { refetch: false } // Skip automatic refetch since we handled it manually
127
- * }
128
- */
129
- onUpdate?: UpdateMutationFn<ResolveType<TExplicit, TSchema, TQueryFn>>;
130
- /**
131
- * Optional asynchronous handler function called before a delete operation
132
- * @param params Object containing transaction and collection information
133
- * @returns Promise resolving to void or { refetch?: boolean } to control refetching
134
- * @example
135
- * // Basic query collection delete handler
136
- * onDelete: async ({ transaction }) => {
137
- * const mutation = transaction.mutations[0]
138
- * await api.deleteTodo(mutation.original.id)
139
- * // Automatically refetches query after delete
140
- * }
141
- *
142
- * @example
143
- * // Delete handler with refetch control
144
- * onDelete: async ({ transaction }) => {
145
- * const mutation = transaction.mutations[0]
146
- * await api.deleteTodo(mutation.original.id)
147
- * return { refetch: false } // Skip automatic refetch
148
- * }
149
- *
150
- * @example
151
- * // Delete handler with multiple items
152
- * onDelete: async ({ transaction }) => {
153
- * const keysToDelete = transaction.mutations.map(m => m.key)
154
- * await api.deleteTodos(keysToDelete)
155
- * // Will refetch query to get updated data
156
- * }
157
- *
158
- * @example
159
- * // Delete handler with related collection refetch
160
- * onDelete: async ({ transaction, collection }) => {
161
- * const mutation = transaction.mutations[0]
162
- * await api.deleteTodo(mutation.original.id)
163
- *
164
- * // Refetch related collections when this item is deleted
165
- * await Promise.all([
166
- * collection.utils.refetch(), // Refetch this collection
167
- * usersCollection.utils.refetch(), // Refetch users
168
- * projectsCollection.utils.refetch() // Refetch projects
169
- * ])
170
- *
171
- * return { refetch: false } // Skip automatic refetch since we handled it manually
172
- * }
173
- */
174
- onDelete?: DeleteMutationFn<ResolveType<TExplicit, TSchema, TQueryFn>>;
25
+ refetchInterval?: QueryObserverOptions<Array<T>, TError, Array<T>, Array<T>, TQueryKey>[`refetchInterval`];
26
+ retry?: QueryObserverOptions<Array<T>, TError, Array<T>, Array<T>, TQueryKey>[`retry`];
27
+ retryDelay?: QueryObserverOptions<Array<T>, TError, Array<T>, Array<T>, TQueryKey>[`retryDelay`];
28
+ staleTime?: QueryObserverOptions<Array<T>, TError, Array<T>, Array<T>, TQueryKey>[`staleTime`];
175
29
  /**
176
30
  * Metadata to pass to the query.
177
31
  * Available in queryFn via context.meta
@@ -197,15 +51,18 @@ export interface QueryCollectionConfig<TExplicit extends object = object, TSchem
197
51
  /**
198
52
  * Type for the refetch utility function
199
53
  */
200
- export type RefetchFn = () => Promise<void>;
54
+ export type RefetchFn = (opts?: {
55
+ throwOnError?: boolean;
56
+ }) => Promise<void>;
201
57
  /**
202
58
  * Utility methods available on Query Collections for direct writes and manual operations.
203
59
  * Direct writes bypass the normal query/mutation flow and write directly to the synced data store.
204
60
  * @template TItem - The type of items stored in the collection
205
61
  * @template TKey - The type of the item keys
206
62
  * @template TInsertInput - The type accepted for insert operations
63
+ * @template TError - The type of errors that can occur during queries
207
64
  */
208
- export interface QueryCollectionUtils<TItem extends object = Record<string, unknown>, TKey extends string | number = string | number, TInsertInput extends object = TItem> extends UtilsRecord {
65
+ export interface QueryCollectionUtils<TItem extends object = Record<string, unknown>, TKey extends string | number = string | number, TInsertInput extends object = TItem, TError = unknown> extends UtilsRecord {
209
66
  /** Manually trigger a refetch of the query */
210
67
  refetch: RefetchFn;
211
68
  /** Insert one or more items directly into the synced data store without triggering a query refetch or optimistic update */
@@ -218,24 +75,34 @@ export interface QueryCollectionUtils<TItem extends object = Record<string, unkn
218
75
  writeUpsert: (data: Partial<TItem> | Array<Partial<TItem>>) => void;
219
76
  /** Execute multiple write operations as a single atomic batch to the synced data store */
220
77
  writeBatch: (callback: () => void) => void;
78
+ /** Get the last error encountered by the query (if any); reset on success */
79
+ lastError: () => TError | undefined;
80
+ /** Check if the collection is in an error state */
81
+ isError: () => boolean;
82
+ /**
83
+ * Get the number of consecutive sync failures.
84
+ * Incremented only when query fails completely (not per retry attempt); reset on success.
85
+ */
86
+ errorCount: () => number;
87
+ /**
88
+ * Clear the error state and trigger a refetch of the query
89
+ * @returns Promise that resolves when the refetch completes successfully
90
+ * @throws Error if the refetch fails
91
+ */
92
+ clearError: () => Promise<void>;
221
93
  }
222
94
  /**
223
95
  * Creates query collection options for use with a standard Collection.
224
96
  * This integrates TanStack Query with TanStack DB for automatic synchronization.
225
97
  *
226
98
  * Supports automatic type inference following the priority order:
227
- * 1. Explicit type (highest priority)
228
- * 2. Schema inference (second priority)
229
- * 3. QueryFn return type inference (third priority)
230
- * 4. Fallback to Record<string, unknown>
99
+ * 1. Schema inference (highest priority)
100
+ * 2. QueryFn return type inference (second priority)
231
101
  *
232
- * @template TExplicit - The explicit type of items in the collection (highest priority)
233
- * @template TSchema - The schema type for validation and type inference (second priority)
234
- * @template TQueryFn - The queryFn type for inferring return type (third priority)
102
+ * @template T - Type of the schema if a schema is provided otherwise it is the type of the values returned by the queryFn
235
103
  * @template TError - The type of errors that can occur during queries
236
104
  * @template TQueryKey - The type of the query key
237
105
  * @template TKey - The type of the item keys
238
- * @template TInsertInput - The type accepted for insert operations
239
106
  * @param config - Configuration options for the Query collection
240
107
  * @returns Collection options with utilities for direct writes and manual operations
241
108
  *
@@ -254,7 +121,7 @@ export interface QueryCollectionUtils<TItem extends object = Record<string, unkn
254
121
  * )
255
122
  *
256
123
  * @example
257
- * // Explicit type (highest priority)
124
+ * // Explicit type
258
125
  * const todosCollection = createCollection<Todo>(
259
126
  * queryCollectionOptions({
260
127
  * queryKey: ['todos'],
@@ -265,7 +132,7 @@ export interface QueryCollectionUtils<TItem extends object = Record<string, unkn
265
132
  * )
266
133
  *
267
134
  * @example
268
- * // Schema inference (second priority)
135
+ * // Schema inference
269
136
  * const todosCollection = createCollection(
270
137
  * queryCollectionOptions({
271
138
  * queryKey: ['todos'],
@@ -296,6 +163,15 @@ export interface QueryCollectionUtils<TItem extends object = Record<string, unkn
296
163
  * })
297
164
  * )
298
165
  */
299
- export declare function queryCollectionOptions<TExplicit extends object = object, TSchema extends StandardSchemaV1 = never, TQueryFn extends (context: QueryFunctionContext<any>) => Promise<Array<any>> = (context: QueryFunctionContext<any>) => Promise<Array<any>>, TError = unknown, TQueryKey extends QueryKey = QueryKey, TKey extends string | number = string | number, TInsertInput extends object = ResolveType<TExplicit, TSchema, TQueryFn>>(config: QueryCollectionConfig<TExplicit, TSchema, TQueryFn, TError, TQueryKey>): CollectionConfig<ResolveType<TExplicit, TSchema, TQueryFn>> & {
300
- utils: QueryCollectionUtils<ResolveType<TExplicit, TSchema, TQueryFn>, TKey, TInsertInput>;
166
+ export declare function queryCollectionOptions<T extends StandardSchemaV1, TError = unknown, TQueryKey extends QueryKey = QueryKey, TKey extends string | number = string | number>(config: QueryCollectionConfig<InferSchemaOutput<T>, (context: QueryFunctionContext<any>) => Promise<Array<InferSchemaOutput<T>>>, TError, TQueryKey, TKey, T> & {
167
+ schema: T;
168
+ }): CollectionConfig<InferSchemaOutput<T>, TKey, T> & {
169
+ schema: T;
170
+ utils: QueryCollectionUtils<InferSchemaOutput<T>, TKey, InferSchemaInput<T>, TError>;
171
+ };
172
+ export declare function queryCollectionOptions<T extends object, TError = unknown, TQueryKey extends QueryKey = QueryKey, TKey extends string | number = string | number>(config: QueryCollectionConfig<T, (context: QueryFunctionContext<any>) => Promise<Array<T>>, TError, TQueryKey, TKey> & {
173
+ schema?: never;
174
+ }): CollectionConfig<T, TKey> & {
175
+ schema?: never;
176
+ utils: QueryCollectionUtils<T, TKey, T, TError>;
301
177
  };
package/dist/esm/query.js CHANGED
@@ -30,6 +30,9 @@ function queryCollectionOptions(config) {
30
30
  if (!getKey) {
31
31
  throw new GetKeyRequiredError();
32
32
  }
33
+ let lastError;
34
+ let errorCount = 0;
35
+ let lastErrorUpdatedAt = 0;
33
36
  const internalSync = (params) => {
34
37
  const { begin, write, commit, markReady, collection } = params;
35
38
  const observerOptions = {
@@ -47,6 +50,8 @@ function queryCollectionOptions(config) {
47
50
  const localObserver = new QueryObserver(queryClient, observerOptions);
48
51
  const handleUpdate = (result) => {
49
52
  if (result.isSuccess) {
53
+ lastError = void 0;
54
+ errorCount = 0;
50
55
  const newItemsArray = result.data;
51
56
  if (!Array.isArray(newItemsArray) || newItemsArray.some((item) => typeof item !== `object`)) {
52
57
  console.error(
@@ -90,6 +95,11 @@ function queryCollectionOptions(config) {
90
95
  commit();
91
96
  markReady();
92
97
  } else if (result.isError) {
98
+ if (result.errorUpdatedAt !== lastErrorUpdatedAt) {
99
+ lastError = result.error;
100
+ errorCount++;
101
+ lastErrorUpdatedAt = result.errorUpdatedAt;
102
+ }
93
103
  console.error(
94
104
  `[QueryCollection] Error observing query ${String(queryKey)}:`,
95
105
  result.error
@@ -105,10 +115,15 @@ function queryCollectionOptions(config) {
105
115
  queryClient.removeQueries({ queryKey });
106
116
  };
107
117
  };
108
- const refetch = async () => {
109
- return queryClient.refetchQueries({
110
- queryKey
111
- });
118
+ const refetch = (opts) => {
119
+ return queryClient.refetchQueries(
120
+ {
121
+ queryKey
122
+ },
123
+ {
124
+ throwOnError: opts == null ? void 0 : opts.throwOnError
125
+ }
126
+ );
112
127
  };
113
128
  let writeContext = null;
114
129
  const enhancedInternalSync = (params) => {
@@ -160,7 +175,16 @@ function queryCollectionOptions(config) {
160
175
  onDelete: wrappedOnDelete,
161
176
  utils: {
162
177
  refetch,
163
- ...writeUtils
178
+ ...writeUtils,
179
+ lastError: () => lastError,
180
+ isError: () => !!lastError,
181
+ errorCount: () => errorCount,
182
+ clearError: () => {
183
+ lastError = void 0;
184
+ errorCount = 0;
185
+ lastErrorUpdatedAt = 0;
186
+ return refetch({ throwOnError: true });
187
+ }
164
188
  }
165
189
  };
166
190
  }
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","sources":["../../src/query.ts"],"sourcesContent":["import { QueryObserver } from \"@tanstack/query-core\"\nimport {\n GetKeyRequiredError,\n QueryClientRequiredError,\n QueryFnRequiredError,\n QueryKeyRequiredError,\n} from \"./errors\"\nimport { createWriteUtils } from \"./manual-sync\"\nimport type {\n QueryClient,\n QueryFunctionContext,\n QueryKey,\n QueryObserverOptions,\n} from \"@tanstack/query-core\"\nimport type {\n ChangeMessage,\n CollectionConfig,\n DeleteMutationFn,\n DeleteMutationFnParams,\n InsertMutationFn,\n InsertMutationFnParams,\n SyncConfig,\n UpdateMutationFn,\n UpdateMutationFnParams,\n UtilsRecord,\n} from \"@tanstack/db\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\n\n// Re-export for external use\nexport type { SyncOperation } from \"./manual-sync\"\n\n// Schema output type inference helper (matches electric.ts pattern)\ntype InferSchemaOutput<T> = T extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<T> extends object\n ? StandardSchemaV1.InferOutput<T>\n : Record<string, unknown>\n : Record<string, unknown>\n\n// QueryFn return type inference helper\ntype InferQueryFnOutput<TQueryFn> = TQueryFn extends (\n context: QueryFunctionContext<any>\n) => Promise<Array<infer TItem>>\n ? TItem extends object\n ? TItem\n : Record<string, unknown>\n : Record<string, unknown>\n\n// Type resolution system with priority order (matches electric.ts pattern)\ntype ResolveType<\n TExplicit extends object | unknown = unknown,\n TSchema extends StandardSchemaV1 = never,\n TQueryFn = unknown,\n> = unknown extends TExplicit\n ? [TSchema] extends [never]\n ? InferQueryFnOutput<TQueryFn>\n : InferSchemaOutput<TSchema>\n : TExplicit\n\n/**\n * Configuration options for creating a Query Collection\n * @template TExplicit - The explicit type of items stored in the collection (highest priority)\n * @template TSchema - The schema type for validation and type inference (second priority)\n * @template TQueryFn - The queryFn type for inferring return type (third priority)\n * @template TError - The type of errors that can occur during queries\n * @template TQueryKey - The type of the query key\n */\nexport interface QueryCollectionConfig<\n TExplicit extends object = object,\n TSchema extends StandardSchemaV1 = never,\n TQueryFn extends (\n context: QueryFunctionContext<any>\n ) => Promise<Array<any>> = (\n context: QueryFunctionContext<any>\n ) => Promise<Array<any>>,\n TError = unknown,\n TQueryKey extends QueryKey = QueryKey,\n> {\n /** The query key used by TanStack Query to identify this query */\n queryKey: TQueryKey\n /** Function that fetches data from the server. Must return the complete collection state */\n queryFn: TQueryFn extends (\n context: QueryFunctionContext<TQueryKey>\n ) => Promise<Array<any>>\n ? TQueryFn\n : (\n context: QueryFunctionContext<TQueryKey>\n ) => Promise<Array<ResolveType<TExplicit, TSchema, TQueryFn>>>\n\n /** The TanStack Query client instance */\n queryClient: QueryClient\n\n // Query-specific options\n /** Whether the query should automatically run (default: true) */\n enabled?: boolean\n refetchInterval?: QueryObserverOptions<\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n TError,\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n TQueryKey\n >[`refetchInterval`]\n retry?: QueryObserverOptions<\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n TError,\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n TQueryKey\n >[`retry`]\n retryDelay?: QueryObserverOptions<\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n TError,\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n TQueryKey\n >[`retryDelay`]\n staleTime?: QueryObserverOptions<\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n TError,\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n Array<ResolveType<TExplicit, TSchema, TQueryFn>>,\n TQueryKey\n >[`staleTime`]\n\n // Standard Collection configuration properties\n /** Unique identifier for the collection */\n id?: string\n /** Function to extract the unique key from an item */\n getKey: CollectionConfig<ResolveType<TExplicit, TSchema, TQueryFn>>[`getKey`]\n /** Schema for validating items */\n schema?: TSchema\n sync?: CollectionConfig<ResolveType<TExplicit, TSchema, TQueryFn>>[`sync`]\n startSync?: CollectionConfig<\n ResolveType<TExplicit, TSchema, TQueryFn>\n >[`startSync`]\n\n // Direct persistence handlers\n /**\n * Optional asynchronous handler function called before an insert operation\n * @param params Object containing transaction and collection information\n * @returns Promise resolving to void or { refetch?: boolean } to control refetching\n * @example\n * // Basic query collection insert handler\n * onInsert: async ({ transaction }) => {\n * const newItem = transaction.mutations[0].modified\n * await api.createTodo(newItem)\n * // Automatically refetches query after insert\n * }\n *\n * @example\n * // Insert handler with refetch control\n * onInsert: async ({ transaction }) => {\n * const newItem = transaction.mutations[0].modified\n * await api.createTodo(newItem)\n * return { refetch: false } // Skip automatic refetch\n * }\n *\n * @example\n * // Insert handler with multiple items\n * onInsert: async ({ transaction }) => {\n * const items = transaction.mutations.map(m => m.modified)\n * await api.createTodos(items)\n * // Will refetch query to get updated data\n * }\n *\n * @example\n * // Insert handler with error handling\n * onInsert: async ({ transaction }) => {\n * try {\n * const newItem = transaction.mutations[0].modified\n * await api.createTodo(newItem)\n * } catch (error) {\n * console.error('Insert failed:', error)\n * throw error // Transaction will rollback optimistic changes\n * }\n * }\n */\n onInsert?: InsertMutationFn<ResolveType<TExplicit, TSchema, TQueryFn>>\n\n /**\n * Optional asynchronous handler function called before an update operation\n * @param params Object containing transaction and collection information\n * @returns Promise resolving to void or { refetch?: boolean } to control refetching\n * @example\n * // Basic query collection update handler\n * onUpdate: async ({ transaction }) => {\n * const mutation = transaction.mutations[0]\n * await api.updateTodo(mutation.original.id, mutation.changes)\n * // Automatically refetches query after update\n * }\n *\n * @example\n * // Update handler with multiple items\n * onUpdate: async ({ transaction }) => {\n * const updates = transaction.mutations.map(m => ({\n * id: m.key,\n * changes: m.changes\n * }))\n * await api.updateTodos(updates)\n * // Will refetch query to get updated data\n * }\n *\n * @example\n * // Update handler with manual refetch\n * onUpdate: async ({ transaction, collection }) => {\n * const mutation = transaction.mutations[0]\n * await api.updateTodo(mutation.original.id, mutation.changes)\n *\n * // Manually trigger refetch\n * await collection.utils.refetch()\n *\n * return { refetch: false } // Skip automatic refetch\n * }\n *\n * @example\n * // Update handler with related collection refetch\n * onUpdate: async ({ transaction, collection }) => {\n * const mutation = transaction.mutations[0]\n * await api.updateTodo(mutation.original.id, mutation.changes)\n *\n * // Refetch related collections when this item changes\n * await Promise.all([\n * collection.utils.refetch(), // Refetch this collection\n * usersCollection.utils.refetch(), // Refetch users\n * tagsCollection.utils.refetch() // Refetch tags\n * ])\n *\n * return { refetch: false } // Skip automatic refetch since we handled it manually\n * }\n */\n onUpdate?: UpdateMutationFn<ResolveType<TExplicit, TSchema, TQueryFn>>\n\n /**\n * Optional asynchronous handler function called before a delete operation\n * @param params Object containing transaction and collection information\n * @returns Promise resolving to void or { refetch?: boolean } to control refetching\n * @example\n * // Basic query collection delete handler\n * onDelete: async ({ transaction }) => {\n * const mutation = transaction.mutations[0]\n * await api.deleteTodo(mutation.original.id)\n * // Automatically refetches query after delete\n * }\n *\n * @example\n * // Delete handler with refetch control\n * onDelete: async ({ transaction }) => {\n * const mutation = transaction.mutations[0]\n * await api.deleteTodo(mutation.original.id)\n * return { refetch: false } // Skip automatic refetch\n * }\n *\n * @example\n * // Delete handler with multiple items\n * onDelete: async ({ transaction }) => {\n * const keysToDelete = transaction.mutations.map(m => m.key)\n * await api.deleteTodos(keysToDelete)\n * // Will refetch query to get updated data\n * }\n *\n * @example\n * // Delete handler with related collection refetch\n * onDelete: async ({ transaction, collection }) => {\n * const mutation = transaction.mutations[0]\n * await api.deleteTodo(mutation.original.id)\n *\n * // Refetch related collections when this item is deleted\n * await Promise.all([\n * collection.utils.refetch(), // Refetch this collection\n * usersCollection.utils.refetch(), // Refetch users\n * projectsCollection.utils.refetch() // Refetch projects\n * ])\n *\n * return { refetch: false } // Skip automatic refetch since we handled it manually\n * }\n */\n onDelete?: DeleteMutationFn<ResolveType<TExplicit, TSchema, TQueryFn>>\n\n /**\n * Metadata to pass to the query.\n * Available in queryFn via context.meta\n *\n * @example\n * // Using meta for error context\n * queryFn: async (context) => {\n * try {\n * return await api.getTodos(userId)\n * } catch (error) {\n * // Use meta for better error messages\n * throw new Error(\n * context.meta?.errorMessage || 'Failed to load todos'\n * )\n * }\n * },\n * meta: {\n * errorMessage: `Failed to load todos for user ${userId}`\n * }\n */\n meta?: Record<string, unknown>\n}\n\n/**\n * Type for the refetch utility function\n */\nexport type RefetchFn = () => Promise<void>\n\n/**\n * Utility methods available on Query Collections for direct writes and manual operations.\n * Direct writes bypass the normal query/mutation flow and write directly to the synced data store.\n * @template TItem - The type of items stored in the collection\n * @template TKey - The type of the item keys\n * @template TInsertInput - The type accepted for insert operations\n */\nexport interface QueryCollectionUtils<\n TItem extends object = Record<string, unknown>,\n TKey extends string | number = string | number,\n TInsertInput extends object = TItem,\n> extends UtilsRecord {\n /** Manually trigger a refetch of the query */\n refetch: RefetchFn\n /** Insert one or more items directly into the synced data store without triggering a query refetch or optimistic update */\n writeInsert: (data: TInsertInput | Array<TInsertInput>) => void\n /** Update one or more items directly in the synced data store without triggering a query refetch or optimistic update */\n writeUpdate: (updates: Partial<TItem> | Array<Partial<TItem>>) => void\n /** Delete one or more items directly from the synced data store without triggering a query refetch or optimistic update */\n writeDelete: (keys: TKey | Array<TKey>) => void\n /** Insert or update one or more items directly in the synced data store without triggering a query refetch or optimistic update */\n writeUpsert: (data: Partial<TItem> | Array<Partial<TItem>>) => void\n /** Execute multiple write operations as a single atomic batch to the synced data store */\n writeBatch: (callback: () => void) => void\n}\n\n/**\n * Creates query collection options for use with a standard Collection.\n * This integrates TanStack Query with TanStack DB for automatic synchronization.\n *\n * Supports automatic type inference following the priority order:\n * 1. Explicit type (highest priority)\n * 2. Schema inference (second priority)\n * 3. QueryFn return type inference (third priority)\n * 4. Fallback to Record<string, unknown>\n *\n * @template TExplicit - The explicit type of items in the collection (highest priority)\n * @template TSchema - The schema type for validation and type inference (second priority)\n * @template TQueryFn - The queryFn type for inferring return type (third priority)\n * @template TError - The type of errors that can occur during queries\n * @template TQueryKey - The type of the query key\n * @template TKey - The type of the item keys\n * @template TInsertInput - The type accepted for insert operations\n * @param config - Configuration options for the Query collection\n * @returns Collection options with utilities for direct writes and manual operations\n *\n * @example\n * // Type inferred from queryFn return type (NEW!)\n * const todosCollection = createCollection(\n * queryCollectionOptions({\n * queryKey: ['todos'],\n * queryFn: async () => {\n * const response = await fetch('/api/todos')\n * return response.json() as Todo[] // Type automatically inferred!\n * },\n * queryClient,\n * getKey: (item) => item.id, // item is typed as Todo\n * })\n * )\n *\n * @example\n * // Explicit type (highest priority)\n * const todosCollection = createCollection<Todo>(\n * queryCollectionOptions({\n * queryKey: ['todos'],\n * queryFn: async () => fetch('/api/todos').then(r => r.json()),\n * queryClient,\n * getKey: (item) => item.id,\n * })\n * )\n *\n * @example\n * // Schema inference (second priority)\n * const todosCollection = createCollection(\n * queryCollectionOptions({\n * queryKey: ['todos'],\n * queryFn: async () => fetch('/api/todos').then(r => r.json()),\n * queryClient,\n * schema: todoSchema, // Type inferred from schema\n * getKey: (item) => item.id,\n * })\n * )\n *\n * @example\n * // With persistence handlers\n * const todosCollection = createCollection(\n * queryCollectionOptions({\n * queryKey: ['todos'],\n * queryFn: fetchTodos,\n * queryClient,\n * getKey: (item) => item.id,\n * onInsert: async ({ transaction }) => {\n * await api.createTodos(transaction.mutations.map(m => m.modified))\n * },\n * onUpdate: async ({ transaction }) => {\n * await api.updateTodos(transaction.mutations)\n * },\n * onDelete: async ({ transaction }) => {\n * await api.deleteTodos(transaction.mutations.map(m => m.key))\n * }\n * })\n * )\n */\nexport function queryCollectionOptions<\n TExplicit extends object = object,\n TSchema extends StandardSchemaV1 = never,\n TQueryFn extends (\n context: QueryFunctionContext<any>\n ) => Promise<Array<any>> = (\n context: QueryFunctionContext<any>\n ) => Promise<Array<any>>,\n TError = unknown,\n TQueryKey extends QueryKey = QueryKey,\n TKey extends string | number = string | number,\n TInsertInput extends object = ResolveType<TExplicit, TSchema, TQueryFn>,\n>(\n config: QueryCollectionConfig<TExplicit, TSchema, TQueryFn, TError, TQueryKey>\n): CollectionConfig<ResolveType<TExplicit, TSchema, TQueryFn>> & {\n utils: QueryCollectionUtils<\n ResolveType<TExplicit, TSchema, TQueryFn>,\n TKey,\n TInsertInput\n >\n} {\n type TItem = ResolveType<TExplicit, TSchema, TQueryFn>\n\n const {\n queryKey,\n queryFn,\n queryClient,\n enabled,\n refetchInterval,\n retry,\n retryDelay,\n staleTime,\n getKey,\n onInsert,\n onUpdate,\n onDelete,\n meta,\n ...baseCollectionConfig\n } = config\n\n // Validate required parameters\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!queryKey) {\n throw new QueryKeyRequiredError()\n }\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!queryFn) {\n throw new QueryFnRequiredError()\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!queryClient) {\n throw new QueryClientRequiredError()\n }\n\n if (!getKey) {\n throw new GetKeyRequiredError()\n }\n\n const internalSync: SyncConfig<TItem>[`sync`] = (params) => {\n const { begin, write, commit, markReady, collection } = params\n\n const observerOptions: QueryObserverOptions<\n Array<TItem>,\n TError,\n Array<TItem>,\n Array<TItem>,\n TQueryKey\n > = {\n queryKey: queryKey,\n queryFn: queryFn,\n meta: meta,\n enabled: enabled,\n refetchInterval: refetchInterval,\n retry: retry,\n retryDelay: retryDelay,\n staleTime: staleTime,\n structuralSharing: true,\n notifyOnChangeProps: `all`,\n }\n\n const localObserver = new QueryObserver<\n Array<TItem>,\n TError,\n Array<TItem>,\n Array<TItem>,\n TQueryKey\n >(queryClient, observerOptions)\n\n type UpdateHandler = Parameters<typeof localObserver.subscribe>[0]\n const handleUpdate: UpdateHandler = (result) => {\n if (result.isSuccess) {\n const newItemsArray = result.data\n\n if (\n !Array.isArray(newItemsArray) ||\n newItemsArray.some((item) => typeof item !== `object`)\n ) {\n console.error(\n `[QueryCollection] queryFn did not return an array of objects. Skipping update.`,\n newItemsArray\n )\n return\n }\n\n const currentSyncedItems = new Map(collection.syncedData)\n const newItemsMap = new Map<string | number, TItem>()\n newItemsArray.forEach((item) => {\n const key = getKey(item)\n newItemsMap.set(key, item)\n })\n\n begin()\n\n // Helper function for shallow equality check of objects\n const shallowEqual = (\n obj1: Record<string, any>,\n obj2: Record<string, any>\n ): boolean => {\n // Get all keys from both objects\n const keys1 = Object.keys(obj1)\n const keys2 = Object.keys(obj2)\n\n // If number of keys is different, objects are not equal\n if (keys1.length !== keys2.length) return false\n\n // Check if all keys in obj1 have the same values in obj2\n return keys1.every((key) => {\n // Skip comparing functions and complex objects deeply\n if (typeof obj1[key] === `function`) return true\n return obj1[key] === obj2[key]\n })\n }\n\n currentSyncedItems.forEach((oldItem, key) => {\n const newItem = newItemsMap.get(key)\n if (!newItem) {\n write({ type: `delete`, value: oldItem })\n } else if (\n !shallowEqual(\n oldItem as Record<string, any>,\n newItem as Record<string, any>\n )\n ) {\n // Only update if there are actual differences in the properties\n write({ type: `update`, value: newItem })\n }\n })\n\n newItemsMap.forEach((newItem, key) => {\n if (!currentSyncedItems.has(key)) {\n write({ type: `insert`, value: newItem })\n }\n })\n\n commit()\n\n // Mark collection as ready after first successful query result\n markReady()\n } else if (result.isError) {\n console.error(\n `[QueryCollection] Error observing query ${String(queryKey)}:`,\n result.error\n )\n\n // Mark collection as ready even on error to avoid blocking apps\n markReady()\n }\n }\n\n const actualUnsubscribeFn = localObserver.subscribe(handleUpdate)\n\n // Ensure we process any existing query data (QueryObserver doesn't invoke its callback automatically with initial\n // state)\n handleUpdate(localObserver.getCurrentResult())\n\n return async () => {\n actualUnsubscribeFn()\n await queryClient.cancelQueries({ queryKey })\n queryClient.removeQueries({ queryKey })\n }\n }\n\n /**\n * Refetch the query data\n * @returns Promise that resolves when the refetch is complete\n */\n const refetch: RefetchFn = async (): Promise<void> => {\n return queryClient.refetchQueries({\n queryKey: queryKey,\n })\n }\n\n // Create write context for manual write operations\n let writeContext: {\n collection: any\n queryClient: QueryClient\n queryKey: Array<unknown>\n getKey: (item: TItem) => TKey\n begin: () => void\n write: (message: Omit<ChangeMessage<TItem>, `key`>) => void\n commit: () => void\n } | null = null\n\n // Enhanced internalSync that captures write functions for manual use\n const enhancedInternalSync: SyncConfig<TItem>[`sync`] = (params) => {\n const { begin, write, commit, collection } = params\n\n // Store references for manual write operations\n writeContext = {\n collection,\n queryClient,\n queryKey: queryKey as unknown as Array<unknown>,\n getKey: getKey as (item: TItem) => TKey,\n begin,\n write,\n commit,\n }\n\n // Call the original internalSync logic\n return internalSync(params)\n }\n\n // Create write utils using the manual-sync module\n const writeUtils = createWriteUtils<TItem, TKey, TInsertInput>(\n () => writeContext\n )\n\n // Create wrapper handlers for direct persistence operations that handle refetching\n const wrappedOnInsert = onInsert\n ? async (params: InsertMutationFnParams<TItem>) => {\n const handlerResult = (await onInsert(params)) ?? {}\n const shouldRefetch =\n (handlerResult as { refetch?: boolean }).refetch !== false\n\n if (shouldRefetch) {\n await refetch()\n }\n\n return handlerResult\n }\n : undefined\n\n const wrappedOnUpdate = onUpdate\n ? async (params: UpdateMutationFnParams<TItem>) => {\n const handlerResult = (await onUpdate(params)) ?? {}\n const shouldRefetch =\n (handlerResult as { refetch?: boolean }).refetch !== false\n\n if (shouldRefetch) {\n await refetch()\n }\n\n return handlerResult\n }\n : undefined\n\n const wrappedOnDelete = onDelete\n ? async (params: DeleteMutationFnParams<TItem>) => {\n const handlerResult = (await onDelete(params)) ?? {}\n const shouldRefetch =\n (handlerResult as { refetch?: boolean }).refetch !== false\n\n if (shouldRefetch) {\n await refetch()\n }\n\n return handlerResult\n }\n : undefined\n\n return {\n ...baseCollectionConfig,\n getKey,\n sync: { sync: enhancedInternalSync },\n onInsert: wrappedOnInsert,\n onUpdate: wrappedOnUpdate,\n onDelete: wrappedOnDelete,\n utils: {\n refetch,\n ...writeUtils,\n },\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"query.js","sources":["../../src/query.ts"],"sourcesContent":["import { QueryObserver } from \"@tanstack/query-core\"\nimport {\n GetKeyRequiredError,\n QueryClientRequiredError,\n QueryFnRequiredError,\n QueryKeyRequiredError,\n} from \"./errors\"\nimport { createWriteUtils } from \"./manual-sync\"\nimport type {\n QueryClient,\n QueryFunctionContext,\n QueryKey,\n QueryObserverOptions,\n} from \"@tanstack/query-core\"\nimport type {\n BaseCollectionConfig,\n ChangeMessage,\n CollectionConfig,\n DeleteMutationFnParams,\n InsertMutationFnParams,\n SyncConfig,\n UpdateMutationFnParams,\n UtilsRecord,\n} from \"@tanstack/db\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\n\n// Re-export for external use\nexport type { SyncOperation } from \"./manual-sync\"\n\n// Schema output type inference helper (matches electric.ts pattern)\ntype InferSchemaOutput<T> = T extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<T> extends object\n ? StandardSchemaV1.InferOutput<T>\n : Record<string, unknown>\n : Record<string, unknown>\n\n// Schema input type inference helper (matches electric.ts pattern)\ntype InferSchemaInput<T> = T extends StandardSchemaV1\n ? StandardSchemaV1.InferInput<T> extends object\n ? StandardSchemaV1.InferInput<T>\n : Record<string, unknown>\n : Record<string, unknown>\n\n/**\n * Configuration options for creating a Query Collection\n * @template T - The explicit type of items stored in the collection\n * @template TQueryFn - The queryFn type\n * @template TError - The type of errors that can occur during queries\n * @template TQueryKey - The type of the query key\n * @template TKey - The type of the item keys\n * @template TSchema - The schema type for validation\n */\nexport interface QueryCollectionConfig<\n T extends object = object,\n TQueryFn extends (\n context: QueryFunctionContext<any>\n ) => Promise<Array<any>> = (\n context: QueryFunctionContext<any>\n ) => Promise<Array<any>>,\n TError = unknown,\n TQueryKey extends QueryKey = QueryKey,\n TKey extends string | number = string | number,\n TSchema extends StandardSchemaV1 = never,\n> extends BaseCollectionConfig<T, TKey, TSchema> {\n /** The query key used by TanStack Query to identify this query */\n queryKey: TQueryKey\n /** Function that fetches data from the server. Must return the complete collection state */\n queryFn: TQueryFn extends (\n context: QueryFunctionContext<TQueryKey>\n ) => Promise<Array<any>>\n ? TQueryFn\n : (context: QueryFunctionContext<TQueryKey>) => Promise<Array<T>>\n\n /** The TanStack Query client instance */\n queryClient: QueryClient\n\n // Query-specific options\n /** Whether the query should automatically run (default: true) */\n enabled?: boolean\n refetchInterval?: QueryObserverOptions<\n Array<T>,\n TError,\n Array<T>,\n Array<T>,\n TQueryKey\n >[`refetchInterval`]\n retry?: QueryObserverOptions<\n Array<T>,\n TError,\n Array<T>,\n Array<T>,\n TQueryKey\n >[`retry`]\n retryDelay?: QueryObserverOptions<\n Array<T>,\n TError,\n Array<T>,\n Array<T>,\n TQueryKey\n >[`retryDelay`]\n staleTime?: QueryObserverOptions<\n Array<T>,\n TError,\n Array<T>,\n Array<T>,\n TQueryKey\n >[`staleTime`]\n\n /**\n * Metadata to pass to the query.\n * Available in queryFn via context.meta\n *\n * @example\n * // Using meta for error context\n * queryFn: async (context) => {\n * try {\n * return await api.getTodos(userId)\n * } catch (error) {\n * // Use meta for better error messages\n * throw new Error(\n * context.meta?.errorMessage || 'Failed to load todos'\n * )\n * }\n * },\n * meta: {\n * errorMessage: `Failed to load todos for user ${userId}`\n * }\n */\n meta?: Record<string, unknown>\n}\n\n/**\n * Type for the refetch utility function\n */\nexport type RefetchFn = (opts?: { throwOnError?: boolean }) => Promise<void>\n\n/**\n * Utility methods available on Query Collections for direct writes and manual operations.\n * Direct writes bypass the normal query/mutation flow and write directly to the synced data store.\n * @template TItem - The type of items stored in the collection\n * @template TKey - The type of the item keys\n * @template TInsertInput - The type accepted for insert operations\n * @template TError - The type of errors that can occur during queries\n */\nexport interface QueryCollectionUtils<\n TItem extends object = Record<string, unknown>,\n TKey extends string | number = string | number,\n TInsertInput extends object = TItem,\n TError = unknown,\n> extends UtilsRecord {\n /** Manually trigger a refetch of the query */\n refetch: RefetchFn\n /** Insert one or more items directly into the synced data store without triggering a query refetch or optimistic update */\n writeInsert: (data: TInsertInput | Array<TInsertInput>) => void\n /** Update one or more items directly in the synced data store without triggering a query refetch or optimistic update */\n writeUpdate: (updates: Partial<TItem> | Array<Partial<TItem>>) => void\n /** Delete one or more items directly from the synced data store without triggering a query refetch or optimistic update */\n writeDelete: (keys: TKey | Array<TKey>) => void\n /** Insert or update one or more items directly in the synced data store without triggering a query refetch or optimistic update */\n writeUpsert: (data: Partial<TItem> | Array<Partial<TItem>>) => void\n /** Execute multiple write operations as a single atomic batch to the synced data store */\n writeBatch: (callback: () => void) => void\n /** Get the last error encountered by the query (if any); reset on success */\n lastError: () => TError | undefined\n /** Check if the collection is in an error state */\n isError: () => boolean\n /**\n * Get the number of consecutive sync failures.\n * Incremented only when query fails completely (not per retry attempt); reset on success.\n */\n errorCount: () => number\n /**\n * Clear the error state and trigger a refetch of the query\n * @returns Promise that resolves when the refetch completes successfully\n * @throws Error if the refetch fails\n */\n clearError: () => Promise<void>\n}\n\n/**\n * Creates query collection options for use with a standard Collection.\n * This integrates TanStack Query with TanStack DB for automatic synchronization.\n *\n * Supports automatic type inference following the priority order:\n * 1. Schema inference (highest priority)\n * 2. QueryFn return type inference (second priority)\n *\n * @template T - Type of the schema if a schema is provided otherwise it is the type of the values returned by the queryFn\n * @template TError - The type of errors that can occur during queries\n * @template TQueryKey - The type of the query key\n * @template TKey - The type of the item keys\n * @param config - Configuration options for the Query collection\n * @returns Collection options with utilities for direct writes and manual operations\n *\n * @example\n * // Type inferred from queryFn return type (NEW!)\n * const todosCollection = createCollection(\n * queryCollectionOptions({\n * queryKey: ['todos'],\n * queryFn: async () => {\n * const response = await fetch('/api/todos')\n * return response.json() as Todo[] // Type automatically inferred!\n * },\n * queryClient,\n * getKey: (item) => item.id, // item is typed as Todo\n * })\n * )\n *\n * @example\n * // Explicit type\n * const todosCollection = createCollection<Todo>(\n * queryCollectionOptions({\n * queryKey: ['todos'],\n * queryFn: async () => fetch('/api/todos').then(r => r.json()),\n * queryClient,\n * getKey: (item) => item.id,\n * })\n * )\n *\n * @example\n * // Schema inference\n * const todosCollection = createCollection(\n * queryCollectionOptions({\n * queryKey: ['todos'],\n * queryFn: async () => fetch('/api/todos').then(r => r.json()),\n * queryClient,\n * schema: todoSchema, // Type inferred from schema\n * getKey: (item) => item.id,\n * })\n * )\n *\n * @example\n * // With persistence handlers\n * const todosCollection = createCollection(\n * queryCollectionOptions({\n * queryKey: ['todos'],\n * queryFn: fetchTodos,\n * queryClient,\n * getKey: (item) => item.id,\n * onInsert: async ({ transaction }) => {\n * await api.createTodos(transaction.mutations.map(m => m.modified))\n * },\n * onUpdate: async ({ transaction }) => {\n * await api.updateTodos(transaction.mutations)\n * },\n * onDelete: async ({ transaction }) => {\n * await api.deleteTodos(transaction.mutations.map(m => m.key))\n * }\n * })\n * )\n */\n\n// Overload for when schema is provided\nexport function queryCollectionOptions<\n T extends StandardSchemaV1,\n TError = unknown,\n TQueryKey extends QueryKey = QueryKey,\n TKey extends string | number = string | number,\n>(\n config: QueryCollectionConfig<\n InferSchemaOutput<T>,\n (\n context: QueryFunctionContext<any>\n ) => Promise<Array<InferSchemaOutput<T>>>,\n TError,\n TQueryKey,\n TKey,\n T\n > & {\n schema: T\n }\n): CollectionConfig<InferSchemaOutput<T>, TKey, T> & {\n schema: T\n utils: QueryCollectionUtils<\n InferSchemaOutput<T>,\n TKey,\n InferSchemaInput<T>,\n TError\n >\n}\n\n// Overload for when no schema is provided\nexport function queryCollectionOptions<\n T extends object,\n TError = unknown,\n TQueryKey extends QueryKey = QueryKey,\n TKey extends string | number = string | number,\n>(\n config: QueryCollectionConfig<\n T,\n (context: QueryFunctionContext<any>) => Promise<Array<T>>,\n TError,\n TQueryKey,\n TKey\n > & {\n schema?: never // prohibit schema\n }\n): CollectionConfig<T, TKey> & {\n schema?: never // no schema in the result\n utils: QueryCollectionUtils<T, TKey, T, TError>\n}\n\nexport function queryCollectionOptions(\n config: QueryCollectionConfig<Record<string, unknown>>\n): CollectionConfig & {\n utils: QueryCollectionUtils\n} {\n const {\n queryKey,\n queryFn,\n queryClient,\n enabled,\n refetchInterval,\n retry,\n retryDelay,\n staleTime,\n getKey,\n onInsert,\n onUpdate,\n onDelete,\n meta,\n ...baseCollectionConfig\n } = config\n\n // Validate required parameters\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!queryKey) {\n throw new QueryKeyRequiredError()\n }\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!queryFn) {\n throw new QueryFnRequiredError()\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!queryClient) {\n throw new QueryClientRequiredError()\n }\n\n if (!getKey) {\n throw new GetKeyRequiredError()\n }\n\n /** The last error encountered by the query */\n let lastError: any\n /** The number of consecutive sync failures */\n let errorCount = 0\n /** The timestamp for when the query most recently returned the status as \"error\" */\n let lastErrorUpdatedAt = 0\n\n const internalSync: SyncConfig<any>[`sync`] = (params) => {\n const { begin, write, commit, markReady, collection } = params\n\n const observerOptions: QueryObserverOptions<\n Array<any>,\n any,\n Array<any>,\n Array<any>,\n any\n > = {\n queryKey: queryKey,\n queryFn: queryFn,\n meta: meta,\n enabled: enabled,\n refetchInterval: refetchInterval,\n retry: retry,\n retryDelay: retryDelay,\n staleTime: staleTime,\n structuralSharing: true,\n notifyOnChangeProps: `all`,\n }\n\n const localObserver = new QueryObserver<\n Array<any>,\n any,\n Array<any>,\n Array<any>,\n any\n >(queryClient, observerOptions)\n\n type UpdateHandler = Parameters<typeof localObserver.subscribe>[0]\n const handleUpdate: UpdateHandler = (result) => {\n if (result.isSuccess) {\n // Clear error state\n lastError = undefined\n errorCount = 0\n\n const newItemsArray = result.data\n\n if (\n !Array.isArray(newItemsArray) ||\n newItemsArray.some((item) => typeof item !== `object`)\n ) {\n console.error(\n `[QueryCollection] queryFn did not return an array of objects. Skipping update.`,\n newItemsArray\n )\n return\n }\n\n const currentSyncedItems = new Map(collection.syncedData)\n const newItemsMap = new Map<string | number, any>()\n newItemsArray.forEach((item) => {\n const key = getKey(item)\n newItemsMap.set(key, item)\n })\n\n begin()\n\n // Helper function for shallow equality check of objects\n const shallowEqual = (\n obj1: Record<string, any>,\n obj2: Record<string, any>\n ): boolean => {\n // Get all keys from both objects\n const keys1 = Object.keys(obj1)\n const keys2 = Object.keys(obj2)\n\n // If number of keys is different, objects are not equal\n if (keys1.length !== keys2.length) return false\n\n // Check if all keys in obj1 have the same values in obj2\n return keys1.every((key) => {\n // Skip comparing functions and complex objects deeply\n if (typeof obj1[key] === `function`) return true\n return obj1[key] === obj2[key]\n })\n }\n\n currentSyncedItems.forEach((oldItem, key) => {\n const newItem = newItemsMap.get(key)\n if (!newItem) {\n write({ type: `delete`, value: oldItem })\n } else if (\n !shallowEqual(\n oldItem as Record<string, any>,\n newItem as Record<string, any>\n )\n ) {\n // Only update if there are actual differences in the properties\n write({ type: `update`, value: newItem })\n }\n })\n\n newItemsMap.forEach((newItem, key) => {\n if (!currentSyncedItems.has(key)) {\n write({ type: `insert`, value: newItem })\n }\n })\n\n commit()\n\n // Mark collection as ready after first successful query result\n markReady()\n } else if (result.isError) {\n if (result.errorUpdatedAt !== lastErrorUpdatedAt) {\n lastError = result.error\n errorCount++\n lastErrorUpdatedAt = result.errorUpdatedAt\n }\n\n console.error(\n `[QueryCollection] Error observing query ${String(queryKey)}:`,\n result.error\n )\n\n // Mark collection as ready even on error to avoid blocking apps\n markReady()\n }\n }\n\n const actualUnsubscribeFn = localObserver.subscribe(handleUpdate)\n\n // Ensure we process any existing query data (QueryObserver doesn't invoke its callback automatically with initial\n // state)\n handleUpdate(localObserver.getCurrentResult())\n\n return async () => {\n actualUnsubscribeFn()\n await queryClient.cancelQueries({ queryKey })\n queryClient.removeQueries({ queryKey })\n }\n }\n\n /**\n * Refetch the query data\n * @returns Promise that resolves when the refetch is complete\n */\n const refetch: RefetchFn = (opts) => {\n return queryClient.refetchQueries(\n {\n queryKey: queryKey,\n },\n {\n throwOnError: opts?.throwOnError,\n }\n )\n }\n\n // Create write context for manual write operations\n let writeContext: {\n collection: any\n queryClient: QueryClient\n queryKey: Array<unknown>\n getKey: (item: any) => string | number\n begin: () => void\n write: (message: Omit<ChangeMessage<any>, `key`>) => void\n commit: () => void\n } | null = null\n\n // Enhanced internalSync that captures write functions for manual use\n const enhancedInternalSync: SyncConfig<any>[`sync`] = (params) => {\n const { begin, write, commit, collection } = params\n\n // Store references for manual write operations\n writeContext = {\n collection,\n queryClient,\n queryKey: queryKey as unknown as Array<unknown>,\n getKey: getKey as (item: any) => string | number,\n begin,\n write,\n commit,\n }\n\n // Call the original internalSync logic\n return internalSync(params)\n }\n\n // Create write utils using the manual-sync module\n const writeUtils = createWriteUtils<any, string | number, any>(\n () => writeContext\n )\n\n // Create wrapper handlers for direct persistence operations that handle refetching\n const wrappedOnInsert = onInsert\n ? async (params: InsertMutationFnParams<any>) => {\n const handlerResult = (await onInsert(params)) ?? {}\n const shouldRefetch =\n (handlerResult as { refetch?: boolean }).refetch !== false\n\n if (shouldRefetch) {\n await refetch()\n }\n\n return handlerResult\n }\n : undefined\n\n const wrappedOnUpdate = onUpdate\n ? async (params: UpdateMutationFnParams<any>) => {\n const handlerResult = (await onUpdate(params)) ?? {}\n const shouldRefetch =\n (handlerResult as { refetch?: boolean }).refetch !== false\n\n if (shouldRefetch) {\n await refetch()\n }\n\n return handlerResult\n }\n : undefined\n\n const wrappedOnDelete = onDelete\n ? async (params: DeleteMutationFnParams<any>) => {\n const handlerResult = (await onDelete(params)) ?? {}\n const shouldRefetch =\n (handlerResult as { refetch?: boolean }).refetch !== false\n\n if (shouldRefetch) {\n await refetch()\n }\n\n return handlerResult\n }\n : undefined\n\n return {\n ...baseCollectionConfig,\n getKey,\n sync: { sync: enhancedInternalSync },\n onInsert: wrappedOnInsert,\n onUpdate: wrappedOnUpdate,\n onDelete: wrappedOnDelete,\n utils: {\n refetch,\n ...writeUtils,\n lastError: () => lastError,\n isError: () => !!lastError,\n errorCount: () => errorCount,\n clearError: () => {\n lastError = undefined\n errorCount = 0\n lastErrorUpdatedAt = 0\n return refetch({ throwOnError: true })\n },\n },\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@tanstack/query-db-collection",
3
3
  "description": "TanStack Query collection for TanStack DB",
4
- "version": "0.2.15",
4
+ "version": "0.2.17",
5
5
  "dependencies": {
6
6
  "@standard-schema/spec": "^1.0.0",
7
- "@tanstack/db": "0.2.3"
7
+ "@tanstack/db": "0.2.5"
8
8
  },
9
9
  "devDependencies": {
10
10
  "@tanstack/query-core": "^5.87.4",