@tanstack/db 0.0.5 → 0.0.7
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/dist/cjs/collection.cjs +86 -27
- package/dist/cjs/collection.cjs.map +1 -1
- package/dist/cjs/collection.d.cts +30 -13
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/query/compiled-query.cjs +1 -1
- package/dist/cjs/query/compiled-query.cjs.map +1 -1
- package/dist/cjs/query/compiled-query.d.cts +1 -1
- package/dist/cjs/query/evaluators.cjs +15 -0
- package/dist/cjs/query/evaluators.cjs.map +1 -1
- package/dist/cjs/query/evaluators.d.cts +5 -1
- package/dist/cjs/query/pipeline-compiler.cjs +2 -2
- package/dist/cjs/query/pipeline-compiler.cjs.map +1 -1
- package/dist/cjs/query/query-builder.cjs +22 -17
- package/dist/cjs/query/query-builder.cjs.map +1 -1
- package/dist/cjs/query/query-builder.d.cts +12 -2
- package/dist/cjs/query/schema.d.cts +11 -5
- package/dist/cjs/query/select.cjs +12 -0
- package/dist/cjs/query/select.cjs.map +1 -1
- package/dist/cjs/transactions.cjs +3 -1
- package/dist/cjs/transactions.cjs.map +1 -1
- package/dist/cjs/types.d.cts +33 -0
- package/dist/esm/collection.d.ts +30 -13
- package/dist/esm/collection.js +87 -28
- package/dist/esm/collection.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/query/compiled-query.d.ts +1 -1
- package/dist/esm/query/compiled-query.js +2 -2
- package/dist/esm/query/compiled-query.js.map +1 -1
- package/dist/esm/query/evaluators.d.ts +5 -1
- package/dist/esm/query/evaluators.js +16 -1
- package/dist/esm/query/evaluators.js.map +1 -1
- package/dist/esm/query/pipeline-compiler.js +3 -3
- package/dist/esm/query/pipeline-compiler.js.map +1 -1
- package/dist/esm/query/query-builder.d.ts +12 -2
- package/dist/esm/query/query-builder.js +22 -17
- package/dist/esm/query/query-builder.js.map +1 -1
- package/dist/esm/query/schema.d.ts +11 -5
- package/dist/esm/query/select.js +12 -0
- package/dist/esm/query/select.js.map +1 -1
- package/dist/esm/transactions.js +3 -1
- package/dist/esm/transactions.js.map +1 -1
- package/dist/esm/types.d.ts +33 -0
- package/package.json +1 -1
- package/src/collection.ts +164 -45
- package/src/index.ts +1 -1
- package/src/query/compiled-query.ts +4 -3
- package/src/query/evaluators.ts +27 -0
- package/src/query/pipeline-compiler.ts +3 -3
- package/src/query/query-builder.ts +40 -23
- package/src/query/schema.ts +17 -5
- package/src/query/select.ts +24 -1
- package/src/transactions.ts +8 -1
- package/src/types.ts +38 -0
package/dist/cjs/types.d.cts
CHANGED
|
@@ -3,6 +3,14 @@ import { Collection } from './collection.cjs';
|
|
|
3
3
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
4
4
|
import { Transaction } from './transactions.cjs';
|
|
5
5
|
export type TransactionState = `pending` | `persisting` | `completed` | `failed`;
|
|
6
|
+
/**
|
|
7
|
+
* Represents a utility function that can be attached to a collection
|
|
8
|
+
*/
|
|
9
|
+
export type Fn = (...args: Array<any>) => any;
|
|
10
|
+
/**
|
|
11
|
+
* A record of utility functions that can be attached to a collection
|
|
12
|
+
*/
|
|
13
|
+
export type UtilsRecord = Record<string, Fn>;
|
|
6
14
|
/**
|
|
7
15
|
* Represents a pending mutation within a transaction
|
|
8
16
|
* Contains information about the original and modified data, as well as metadata
|
|
@@ -27,6 +35,13 @@ export type MutationFnParams = {
|
|
|
27
35
|
transaction: Transaction;
|
|
28
36
|
};
|
|
29
37
|
export type MutationFn = (params: MutationFnParams) => Promise<any>;
|
|
38
|
+
/**
|
|
39
|
+
* Utility type for a Transaction with at least one mutation
|
|
40
|
+
* This is used internally by the Transaction.commit method
|
|
41
|
+
*/
|
|
42
|
+
export type TransactionWithMutations<T extends object = Record<string, unknown>> = Transaction & {
|
|
43
|
+
mutations: [PendingMutation<T>, ...Array<PendingMutation<T>>];
|
|
44
|
+
};
|
|
30
45
|
export interface TransactionConfig {
|
|
31
46
|
/** Unique identifier for the transaction */
|
|
32
47
|
id?: string;
|
|
@@ -100,6 +115,24 @@ export interface CollectionConfig<T extends object = Record<string, unknown>> {
|
|
|
100
115
|
* getId: (item) => item.uuid
|
|
101
116
|
*/
|
|
102
117
|
getId: (item: T) => any;
|
|
118
|
+
/**
|
|
119
|
+
* Optional asynchronous handler function called before an insert operation
|
|
120
|
+
* @param params Object containing transaction and mutation information
|
|
121
|
+
* @returns Promise resolving to any value
|
|
122
|
+
*/
|
|
123
|
+
onInsert?: MutationFn;
|
|
124
|
+
/**
|
|
125
|
+
* Optional asynchronous handler function called before an update operation
|
|
126
|
+
* @param params Object containing transaction and mutation information
|
|
127
|
+
* @returns Promise resolving to any value
|
|
128
|
+
*/
|
|
129
|
+
onUpdate?: MutationFn;
|
|
130
|
+
/**
|
|
131
|
+
* Optional asynchronous handler function called before a delete operation
|
|
132
|
+
* @param params Object containing transaction and mutation information
|
|
133
|
+
* @returns Promise resolving to any value
|
|
134
|
+
*/
|
|
135
|
+
onDelete?: MutationFn;
|
|
103
136
|
}
|
|
104
137
|
export type ChangesPayload<T extends object = Record<string, unknown>> = Array<ChangeMessage<T>>;
|
|
105
138
|
/**
|
package/dist/esm/collection.d.ts
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import { Derived, Store } from '@tanstack/store';
|
|
2
|
+
import { Transaction } from './transactions.js';
|
|
2
3
|
import { SortedMap } from './SortedMap.js';
|
|
3
|
-
import { ChangeMessage, CollectionConfig, InsertConfig, OperationConfig, OptimisticChangeMessage, Transaction } from './types.js';
|
|
4
|
-
export declare const collectionsStore: Store<Map<string,
|
|
4
|
+
import { ChangeMessage, CollectionConfig, Fn, InsertConfig, OperationConfig, OptimisticChangeMessage, Transaction as TransactionType, UtilsRecord } from './types.js';
|
|
5
|
+
export declare const collectionsStore: Store<Map<string, CollectionImpl<any>>, (cb: Map<string, CollectionImpl<any>>) => Map<string, CollectionImpl<any>>>;
|
|
6
|
+
/**
|
|
7
|
+
* Enhanced Collection interface that includes both data type T and utilities TUtils
|
|
8
|
+
* @template T - The type of items in the collection
|
|
9
|
+
* @template TUtils - The utilities record type
|
|
10
|
+
*/
|
|
11
|
+
export interface Collection<T extends object = Record<string, unknown>, TUtils extends UtilsRecord = {}> extends CollectionImpl<T> {
|
|
12
|
+
readonly utils: TUtils;
|
|
13
|
+
}
|
|
5
14
|
/**
|
|
6
15
|
* Creates a new Collection instance with the given configuration
|
|
7
16
|
*
|
|
8
17
|
* @template T - The type of items in the collection
|
|
9
|
-
* @
|
|
10
|
-
* @
|
|
18
|
+
* @template TUtils - The utilities record type
|
|
19
|
+
* @param options - Collection options with optional utilities
|
|
20
|
+
* @returns A new Collection with utilities exposed both at top level and under .utils
|
|
11
21
|
*/
|
|
12
|
-
export declare function createCollection<T extends object = Record<string, unknown
|
|
22
|
+
export declare function createCollection<T extends object = Record<string, unknown>, TUtils extends UtilsRecord = {}>(options: CollectionConfig<T> & {
|
|
23
|
+
utils?: TUtils;
|
|
24
|
+
}): Collection<T, TUtils>;
|
|
13
25
|
/**
|
|
14
26
|
* Preloads a collection with the given configuration
|
|
15
27
|
* Returns a promise that resolves once the sync tool has done its first commit (initial sync is finished)
|
|
@@ -36,7 +48,7 @@ export declare function createCollection<T extends object = Record<string, unkno
|
|
|
36
48
|
* @param config - Configuration for the collection, including id and sync
|
|
37
49
|
* @returns Promise that resolves when the initial sync is finished
|
|
38
50
|
*/
|
|
39
|
-
export declare function preloadCollection<T extends object = Record<string, unknown>>(config: CollectionConfig<T>): Promise<
|
|
51
|
+
export declare function preloadCollection<T extends object = Record<string, unknown>>(config: CollectionConfig<T>): Promise<CollectionImpl<T>>;
|
|
40
52
|
/**
|
|
41
53
|
* Custom error class for schema validation errors
|
|
42
54
|
*/
|
|
@@ -51,8 +63,13 @@ export declare class SchemaValidationError extends Error {
|
|
|
51
63
|
path?: ReadonlyArray<string | number | symbol>;
|
|
52
64
|
}>, message?: string);
|
|
53
65
|
}
|
|
54
|
-
export declare class
|
|
55
|
-
|
|
66
|
+
export declare class CollectionImpl<T extends object = Record<string, unknown>> {
|
|
67
|
+
/**
|
|
68
|
+
* Utilities namespace
|
|
69
|
+
* This is populated by createCollection
|
|
70
|
+
*/
|
|
71
|
+
utils: Record<string, Fn>;
|
|
72
|
+
transactions: Store<SortedMap<string, TransactionType>>;
|
|
56
73
|
optimisticOperations: Derived<Array<OptimisticChangeMessage<T>>>;
|
|
57
74
|
derivedState: Derived<Map<string, T>>;
|
|
58
75
|
derivedArray: Derived<Array<T>>;
|
|
@@ -91,7 +108,7 @@ export declare class Collection<T extends object = Record<string, unknown>> {
|
|
|
91
108
|
* Inserts one or more items into the collection
|
|
92
109
|
* @param items - Single item or array of items to insert
|
|
93
110
|
* @param config - Optional configuration including metadata and custom keys
|
|
94
|
-
* @returns A
|
|
111
|
+
* @returns A TransactionType object representing the insert operation(s)
|
|
95
112
|
* @throws {SchemaValidationError} If the data fails schema validation
|
|
96
113
|
* @example
|
|
97
114
|
* // Insert a single item
|
|
@@ -145,13 +162,13 @@ export declare class Collection<T extends object = Record<string, unknown>> {
|
|
|
145
162
|
* // Update with metadata
|
|
146
163
|
* update("todo-1", { metadata: { reason: "user update" } }, (draft) => { draft.text = "Updated text" })
|
|
147
164
|
*/
|
|
148
|
-
update<TItem extends object = T>(id: unknown, configOrCallback: ((draft: TItem) => void) | OperationConfig, maybeCallback?: (draft: TItem) => void):
|
|
149
|
-
update<TItem extends object = T>(ids: Array<unknown>, configOrCallback: ((draft: Array<TItem>) => void) | OperationConfig, maybeCallback?: (draft: Array<TItem>) => void):
|
|
165
|
+
update<TItem extends object = T>(id: unknown, configOrCallback: ((draft: TItem) => void) | OperationConfig, maybeCallback?: (draft: TItem) => void): TransactionType;
|
|
166
|
+
update<TItem extends object = T>(ids: Array<unknown>, configOrCallback: ((draft: Array<TItem>) => void) | OperationConfig, maybeCallback?: (draft: Array<TItem>) => void): TransactionType;
|
|
150
167
|
/**
|
|
151
168
|
* Deletes one or more items from the collection
|
|
152
169
|
* @param ids - Single ID or array of IDs to delete
|
|
153
170
|
* @param config - Optional configuration including metadata
|
|
154
|
-
* @returns A
|
|
171
|
+
* @returns A TransactionType object representing the delete operation(s)
|
|
155
172
|
* @example
|
|
156
173
|
* // Delete a single item
|
|
157
174
|
* delete("todo-1")
|
|
@@ -162,7 +179,7 @@ export declare class Collection<T extends object = Record<string, unknown>> {
|
|
|
162
179
|
* // Delete with metadata
|
|
163
180
|
* delete("todo-1", { metadata: { reason: "completed" } })
|
|
164
181
|
*/
|
|
165
|
-
delete: (ids: Array<string> | string, config?: OperationConfig) =>
|
|
182
|
+
delete: (ids: Array<string> | string, config?: OperationConfig) => TransactionType;
|
|
166
183
|
/**
|
|
167
184
|
* Gets the current state of the collection as a Map
|
|
168
185
|
*
|
package/dist/esm/collection.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { Store, batch, Derived } from "@tanstack/store";
|
|
2
2
|
import { withArrayChangeTracking, withChangeTracking } from "./proxy.js";
|
|
3
|
-
import { getActiveTransaction } from "./transactions.js";
|
|
3
|
+
import { getActiveTransaction, Transaction } from "./transactions.js";
|
|
4
4
|
import { SortedMap } from "./SortedMap.js";
|
|
5
|
-
const collectionsStore = new Store(
|
|
5
|
+
const collectionsStore = new Store(
|
|
6
|
+
/* @__PURE__ */ new Map()
|
|
7
|
+
);
|
|
6
8
|
const loadingCollections = /* @__PURE__ */ new Map();
|
|
7
|
-
function createCollection(
|
|
8
|
-
|
|
9
|
+
function createCollection(options) {
|
|
10
|
+
const collection = new CollectionImpl(options);
|
|
11
|
+
if (options.utils) {
|
|
12
|
+
collection.utils = { ...options.utils };
|
|
13
|
+
} else {
|
|
14
|
+
collection.utils = {};
|
|
15
|
+
}
|
|
16
|
+
return collection;
|
|
9
17
|
}
|
|
10
18
|
function preloadCollection(config) {
|
|
11
19
|
if (!config.id) {
|
|
@@ -27,7 +35,7 @@ function preloadCollection(config) {
|
|
|
27
35
|
}
|
|
28
36
|
next.set(
|
|
29
37
|
config.id,
|
|
30
|
-
|
|
38
|
+
createCollection({
|
|
31
39
|
id: config.id,
|
|
32
40
|
getId: config.getId,
|
|
33
41
|
sync: config.sync,
|
|
@@ -68,7 +76,7 @@ class SchemaValidationError extends Error {
|
|
|
68
76
|
this.issues = issues;
|
|
69
77
|
}
|
|
70
78
|
}
|
|
71
|
-
class
|
|
79
|
+
class CollectionImpl {
|
|
72
80
|
/**
|
|
73
81
|
* Creates a new Collection instance
|
|
74
82
|
*
|
|
@@ -76,6 +84,7 @@ class Collection {
|
|
|
76
84
|
* @throws Error if sync config is missing
|
|
77
85
|
*/
|
|
78
86
|
constructor(config) {
|
|
87
|
+
this.utils = {};
|
|
79
88
|
this.syncedData = new Store(/* @__PURE__ */ new Map());
|
|
80
89
|
this.syncedMetadata = new Store(/* @__PURE__ */ new Map());
|
|
81
90
|
this.pendingSyncedTransactions = [];
|
|
@@ -138,9 +147,11 @@ class Collection {
|
|
|
138
147
|
}
|
|
139
148
|
};
|
|
140
149
|
this.insert = (data, config2) => {
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
143
|
-
throw
|
|
150
|
+
const ambientTransaction = getActiveTransaction();
|
|
151
|
+
if (!ambientTransaction && !this.config.onInsert) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Collection.insert called directly (not within an explicit transaction) but no 'onInsert' handler is configured.`
|
|
154
|
+
);
|
|
144
155
|
}
|
|
145
156
|
const items = Array.isArray(data) ? data : [data];
|
|
146
157
|
const mutations = [];
|
|
@@ -170,17 +181,34 @@ class Collection {
|
|
|
170
181
|
};
|
|
171
182
|
mutations.push(mutation);
|
|
172
183
|
});
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
184
|
+
if (ambientTransaction) {
|
|
185
|
+
ambientTransaction.applyMutations(mutations);
|
|
186
|
+
this.transactions.setState((sortedMap) => {
|
|
187
|
+
sortedMap.set(ambientTransaction.id, ambientTransaction);
|
|
188
|
+
return sortedMap;
|
|
189
|
+
});
|
|
190
|
+
return ambientTransaction;
|
|
191
|
+
} else {
|
|
192
|
+
const directOpTransaction = new Transaction({
|
|
193
|
+
mutationFn: async (params) => {
|
|
194
|
+
return this.config.onInsert(params);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
directOpTransaction.applyMutations(mutations);
|
|
198
|
+
directOpTransaction.commit();
|
|
199
|
+
this.transactions.setState((sortedMap) => {
|
|
200
|
+
sortedMap.set(directOpTransaction.id, directOpTransaction);
|
|
201
|
+
return sortedMap;
|
|
202
|
+
});
|
|
203
|
+
return directOpTransaction;
|
|
204
|
+
}
|
|
179
205
|
};
|
|
180
206
|
this.delete = (ids, config2) => {
|
|
181
|
-
const
|
|
182
|
-
if (
|
|
183
|
-
throw
|
|
207
|
+
const ambientTransaction = getActiveTransaction();
|
|
208
|
+
if (!ambientTransaction && !this.config.onDelete) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`Collection.delete called directly (not within an explicit transaction) but no 'onDelete' handler is configured.`
|
|
211
|
+
);
|
|
184
212
|
}
|
|
185
213
|
const idsArray = (Array.isArray(ids) ? ids : [ids]).map(
|
|
186
214
|
(id) => this.getKeyFromId(id)
|
|
@@ -202,12 +230,27 @@ class Collection {
|
|
|
202
230
|
};
|
|
203
231
|
mutations.push(mutation);
|
|
204
232
|
}
|
|
205
|
-
|
|
233
|
+
if (ambientTransaction) {
|
|
234
|
+
ambientTransaction.applyMutations(mutations);
|
|
235
|
+
this.transactions.setState((sortedMap) => {
|
|
236
|
+
sortedMap.set(ambientTransaction.id, ambientTransaction);
|
|
237
|
+
return sortedMap;
|
|
238
|
+
});
|
|
239
|
+
return ambientTransaction;
|
|
240
|
+
}
|
|
241
|
+
const directOpTransaction = new Transaction({
|
|
242
|
+
autoCommit: true,
|
|
243
|
+
mutationFn: async (transaction) => {
|
|
244
|
+
return this.config.onDelete(transaction);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
directOpTransaction.applyMutations(mutations);
|
|
248
|
+
directOpTransaction.commit();
|
|
206
249
|
this.transactions.setState((sortedMap) => {
|
|
207
|
-
sortedMap.set(
|
|
250
|
+
sortedMap.set(directOpTransaction.id, directOpTransaction);
|
|
208
251
|
return sortedMap;
|
|
209
252
|
});
|
|
210
|
-
return
|
|
253
|
+
return directOpTransaction;
|
|
211
254
|
};
|
|
212
255
|
if (!config) {
|
|
213
256
|
throw new Error(`Collection requires a config`);
|
|
@@ -466,9 +509,11 @@ class Collection {
|
|
|
466
509
|
if (typeof ids === `undefined`) {
|
|
467
510
|
throw new Error(`The first argument to update is missing`);
|
|
468
511
|
}
|
|
469
|
-
const
|
|
470
|
-
if (
|
|
471
|
-
throw
|
|
512
|
+
const ambientTransaction = getActiveTransaction();
|
|
513
|
+
if (!ambientTransaction && !this.config.onUpdate) {
|
|
514
|
+
throw new Error(
|
|
515
|
+
`Collection.update called directly (not within an explicit transaction) but no 'onUpdate' handler is configured.`
|
|
516
|
+
);
|
|
472
517
|
}
|
|
473
518
|
const isArray = Array.isArray(ids);
|
|
474
519
|
const idsArray = (Array.isArray(ids) ? ids : [ids]).map(
|
|
@@ -534,12 +579,26 @@ class Collection {
|
|
|
534
579
|
if (mutations.length === 0) {
|
|
535
580
|
throw new Error(`No changes were made to any of the objects`);
|
|
536
581
|
}
|
|
537
|
-
|
|
582
|
+
if (ambientTransaction) {
|
|
583
|
+
ambientTransaction.applyMutations(mutations);
|
|
584
|
+
this.transactions.setState((sortedMap) => {
|
|
585
|
+
sortedMap.set(ambientTransaction.id, ambientTransaction);
|
|
586
|
+
return sortedMap;
|
|
587
|
+
});
|
|
588
|
+
return ambientTransaction;
|
|
589
|
+
}
|
|
590
|
+
const directOpTransaction = new Transaction({
|
|
591
|
+
mutationFn: async (transaction) => {
|
|
592
|
+
return this.config.onUpdate(transaction);
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
directOpTransaction.applyMutations(mutations);
|
|
596
|
+
directOpTransaction.commit();
|
|
538
597
|
this.transactions.setState((sortedMap) => {
|
|
539
|
-
sortedMap.set(
|
|
598
|
+
sortedMap.set(directOpTransaction.id, directOpTransaction);
|
|
540
599
|
return sortedMap;
|
|
541
600
|
});
|
|
542
|
-
return
|
|
601
|
+
return directOpTransaction;
|
|
543
602
|
}
|
|
544
603
|
/**
|
|
545
604
|
* Gets the current state of the collection as a Map
|
|
@@ -615,7 +674,7 @@ class Collection {
|
|
|
615
674
|
}
|
|
616
675
|
}
|
|
617
676
|
export {
|
|
618
|
-
|
|
677
|
+
CollectionImpl,
|
|
619
678
|
SchemaValidationError,
|
|
620
679
|
collectionsStore,
|
|
621
680
|
createCollection,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection.js","sources":["../../src/collection.ts"],"sourcesContent":["import { Derived, Store, batch } from \"@tanstack/store\"\nimport { withArrayChangeTracking, withChangeTracking } from \"./proxy\"\nimport { getActiveTransaction } from \"./transactions\"\nimport { SortedMap } from \"./SortedMap\"\nimport type {\n ChangeMessage,\n CollectionConfig,\n InsertConfig,\n OperationConfig,\n OptimisticChangeMessage,\n PendingMutation,\n StandardSchema,\n Transaction,\n} from \"./types\"\n\n// Store collections in memory using Tanstack store\nexport const collectionsStore = new Store(new Map<string, Collection<any>>())\n\n// Map to track loading collections\n\nconst loadingCollections = new Map<\n string,\n Promise<Collection<Record<string, unknown>>>\n>()\n\ninterface PendingSyncedTransaction<T extends object = Record<string, unknown>> {\n committed: boolean\n operations: Array<OptimisticChangeMessage<T>>\n}\n\n/**\n * Creates a new Collection instance with the given configuration\n *\n * @template T - The type of items in the collection\n * @param config - Configuration for the collection, including id and sync\n * @returns A new Collection instance\n */\nexport function createCollection<T extends object = Record<string, unknown>>(\n config: CollectionConfig<T>\n): Collection<T> {\n return new Collection<T>(config)\n}\n\n/**\n * Preloads a collection with the given configuration\n * Returns a promise that resolves once the sync tool has done its first commit (initial sync is finished)\n * If the collection has already loaded, it resolves immediately\n *\n * This function is useful in route loaders or similar pre-rendering scenarios where you want\n * to ensure data is available before a route transition completes. It uses the same shared collection\n * instance that will be used by useCollection, ensuring data consistency.\n *\n * @example\n * ```typescript\n * // In a route loader\n * async function loader({ params }) {\n * await preloadCollection({\n * id: `users-${params.userId}`,\n * sync: { ... },\n * });\n *\n * return null;\n * }\n * ```\n *\n * @template T - The type of items in the collection\n * @param config - Configuration for the collection, including id and sync\n * @returns Promise that resolves when the initial sync is finished\n */\nexport function preloadCollection<T extends object = Record<string, unknown>>(\n config: CollectionConfig<T>\n): Promise<Collection<T>> {\n if (!config.id) {\n throw new Error(`The id property is required for preloadCollection`)\n }\n\n // If the collection is already fully loaded, return a resolved promise\n if (\n collectionsStore.state.has(config.id) &&\n !loadingCollections.has(config.id)\n ) {\n return Promise.resolve(\n collectionsStore.state.get(config.id)! as Collection<T>\n )\n }\n\n // If the collection is in the process of loading, return its promise\n if (loadingCollections.has(config.id)) {\n return loadingCollections.get(config.id)! as Promise<Collection<T>>\n }\n\n // Create a new collection instance if it doesn't exist\n if (!collectionsStore.state.has(config.id)) {\n collectionsStore.setState((prev) => {\n const next = new Map(prev)\n if (!config.id) {\n throw new Error(`The id property is required for preloadCollection`)\n }\n next.set(\n config.id,\n new Collection<T>({\n id: config.id,\n getId: config.getId,\n sync: config.sync,\n schema: config.schema,\n })\n )\n return next\n })\n }\n\n const collection = collectionsStore.state.get(config.id)! as Collection<T>\n\n // Create a promise that will resolve after the first commit\n let resolveFirstCommit: () => void\n const firstCommitPromise = new Promise<Collection<T>>((resolve) => {\n resolveFirstCommit = () => {\n resolve(collection)\n }\n })\n\n // Register a one-time listener for the first commit\n collection.onFirstCommit(() => {\n if (!config.id) {\n throw new Error(`The id property is required for preloadCollection`)\n }\n if (loadingCollections.has(config.id)) {\n loadingCollections.delete(config.id)\n resolveFirstCommit()\n }\n })\n\n // Store the loading promise\n loadingCollections.set(\n config.id,\n firstCommitPromise as Promise<Collection<Record<string, unknown>>>\n )\n\n return firstCommitPromise\n}\n\n/**\n * Custom error class for schema validation errors\n */\nexport class SchemaValidationError extends Error {\n type: `insert` | `update`\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>\n\n constructor(\n type: `insert` | `update`,\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>,\n message?: string\n ) {\n const defaultMessage = `${type === `insert` ? `Insert` : `Update`} validation failed: ${issues\n .map((issue) => issue.message)\n .join(`, `)}`\n\n super(message || defaultMessage)\n this.name = `SchemaValidationError`\n this.type = type\n this.issues = issues\n }\n}\n\nexport class Collection<T extends object = Record<string, unknown>> {\n public transactions: Store<SortedMap<string, Transaction>>\n public optimisticOperations: Derived<Array<OptimisticChangeMessage<T>>>\n public derivedState: Derived<Map<string, T>>\n public derivedArray: Derived<Array<T>>\n public derivedChanges: Derived<Array<ChangeMessage<T>>>\n public syncedData = new Store<Map<string, T>>(new Map())\n public syncedMetadata = new Store(new Map<string, unknown>())\n private pendingSyncedTransactions: Array<PendingSyncedTransaction<T>> = []\n private syncedKeys = new Set<string>()\n public config: CollectionConfig<T>\n private hasReceivedFirstCommit = false\n\n // Array to store one-time commit listeners\n private onFirstCommitCallbacks: Array<() => void> = []\n\n /**\n * Register a callback to be executed on the next commit\n * Useful for preloading collections\n * @param callback Function to call after the next commit\n */\n public onFirstCommit(callback: () => void): void {\n this.onFirstCommitCallbacks.push(callback)\n }\n\n public id = ``\n\n /**\n * Creates a new Collection instance\n *\n * @param config - Configuration object for the collection\n * @throws Error if sync config is missing\n */\n constructor(config: CollectionConfig<T>) {\n // eslint-disable-next-line\n if (!config) {\n throw new Error(`Collection requires a config`)\n }\n if (config.id) {\n this.id = config.id\n } else {\n this.id = crypto.randomUUID()\n }\n\n // eslint-disable-next-line\n if (!config.sync) {\n throw new Error(`Collection requires a sync config`)\n }\n\n this.transactions = new Store(\n new SortedMap<string, Transaction>(\n (a, b) => a.createdAt.getTime() - b.createdAt.getTime()\n )\n )\n\n // Copies of live mutations are stored here and removed once the transaction completes.\n this.optimisticOperations = new Derived({\n fn: ({ currDepVals: [transactions] }) => {\n const result = Array.from(transactions.values())\n .map((transaction) => {\n const isActive = ![`completed`, `failed`].includes(\n transaction.state\n )\n return transaction.mutations\n .filter((mutation) => mutation.collection === this)\n .map((mutation) => {\n const message: OptimisticChangeMessage<T> = {\n type: mutation.type,\n key: mutation.key,\n value: mutation.modified as T,\n isActive,\n }\n if (\n mutation.metadata !== undefined &&\n mutation.metadata !== null\n ) {\n message.metadata = mutation.metadata as Record<\n string,\n unknown\n >\n }\n return message\n })\n })\n .flat()\n\n return result\n },\n deps: [this.transactions],\n })\n this.optimisticOperations.mount()\n\n // Combine together synced data & optimistic operations.\n this.derivedState = new Derived({\n fn: ({ currDepVals: [syncedData, operations] }) => {\n const combined = new Map<string, T>(syncedData)\n\n // Apply the optimistic operations on top of the synced state.\n for (const operation of operations) {\n if (operation.isActive) {\n switch (operation.type) {\n case `insert`:\n combined.set(operation.key, operation.value)\n break\n case `update`:\n combined.set(operation.key, operation.value)\n break\n case `delete`:\n combined.delete(operation.key)\n break\n }\n }\n }\n\n return combined\n },\n deps: [this.syncedData, this.optimisticOperations],\n })\n\n // Create a derived array from the map to avoid recalculating it\n this.derivedArray = new Derived({\n fn: ({ currDepVals: [stateMap] }) => {\n // Collections returned by a query that has an orderBy are annotated\n // with the _orderByIndex field.\n // This is used to sort the array when it's derived.\n const array: Array<T & { _orderByIndex?: number }> = Array.from(\n stateMap.values()\n )\n if (array[0] && `_orderByIndex` in array[0]) {\n ;(array as Array<T & { _orderByIndex: number }>).sort((a, b) => {\n if (a._orderByIndex === b._orderByIndex) {\n return 0\n }\n return a._orderByIndex < b._orderByIndex ? -1 : 1\n })\n }\n return array\n },\n deps: [this.derivedState],\n })\n this.derivedArray.mount()\n\n this.derivedChanges = new Derived({\n fn: ({\n currDepVals: [derivedState, optimisticOperations],\n prevDepVals,\n }) => {\n const prevDerivedState = prevDepVals?.[0] ?? new Map<string, T>()\n const prevOptimisticOperations = prevDepVals?.[1] ?? []\n const changedKeys = new Set(this.syncedKeys)\n optimisticOperations\n .flat()\n .filter((op) => op.isActive)\n .forEach((op) => changedKeys.add(op.key))\n prevOptimisticOperations.flat().forEach((op) => {\n changedKeys.add(op.key)\n })\n\n if (changedKeys.size === 0) {\n return []\n }\n\n const changes: Array<ChangeMessage<T>> = []\n for (const key of changedKeys) {\n if (prevDerivedState.has(key) && !derivedState.has(key)) {\n changes.push({\n type: `delete`,\n key,\n value: prevDerivedState.get(key)!,\n })\n } else if (!prevDerivedState.has(key) && derivedState.has(key)) {\n changes.push({ type: `insert`, key, value: derivedState.get(key)! })\n } else if (prevDerivedState.has(key) && derivedState.has(key)) {\n const value = derivedState.get(key)!\n const previousValue = prevDerivedState.get(key)\n if (value !== previousValue) {\n // Comparing objects by reference as records are not mutated\n changes.push({\n type: `update`,\n key,\n value,\n previousValue,\n })\n }\n }\n }\n\n this.syncedKeys.clear()\n\n return changes\n },\n deps: [this.derivedState, this.optimisticOperations],\n })\n this.derivedChanges.mount()\n\n this.config = config\n\n this.derivedState.mount()\n\n // Start the sync process\n config.sync.sync({\n collection: this,\n begin: () => {\n this.pendingSyncedTransactions.push({\n committed: false,\n operations: [],\n })\n },\n write: (messageWithoutKey: Omit<ChangeMessage<T>, `key`>) => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new Error(`No pending sync transaction to write to`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't still write to it.`\n )\n }\n const key = this.generateObjectKey(\n this.config.getId(messageWithoutKey.value),\n messageWithoutKey.value\n )\n\n // Check if an item with this ID already exists when inserting\n if (messageWithoutKey.type === `insert`) {\n if (\n this.syncedData.state.has(key) &&\n !pendingTransaction.operations.some(\n (op) => op.key === key && op.type === `delete`\n )\n ) {\n const id = this.config.getId(messageWithoutKey.value)\n throw new Error(\n `Cannot insert document with ID \"${id}\" from sync because it already exists in the collection \"${this.id}\"`\n )\n }\n }\n\n const message: ChangeMessage<T> = {\n ...messageWithoutKey,\n key,\n }\n pendingTransaction.operations.push(message)\n },\n commit: () => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new Error(`No pending sync transaction to commit`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't commit it again.`\n )\n }\n\n pendingTransaction.committed = true\n\n this.commitPendingTransactions()\n },\n })\n }\n\n /**\n * Attempts to commit pending synced transactions if there are no active transactions\n * This method processes operations from pending transactions and applies them to the synced data\n */\n commitPendingTransactions = () => {\n if (\n !Array.from(this.transactions.state.values()).some(\n ({ state }) => state === `persisting`\n )\n ) {\n batch(() => {\n for (const transaction of this.pendingSyncedTransactions) {\n for (const operation of transaction.operations) {\n this.syncedKeys.add(operation.key)\n this.syncedMetadata.setState((prevData) => {\n switch (operation.type) {\n case `insert`:\n prevData.set(operation.key, operation.metadata)\n break\n case `update`:\n prevData.set(operation.key, {\n ...prevData.get(operation.key)!,\n ...operation.metadata,\n })\n break\n case `delete`:\n prevData.delete(operation.key)\n break\n }\n return prevData\n })\n this.syncedData.setState((prevData) => {\n switch (operation.type) {\n case `insert`:\n prevData.set(operation.key, operation.value)\n break\n case `update`:\n prevData.set(operation.key, {\n ...prevData.get(operation.key)!,\n ...operation.value,\n })\n break\n case `delete`:\n prevData.delete(operation.key)\n break\n }\n return prevData\n })\n }\n }\n })\n\n this.pendingSyncedTransactions = []\n\n // Call any registered one-time commit listeners\n if (!this.hasReceivedFirstCommit) {\n this.hasReceivedFirstCommit = true\n const callbacks = [...this.onFirstCommitCallbacks]\n this.onFirstCommitCallbacks = []\n callbacks.forEach((callback) => callback())\n }\n }\n }\n\n private ensureStandardSchema(schema: unknown): StandardSchema<T> {\n // If the schema already implements the standard-schema interface, return it\n if (schema && typeof schema === `object` && `~standard` in schema) {\n return schema as StandardSchema<T>\n }\n\n throw new Error(\n `Schema must either implement the standard-schema interface or be a Zod schema`\n )\n }\n\n private getKeyFromId(id: unknown): string {\n if (typeof id === `undefined`) {\n throw new Error(`id is undefined`)\n }\n if (typeof id === `string` && id.startsWith(`KEY::`)) {\n return id\n } else {\n // if it's not a string, then it's some other\n // primitive type and needs turned into a key.\n return this.generateObjectKey(id, null)\n }\n }\n\n public generateObjectKey(id: any, item: any): string {\n if (typeof id === `undefined`) {\n throw new Error(\n `An object was created without a defined id: ${JSON.stringify(item)}`\n )\n }\n\n return `KEY::${this.id}/${id}`\n }\n\n private validateData(\n data: unknown,\n type: `insert` | `update`,\n key?: string\n ): T | never {\n if (!this.config.schema) return data as T\n\n const standardSchema = this.ensureStandardSchema(this.config.schema)\n\n // For updates, we need to merge with the existing data before validation\n if (type === `update` && key) {\n // Get the existing data for this key\n const existingData = this.state.get(key)\n\n if (\n existingData &&\n data &&\n typeof data === `object` &&\n typeof existingData === `object`\n ) {\n // Merge the update with the existing data\n const mergedData = { ...existingData, ...data }\n\n // Validate the merged data\n const result = standardSchema[`~standard`].validate(mergedData)\n\n // Ensure validation is synchronous\n if (result instanceof Promise) {\n throw new TypeError(`Schema validation must be synchronous`)\n }\n\n // If validation fails, throw a SchemaValidationError with the issues\n if (`issues` in result && result.issues) {\n const typedIssues = result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((p) => String(p)),\n }))\n throw new SchemaValidationError(type, typedIssues)\n }\n\n // Return the original update data, not the merged data\n // We only used the merged data for validation\n return data as T\n }\n }\n\n // For inserts or updates without existing data, validate the data directly\n const result = standardSchema[`~standard`].validate(data)\n\n // Ensure validation is synchronous\n if (result instanceof Promise) {\n throw new TypeError(`Schema validation must be synchronous`)\n }\n\n // If validation fails, throw a SchemaValidationError with the issues\n if (`issues` in result && result.issues) {\n const typedIssues = result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((p) => String(p)),\n }))\n throw new SchemaValidationError(type, typedIssues)\n }\n\n return result.value as T\n }\n\n /**\n * Inserts one or more items into the collection\n * @param items - Single item or array of items to insert\n * @param config - Optional configuration including metadata and custom keys\n * @returns A Transaction object representing the insert operation(s)\n * @throws {SchemaValidationError} If the data fails schema validation\n * @example\n * // Insert a single item\n * insert({ text: \"Buy groceries\", completed: false })\n *\n * // Insert multiple items\n * insert([\n * { text: \"Buy groceries\", completed: false },\n * { text: \"Walk dog\", completed: false }\n * ])\n *\n * // Insert with custom key\n * insert({ text: \"Buy groceries\" }, { key: \"grocery-task\" })\n */\n insert = (data: T | Array<T>, config?: InsertConfig) => {\n const transaction = getActiveTransaction()\n if (typeof transaction === `undefined`) {\n throw `no transaction found when calling collection.insert`\n }\n\n const items = Array.isArray(data) ? data : [data]\n const mutations: Array<PendingMutation<T>> = []\n\n // Handle keys - convert to array if string, or generate if not provided\n const keys: Array<unknown> = items.map((item) =>\n this.generateObjectKey(this.config.getId(item), item)\n )\n\n // Create mutations for each item\n items.forEach((item, index) => {\n // Validate the data against the schema if one exists\n const validatedData = this.validateData(item, `insert`)\n const key = keys[index]!\n\n // Check if an item with this ID already exists in the collection\n const id = this.config.getId(item)\n if (this.state.has(this.getKeyFromId(id))) {\n throw `Cannot insert document with ID \"${id}\" because it already exists in the collection`\n }\n\n const mutation: PendingMutation<T> = {\n mutationId: crypto.randomUUID(),\n original: {},\n modified: validatedData as Record<string, unknown>,\n changes: validatedData as Record<string, unknown>,\n key,\n metadata: config?.metadata as unknown,\n syncMetadata: this.config.sync.getSyncMetadata?.() || {},\n type: `insert`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n\n mutations.push(mutation)\n })\n\n transaction.applyMutations(mutations)\n\n this.transactions.setState((sortedMap) => {\n sortedMap.set(transaction.id, transaction)\n return sortedMap\n })\n\n return transaction\n }\n\n /**\n * Updates one or more items in the collection using a callback function\n * @param items - Single item/key or array of items/keys to update\n * @param configOrCallback - Either update configuration or update callback\n * @param maybeCallback - Update callback if config was provided\n * @returns A Transaction object representing the update operation(s)\n * @throws {SchemaValidationError} If the updated data fails schema validation\n * @example\n * // Update a single item\n * update(todo, (draft) => { draft.completed = true })\n *\n * // Update multiple items\n * update([todo1, todo2], (drafts) => {\n * drafts.forEach(draft => { draft.completed = true })\n * })\n *\n * // Update with metadata\n * update(todo, { metadata: { reason: \"user update\" } }, (draft) => { draft.text = \"Updated text\" })\n */\n\n /**\n * Updates one or more items in the collection using a callback function\n * @param ids - Single ID or array of IDs to update\n * @param configOrCallback - Either update configuration or update callback\n * @param maybeCallback - Update callback if config was provided\n * @returns A Transaction object representing the update operation(s)\n * @throws {SchemaValidationError} If the updated data fails schema validation\n * @example\n * // Update a single item\n * update(\"todo-1\", (draft) => { draft.completed = true })\n *\n * // Update multiple items\n * update([\"todo-1\", \"todo-2\"], (drafts) => {\n * drafts.forEach(draft => { draft.completed = true })\n * })\n *\n * // Update with metadata\n * update(\"todo-1\", { metadata: { reason: \"user update\" } }, (draft) => { draft.text = \"Updated text\" })\n */\n update<TItem extends object = T>(\n id: unknown,\n configOrCallback: ((draft: TItem) => void) | OperationConfig,\n maybeCallback?: (draft: TItem) => void\n ): Transaction\n\n update<TItem extends object = T>(\n ids: Array<unknown>,\n configOrCallback: ((draft: Array<TItem>) => void) | OperationConfig,\n maybeCallback?: (draft: Array<TItem>) => void\n ): Transaction\n\n update<TItem extends object = T>(\n ids: unknown | Array<unknown>,\n configOrCallback: ((draft: TItem | Array<TItem>) => void) | OperationConfig,\n maybeCallback?: (draft: TItem | Array<TItem>) => void\n ) {\n if (typeof ids === `undefined`) {\n throw new Error(`The first argument to update is missing`)\n }\n\n const transaction = getActiveTransaction()\n if (typeof transaction === `undefined`) {\n throw `no transaction found when calling collection.update`\n }\n\n const isArray = Array.isArray(ids)\n const idsArray = (Array.isArray(ids) ? ids : [ids]).map((id) =>\n this.getKeyFromId(id)\n )\n const callback =\n typeof configOrCallback === `function` ? configOrCallback : maybeCallback!\n const config =\n typeof configOrCallback === `function` ? {} : configOrCallback\n\n // Get the current objects or empty objects if they don't exist\n const currentObjects = idsArray.map((id) => {\n const item = this.state.get(id)\n if (!item) {\n throw new Error(\n `The id \"${id}\" was passed to update but an object for this ID was not found in the collection`\n )\n }\n\n return item\n }) as unknown as Array<TItem>\n\n let changesArray\n if (isArray) {\n // Use the proxy to track changes for all objects\n changesArray = withArrayChangeTracking(\n currentObjects,\n callback as (draft: Array<TItem>) => void\n )\n } else {\n const result = withChangeTracking(\n currentObjects[0] as TItem,\n callback as (draft: TItem) => void\n )\n changesArray = [result]\n }\n\n // Create mutations for each object that has changes\n const mutations: Array<PendingMutation<T>> = idsArray\n .map((id, index) => {\n const itemChanges = changesArray[index] // User-provided changes for this specific item\n\n // Skip items with no changes\n if (!itemChanges || Object.keys(itemChanges).length === 0) {\n return null\n }\n\n const originalItem = currentObjects[index] as unknown as T\n // Validate the user-provided changes for this item\n const validatedUpdatePayload = this.validateData(\n itemChanges,\n `update`,\n id\n )\n\n // Construct the full modified item by applying the validated update payload to the original item\n const modifiedItem = { ...originalItem, ...validatedUpdatePayload }\n\n // Check if the ID of the item is being changed\n const originalItemId = this.config.getId(originalItem)\n const modifiedItemId = this.config.getId(modifiedItem)\n\n if (originalItemId !== modifiedItemId) {\n throw new Error(\n `Updating the ID of an item is not allowed. Original ID: \"${originalItemId}\", Attempted new ID: \"${modifiedItemId}\". Please delete the old item and create a new one if an ID change is necessary.`\n )\n }\n\n return {\n mutationId: crypto.randomUUID(),\n original: originalItem as Record<string, unknown>,\n modified: modifiedItem as Record<string, unknown>,\n changes: validatedUpdatePayload as Record<string, unknown>,\n key: id,\n metadata: config.metadata as unknown,\n syncMetadata: (this.syncedMetadata.state.get(id) || {}) as Record<\n string,\n unknown\n >,\n type: `update`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n })\n .filter(Boolean) as Array<PendingMutation<T>>\n\n // If no changes were made, return early\n if (mutations.length === 0) {\n throw new Error(`No changes were made to any of the objects`)\n }\n\n transaction.applyMutations(mutations)\n\n this.transactions.setState((sortedMap) => {\n sortedMap.set(transaction.id, transaction)\n return sortedMap\n })\n\n return transaction\n }\n\n /**\n * Deletes one or more items from the collection\n * @param ids - Single ID or array of IDs to delete\n * @param config - Optional configuration including metadata\n * @returns A Transaction object representing the delete operation(s)\n * @example\n * // Delete a single item\n * delete(\"todo-1\")\n *\n * // Delete multiple items\n * delete([\"todo-1\", \"todo-2\"])\n *\n * // Delete with metadata\n * delete(\"todo-1\", { metadata: { reason: \"completed\" } })\n */\n delete = (ids: Array<string> | string, config?: OperationConfig) => {\n const transaction = getActiveTransaction()\n if (typeof transaction === `undefined`) {\n throw `no transaction found when calling collection.delete`\n }\n\n const idsArray = (Array.isArray(ids) ? ids : [ids]).map((id) =>\n this.getKeyFromId(id)\n )\n const mutations: Array<PendingMutation<T>> = []\n\n for (const id of idsArray) {\n const mutation: PendingMutation<T> = {\n mutationId: crypto.randomUUID(),\n original: (this.state.get(id) || {}) as Record<string, unknown>,\n modified: (this.state.get(id) || {}) as Record<string, unknown>,\n changes: (this.state.get(id) || {}) as Record<string, unknown>,\n key: id,\n metadata: config?.metadata as unknown,\n syncMetadata: (this.syncedMetadata.state.get(id) || {}) as Record<\n string,\n unknown\n >,\n type: `delete`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n\n mutations.push(mutation)\n }\n\n transaction.applyMutations(mutations)\n\n this.transactions.setState((sortedMap) => {\n sortedMap.set(transaction.id, transaction)\n return sortedMap\n })\n\n return transaction\n }\n\n /**\n * Gets the current state of the collection as a Map\n *\n * @returns A Map containing all items in the collection, with keys as identifiers\n */\n get state() {\n return this.derivedState.state\n }\n\n /**\n * Gets the current state of the collection as a Map, but only resolves when data is available\n * Waits for the first sync commit to complete before resolving\n *\n * @returns Promise that resolves to a Map containing all items in the collection\n */\n stateWhenReady(): Promise<Map<string, T>> {\n // If we already have data or there are no loading collections, resolve immediately\n if (this.state.size > 0 || this.hasReceivedFirstCommit === true) {\n return Promise.resolve(this.state)\n }\n\n // Otherwise, wait for the first commit\n return new Promise<Map<string, T>>((resolve) => {\n this.onFirstCommit(() => {\n resolve(this.state)\n })\n })\n }\n\n /**\n * Gets the current state of the collection as an Array\n *\n * @returns An Array containing all items in the collection\n */\n get toArray() {\n return this.derivedArray.state\n }\n\n /**\n * Gets the current state of the collection as an Array, but only resolves when data is available\n * Waits for the first sync commit to complete before resolving\n *\n * @returns Promise that resolves to an Array containing all items in the collection\n */\n toArrayWhenReady(): Promise<Array<T>> {\n // If we already have data or there are no loading collections, resolve immediately\n if (this.toArray.length > 0 || this.hasReceivedFirstCommit === true) {\n return Promise.resolve(this.toArray)\n }\n\n // Otherwise, wait for the first commit\n return new Promise<Array<T>>((resolve) => {\n this.onFirstCommit(() => {\n resolve(this.toArray)\n })\n })\n }\n\n /**\n * Returns the current state of the collection as an array of changes\n * @returns An array of changes\n */\n public currentStateAsChanges(): Array<ChangeMessage<T>> {\n return [...this.state.entries()].map(([key, value]) => ({\n type: `insert`,\n key,\n value,\n }))\n }\n\n /**\n * Subscribe to changes in the collection\n * @param callback - A function that will be called with the changes in the collection\n * @returns A function that can be called to unsubscribe from the changes\n */\n public subscribeChanges(\n callback: (changes: Array<ChangeMessage<T>>) => void\n ): () => void {\n // First send the current state as changes\n callback(this.currentStateAsChanges())\n\n // Then subscribe to changes, this returns an unsubscribe function\n return this.derivedChanges.subscribe((changes) => {\n if (changes.currentVal.length > 0) {\n callback(changes.currentVal)\n }\n })\n }\n}\n"],"names":["config","result"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"collection.js","sources":["../../src/collection.ts"],"sourcesContent":["import { Derived, Store, batch } from \"@tanstack/store\"\nimport { withArrayChangeTracking, withChangeTracking } from \"./proxy\"\nimport { Transaction, getActiveTransaction } from \"./transactions\"\nimport { SortedMap } from \"./SortedMap\"\nimport type {\n ChangeMessage,\n CollectionConfig,\n Fn,\n InsertConfig,\n OperationConfig,\n OptimisticChangeMessage,\n PendingMutation,\n StandardSchema,\n Transaction as TransactionType,\n UtilsRecord,\n} from \"./types\"\n\n// Store collections in memory using Tanstack store\nexport const collectionsStore = new Store(\n new Map<string, CollectionImpl<any>>()\n)\n\n// Map to track loading collections\n\nconst loadingCollections = new Map<\n string,\n Promise<CollectionImpl<Record<string, unknown>>>\n>()\n\ninterface PendingSyncedTransaction<T extends object = Record<string, unknown>> {\n committed: boolean\n operations: Array<OptimisticChangeMessage<T>>\n}\n\n/**\n * Enhanced Collection interface that includes both data type T and utilities TUtils\n * @template T - The type of items in the collection\n * @template TUtils - The utilities record type\n */\nexport interface Collection<\n T extends object = Record<string, unknown>,\n TUtils extends UtilsRecord = {},\n> extends CollectionImpl<T> {\n readonly utils: TUtils\n}\n\n/**\n * Creates a new Collection instance with the given configuration\n *\n * @template T - The type of items in the collection\n * @template TUtils - The utilities record type\n * @param options - Collection options with optional utilities\n * @returns A new Collection with utilities exposed both at top level and under .utils\n */\nexport function createCollection<\n T extends object = Record<string, unknown>,\n TUtils extends UtilsRecord = {},\n>(options: CollectionConfig<T> & { utils?: TUtils }): Collection<T, TUtils> {\n const collection = new CollectionImpl<T>(options)\n\n // Copy utils to both top level and .utils namespace\n if (options.utils) {\n collection.utils = { ...options.utils }\n } else {\n collection.utils = {} as TUtils\n }\n\n return collection as Collection<T, TUtils>\n}\n\n/**\n * Preloads a collection with the given configuration\n * Returns a promise that resolves once the sync tool has done its first commit (initial sync is finished)\n * If the collection has already loaded, it resolves immediately\n *\n * This function is useful in route loaders or similar pre-rendering scenarios where you want\n * to ensure data is available before a route transition completes. It uses the same shared collection\n * instance that will be used by useCollection, ensuring data consistency.\n *\n * @example\n * ```typescript\n * // In a route loader\n * async function loader({ params }) {\n * await preloadCollection({\n * id: `users-${params.userId}`,\n * sync: { ... },\n * });\n *\n * return null;\n * }\n * ```\n *\n * @template T - The type of items in the collection\n * @param config - Configuration for the collection, including id and sync\n * @returns Promise that resolves when the initial sync is finished\n */\nexport function preloadCollection<T extends object = Record<string, unknown>>(\n config: CollectionConfig<T>\n): Promise<CollectionImpl<T>> {\n if (!config.id) {\n throw new Error(`The id property is required for preloadCollection`)\n }\n\n // If the collection is already fully loaded, return a resolved promise\n if (\n collectionsStore.state.has(config.id) &&\n !loadingCollections.has(config.id)\n ) {\n return Promise.resolve(\n collectionsStore.state.get(config.id)! as Collection<T>\n )\n }\n\n // If the collection is in the process of loading, return its promise\n if (loadingCollections.has(config.id)) {\n return loadingCollections.get(config.id)! as Promise<CollectionImpl<T>>\n }\n\n // Create a new collection instance if it doesn't exist\n if (!collectionsStore.state.has(config.id)) {\n collectionsStore.setState((prev) => {\n const next = new Map(prev)\n if (!config.id) {\n throw new Error(`The id property is required for preloadCollection`)\n }\n next.set(\n config.id,\n createCollection<T>({\n id: config.id,\n getId: config.getId,\n sync: config.sync,\n schema: config.schema,\n })\n )\n return next\n })\n }\n\n const collection = collectionsStore.state.get(config.id)! as Collection<T>\n\n // Create a promise that will resolve after the first commit\n let resolveFirstCommit: () => void\n const firstCommitPromise = new Promise<CollectionImpl<T>>((resolve) => {\n resolveFirstCommit = () => {\n resolve(collection as CollectionImpl<T>)\n }\n })\n\n // Register a one-time listener for the first commit\n collection.onFirstCommit(() => {\n if (!config.id) {\n throw new Error(`The id property is required for preloadCollection`)\n }\n if (loadingCollections.has(config.id)) {\n loadingCollections.delete(config.id)\n resolveFirstCommit()\n }\n })\n\n // Store the loading promise\n loadingCollections.set(\n config.id,\n firstCommitPromise as Promise<CollectionImpl<Record<string, unknown>>>\n )\n\n return firstCommitPromise\n}\n\n/**\n * Custom error class for schema validation errors\n */\nexport class SchemaValidationError extends Error {\n type: `insert` | `update`\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>\n\n constructor(\n type: `insert` | `update`,\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>,\n message?: string\n ) {\n const defaultMessage = `${type === `insert` ? `Insert` : `Update`} validation failed: ${issues\n .map((issue) => issue.message)\n .join(`, `)}`\n\n super(message || defaultMessage)\n this.name = `SchemaValidationError`\n this.type = type\n this.issues = issues\n }\n}\n\nexport class CollectionImpl<T extends object = Record<string, unknown>> {\n /**\n * Utilities namespace\n * This is populated by createCollection\n */\n public utils: Record<string, Fn> = {}\n public transactions: Store<SortedMap<string, TransactionType>>\n public optimisticOperations: Derived<Array<OptimisticChangeMessage<T>>>\n public derivedState: Derived<Map<string, T>>\n public derivedArray: Derived<Array<T>>\n public derivedChanges: Derived<Array<ChangeMessage<T>>>\n public syncedData = new Store<Map<string, T>>(new Map())\n public syncedMetadata = new Store(new Map<string, unknown>())\n private pendingSyncedTransactions: Array<PendingSyncedTransaction<T>> = []\n private syncedKeys = new Set<string>()\n public config: CollectionConfig<T>\n private hasReceivedFirstCommit = false\n\n // Array to store one-time commit listeners\n private onFirstCommitCallbacks: Array<() => void> = []\n\n /**\n * Register a callback to be executed on the next commit\n * Useful for preloading collections\n * @param callback Function to call after the next commit\n */\n public onFirstCommit(callback: () => void): void {\n this.onFirstCommitCallbacks.push(callback)\n }\n\n public id = ``\n\n /**\n * Creates a new Collection instance\n *\n * @param config - Configuration object for the collection\n * @throws Error if sync config is missing\n */\n constructor(config: CollectionConfig<T>) {\n // eslint-disable-next-line\n if (!config) {\n throw new Error(`Collection requires a config`)\n }\n if (config.id) {\n this.id = config.id\n } else {\n this.id = crypto.randomUUID()\n }\n\n // eslint-disable-next-line\n if (!config.sync) {\n throw new Error(`Collection requires a sync config`)\n }\n\n this.transactions = new Store(\n new SortedMap<string, TransactionType>(\n (a, b) => a.createdAt.getTime() - b.createdAt.getTime()\n )\n )\n\n // Copies of live mutations are stored here and removed once the transaction completes.\n this.optimisticOperations = new Derived({\n fn: ({ currDepVals: [transactions] }) => {\n const result = Array.from(transactions.values())\n .map((transaction) => {\n const isActive = ![`completed`, `failed`].includes(\n transaction.state\n )\n return transaction.mutations\n .filter((mutation) => mutation.collection === this)\n .map((mutation) => {\n const message: OptimisticChangeMessage<T> = {\n type: mutation.type,\n key: mutation.key,\n value: mutation.modified as T,\n isActive,\n }\n if (\n mutation.metadata !== undefined &&\n mutation.metadata !== null\n ) {\n message.metadata = mutation.metadata as Record<\n string,\n unknown\n >\n }\n return message\n })\n })\n .flat()\n\n return result\n },\n deps: [this.transactions],\n })\n this.optimisticOperations.mount()\n\n // Combine together synced data & optimistic operations.\n this.derivedState = new Derived({\n fn: ({ currDepVals: [syncedData, operations] }) => {\n const combined = new Map<string, T>(syncedData)\n\n // Apply the optimistic operations on top of the synced state.\n for (const operation of operations) {\n if (operation.isActive) {\n switch (operation.type) {\n case `insert`:\n combined.set(operation.key, operation.value)\n break\n case `update`:\n combined.set(operation.key, operation.value)\n break\n case `delete`:\n combined.delete(operation.key)\n break\n }\n }\n }\n\n return combined\n },\n deps: [this.syncedData, this.optimisticOperations],\n })\n\n // Create a derived array from the map to avoid recalculating it\n this.derivedArray = new Derived({\n fn: ({ currDepVals: [stateMap] }) => {\n // Collections returned by a query that has an orderBy are annotated\n // with the _orderByIndex field.\n // This is used to sort the array when it's derived.\n const array: Array<T & { _orderByIndex?: number }> = Array.from(\n stateMap.values()\n )\n if (array[0] && `_orderByIndex` in array[0]) {\n ;(array as Array<T & { _orderByIndex: number }>).sort((a, b) => {\n if (a._orderByIndex === b._orderByIndex) {\n return 0\n }\n return a._orderByIndex < b._orderByIndex ? -1 : 1\n })\n }\n return array\n },\n deps: [this.derivedState],\n })\n this.derivedArray.mount()\n\n this.derivedChanges = new Derived({\n fn: ({\n currDepVals: [derivedState, optimisticOperations],\n prevDepVals,\n }) => {\n const prevDerivedState = prevDepVals?.[0] ?? new Map<string, T>()\n const prevOptimisticOperations = prevDepVals?.[1] ?? []\n const changedKeys = new Set(this.syncedKeys)\n optimisticOperations\n .flat()\n .filter((op) => op.isActive)\n .forEach((op) => changedKeys.add(op.key))\n prevOptimisticOperations.flat().forEach((op) => {\n changedKeys.add(op.key)\n })\n\n if (changedKeys.size === 0) {\n return []\n }\n\n const changes: Array<ChangeMessage<T>> = []\n for (const key of changedKeys) {\n if (prevDerivedState.has(key) && !derivedState.has(key)) {\n changes.push({\n type: `delete`,\n key,\n value: prevDerivedState.get(key)!,\n })\n } else if (!prevDerivedState.has(key) && derivedState.has(key)) {\n changes.push({ type: `insert`, key, value: derivedState.get(key)! })\n } else if (prevDerivedState.has(key) && derivedState.has(key)) {\n const value = derivedState.get(key)!\n const previousValue = prevDerivedState.get(key)\n if (value !== previousValue) {\n // Comparing objects by reference as records are not mutated\n changes.push({\n type: `update`,\n key,\n value,\n previousValue,\n })\n }\n }\n }\n\n this.syncedKeys.clear()\n\n return changes\n },\n deps: [this.derivedState, this.optimisticOperations],\n })\n this.derivedChanges.mount()\n\n this.config = config\n\n this.derivedState.mount()\n\n // Start the sync process\n config.sync.sync({\n collection: this,\n begin: () => {\n this.pendingSyncedTransactions.push({\n committed: false,\n operations: [],\n })\n },\n write: (messageWithoutKey: Omit<ChangeMessage<T>, `key`>) => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new Error(`No pending sync transaction to write to`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't still write to it.`\n )\n }\n const key = this.generateObjectKey(\n this.config.getId(messageWithoutKey.value),\n messageWithoutKey.value\n )\n\n // Check if an item with this ID already exists when inserting\n if (messageWithoutKey.type === `insert`) {\n if (\n this.syncedData.state.has(key) &&\n !pendingTransaction.operations.some(\n (op) => op.key === key && op.type === `delete`\n )\n ) {\n const id = this.config.getId(messageWithoutKey.value)\n throw new Error(\n `Cannot insert document with ID \"${id}\" from sync because it already exists in the collection \"${this.id}\"`\n )\n }\n }\n\n const message: ChangeMessage<T> = {\n ...messageWithoutKey,\n key,\n }\n pendingTransaction.operations.push(message)\n },\n commit: () => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new Error(`No pending sync transaction to commit`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't commit it again.`\n )\n }\n\n pendingTransaction.committed = true\n\n this.commitPendingTransactions()\n },\n })\n }\n\n /**\n * Attempts to commit pending synced transactions if there are no active transactions\n * This method processes operations from pending transactions and applies them to the synced data\n */\n commitPendingTransactions = () => {\n if (\n !Array.from(this.transactions.state.values()).some(\n ({ state }) => state === `persisting`\n )\n ) {\n batch(() => {\n for (const transaction of this.pendingSyncedTransactions) {\n for (const operation of transaction.operations) {\n this.syncedKeys.add(operation.key)\n this.syncedMetadata.setState((prevData) => {\n switch (operation.type) {\n case `insert`:\n prevData.set(operation.key, operation.metadata)\n break\n case `update`:\n prevData.set(operation.key, {\n ...prevData.get(operation.key)!,\n ...operation.metadata,\n })\n break\n case `delete`:\n prevData.delete(operation.key)\n break\n }\n return prevData\n })\n this.syncedData.setState((prevData) => {\n switch (operation.type) {\n case `insert`:\n prevData.set(operation.key, operation.value)\n break\n case `update`:\n prevData.set(operation.key, {\n ...prevData.get(operation.key)!,\n ...operation.value,\n })\n break\n case `delete`:\n prevData.delete(operation.key)\n break\n }\n return prevData\n })\n }\n }\n })\n\n this.pendingSyncedTransactions = []\n\n // Call any registered one-time commit listeners\n if (!this.hasReceivedFirstCommit) {\n this.hasReceivedFirstCommit = true\n const callbacks = [...this.onFirstCommitCallbacks]\n this.onFirstCommitCallbacks = []\n callbacks.forEach((callback) => callback())\n }\n }\n }\n\n private ensureStandardSchema(schema: unknown): StandardSchema<T> {\n // If the schema already implements the standard-schema interface, return it\n if (schema && typeof schema === `object` && `~standard` in schema) {\n return schema as StandardSchema<T>\n }\n\n throw new Error(\n `Schema must either implement the standard-schema interface or be a Zod schema`\n )\n }\n\n private getKeyFromId(id: unknown): string {\n if (typeof id === `undefined`) {\n throw new Error(`id is undefined`)\n }\n if (typeof id === `string` && id.startsWith(`KEY::`)) {\n return id\n } else {\n // if it's not a string, then it's some other\n // primitive type and needs turned into a key.\n return this.generateObjectKey(id, null)\n }\n }\n\n public generateObjectKey(id: any, item: any): string {\n if (typeof id === `undefined`) {\n throw new Error(\n `An object was created without a defined id: ${JSON.stringify(item)}`\n )\n }\n\n return `KEY::${this.id}/${id}`\n }\n\n private validateData(\n data: unknown,\n type: `insert` | `update`,\n key?: string\n ): T | never {\n if (!this.config.schema) return data as T\n\n const standardSchema = this.ensureStandardSchema(this.config.schema)\n\n // For updates, we need to merge with the existing data before validation\n if (type === `update` && key) {\n // Get the existing data for this key\n const existingData = this.state.get(key)\n\n if (\n existingData &&\n data &&\n typeof data === `object` &&\n typeof existingData === `object`\n ) {\n // Merge the update with the existing data\n const mergedData = { ...existingData, ...data }\n\n // Validate the merged data\n const result = standardSchema[`~standard`].validate(mergedData)\n\n // Ensure validation is synchronous\n if (result instanceof Promise) {\n throw new TypeError(`Schema validation must be synchronous`)\n }\n\n // If validation fails, throw a SchemaValidationError with the issues\n if (`issues` in result && result.issues) {\n const typedIssues = result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((p) => String(p)),\n }))\n throw new SchemaValidationError(type, typedIssues)\n }\n\n // Return the original update data, not the merged data\n // We only used the merged data for validation\n return data as T\n }\n }\n\n // For inserts or updates without existing data, validate the data directly\n const result = standardSchema[`~standard`].validate(data)\n\n // Ensure validation is synchronous\n if (result instanceof Promise) {\n throw new TypeError(`Schema validation must be synchronous`)\n }\n\n // If validation fails, throw a SchemaValidationError with the issues\n if (`issues` in result && result.issues) {\n const typedIssues = result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((p) => String(p)),\n }))\n throw new SchemaValidationError(type, typedIssues)\n }\n\n return result.value as T\n }\n\n /**\n * Inserts one or more items into the collection\n * @param items - Single item or array of items to insert\n * @param config - Optional configuration including metadata and custom keys\n * @returns A TransactionType object representing the insert operation(s)\n * @throws {SchemaValidationError} If the data fails schema validation\n * @example\n * // Insert a single item\n * insert({ text: \"Buy groceries\", completed: false })\n *\n * // Insert multiple items\n * insert([\n * { text: \"Buy groceries\", completed: false },\n * { text: \"Walk dog\", completed: false }\n * ])\n *\n * // Insert with custom key\n * insert({ text: \"Buy groceries\" }, { key: \"grocery-task\" })\n */\n insert = (data: T | Array<T>, config?: InsertConfig) => {\n const ambientTransaction = getActiveTransaction()\n\n // If no ambient transaction exists, check for an onInsert handler early\n if (!ambientTransaction && !this.config.onInsert) {\n throw new Error(\n `Collection.insert called directly (not within an explicit transaction) but no 'onInsert' handler is configured.`\n )\n }\n\n const items = Array.isArray(data) ? data : [data]\n const mutations: Array<PendingMutation<T>> = []\n\n // Handle keys - convert to array if string, or generate if not provided\n const keys: Array<unknown> = items.map((item) =>\n this.generateObjectKey(this.config.getId(item), item)\n )\n\n // Create mutations for each item\n items.forEach((item, index) => {\n // Validate the data against the schema if one exists\n const validatedData = this.validateData(item, `insert`)\n const key = keys[index]!\n\n // Check if an item with this ID already exists in the collection\n const id = this.config.getId(item)\n if (this.state.has(this.getKeyFromId(id))) {\n throw `Cannot insert document with ID \"${id}\" because it already exists in the collection`\n }\n\n const mutation: PendingMutation<T> = {\n mutationId: crypto.randomUUID(),\n original: {},\n modified: validatedData as Record<string, unknown>,\n changes: validatedData as Record<string, unknown>,\n key,\n metadata: config?.metadata as unknown,\n syncMetadata: this.config.sync.getSyncMetadata?.() || {},\n type: `insert`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n\n mutations.push(mutation)\n })\n\n // If an ambient transaction exists, use it\n if (ambientTransaction) {\n ambientTransaction.applyMutations(mutations)\n\n this.transactions.setState((sortedMap) => {\n sortedMap.set(ambientTransaction.id, ambientTransaction)\n return sortedMap\n })\n\n return ambientTransaction\n } else {\n // Create a new transaction with a mutation function that calls the onInsert handler\n const directOpTransaction = new Transaction({\n mutationFn: async (params) => {\n // Call the onInsert handler with the transaction\n return this.config.onInsert!(params)\n },\n })\n\n // Apply mutations to the new transaction\n directOpTransaction.applyMutations(mutations)\n directOpTransaction.commit()\n\n // Add the transaction to the collection's transactions store\n this.transactions.setState((sortedMap) => {\n sortedMap.set(directOpTransaction.id, directOpTransaction)\n return sortedMap\n })\n\n return directOpTransaction\n }\n }\n\n /**\n * Updates one or more items in the collection using a callback function\n * @param items - Single item/key or array of items/keys to update\n * @param configOrCallback - Either update configuration or update callback\n * @param maybeCallback - Update callback if config was provided\n * @returns A Transaction object representing the update operation(s)\n * @throws {SchemaValidationError} If the updated data fails schema validation\n * @example\n * // Update a single item\n * update(todo, (draft) => { draft.completed = true })\n *\n * // Update multiple items\n * update([todo1, todo2], (drafts) => {\n * drafts.forEach(draft => { draft.completed = true })\n * })\n *\n * // Update with metadata\n * update(todo, { metadata: { reason: \"user update\" } }, (draft) => { draft.text = \"Updated text\" })\n */\n\n /**\n * Updates one or more items in the collection using a callback function\n * @param ids - Single ID or array of IDs to update\n * @param configOrCallback - Either update configuration or update callback\n * @param maybeCallback - Update callback if config was provided\n * @returns A Transaction object representing the update operation(s)\n * @throws {SchemaValidationError} If the updated data fails schema validation\n * @example\n * // Update a single item\n * update(\"todo-1\", (draft) => { draft.completed = true })\n *\n * // Update multiple items\n * update([\"todo-1\", \"todo-2\"], (drafts) => {\n * drafts.forEach(draft => { draft.completed = true })\n * })\n *\n * // Update with metadata\n * update(\"todo-1\", { metadata: { reason: \"user update\" } }, (draft) => { draft.text = \"Updated text\" })\n */\n update<TItem extends object = T>(\n id: unknown,\n configOrCallback: ((draft: TItem) => void) | OperationConfig,\n maybeCallback?: (draft: TItem) => void\n ): TransactionType\n\n update<TItem extends object = T>(\n ids: Array<unknown>,\n configOrCallback: ((draft: Array<TItem>) => void) | OperationConfig,\n maybeCallback?: (draft: Array<TItem>) => void\n ): TransactionType\n\n update<TItem extends object = T>(\n ids: unknown | Array<unknown>,\n configOrCallback: ((draft: TItem | Array<TItem>) => void) | OperationConfig,\n maybeCallback?: (draft: TItem | Array<TItem>) => void\n ) {\n if (typeof ids === `undefined`) {\n throw new Error(`The first argument to update is missing`)\n }\n\n const ambientTransaction = getActiveTransaction()\n\n // If no ambient transaction exists, check for an onUpdate handler early\n if (!ambientTransaction && !this.config.onUpdate) {\n throw new Error(\n `Collection.update called directly (not within an explicit transaction) but no 'onUpdate' handler is configured.`\n )\n }\n\n const isArray = Array.isArray(ids)\n const idsArray = (Array.isArray(ids) ? ids : [ids]).map((id) =>\n this.getKeyFromId(id)\n )\n const callback =\n typeof configOrCallback === `function` ? configOrCallback : maybeCallback!\n const config =\n typeof configOrCallback === `function` ? {} : configOrCallback\n\n // Get the current objects or empty objects if they don't exist\n const currentObjects = idsArray.map((id) => {\n const item = this.state.get(id)\n if (!item) {\n throw new Error(\n `The id \"${id}\" was passed to update but an object for this ID was not found in the collection`\n )\n }\n\n return item\n }) as unknown as Array<TItem>\n\n let changesArray\n if (isArray) {\n // Use the proxy to track changes for all objects\n changesArray = withArrayChangeTracking(\n currentObjects,\n callback as (draft: Array<TItem>) => void\n )\n } else {\n const result = withChangeTracking(\n currentObjects[0] as TItem,\n callback as (draft: TItem) => void\n )\n changesArray = [result]\n }\n\n // Create mutations for each object that has changes\n const mutations: Array<PendingMutation<T>> = idsArray\n .map((id, index) => {\n const itemChanges = changesArray[index] // User-provided changes for this specific item\n\n // Skip items with no changes\n if (!itemChanges || Object.keys(itemChanges).length === 0) {\n return null\n }\n\n const originalItem = currentObjects[index] as unknown as T\n // Validate the user-provided changes for this item\n const validatedUpdatePayload = this.validateData(\n itemChanges,\n `update`,\n id\n )\n\n // Construct the full modified item by applying the validated update payload to the original item\n const modifiedItem = { ...originalItem, ...validatedUpdatePayload }\n\n // Check if the ID of the item is being changed\n const originalItemId = this.config.getId(originalItem)\n const modifiedItemId = this.config.getId(modifiedItem)\n\n if (originalItemId !== modifiedItemId) {\n throw new Error(\n `Updating the ID of an item is not allowed. Original ID: \"${originalItemId}\", Attempted new ID: \"${modifiedItemId}\". Please delete the old item and create a new one if an ID change is necessary.`\n )\n }\n\n return {\n mutationId: crypto.randomUUID(),\n original: originalItem as Record<string, unknown>,\n modified: modifiedItem as Record<string, unknown>,\n changes: validatedUpdatePayload as Record<string, unknown>,\n key: id,\n metadata: config.metadata as unknown,\n syncMetadata: (this.syncedMetadata.state.get(id) || {}) as Record<\n string,\n unknown\n >,\n type: `update`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n })\n .filter(Boolean) as Array<PendingMutation<T>>\n\n // If no changes were made, return early\n if (mutations.length === 0) {\n throw new Error(`No changes were made to any of the objects`)\n }\n\n // If an ambient transaction exists, use it\n if (ambientTransaction) {\n ambientTransaction.applyMutations(mutations)\n\n this.transactions.setState((sortedMap) => {\n sortedMap.set(ambientTransaction.id, ambientTransaction)\n return sortedMap\n })\n\n return ambientTransaction\n }\n\n // No need to check for onUpdate handler here as we've already checked at the beginning\n\n // Create a new transaction with a mutation function that calls the onUpdate handler\n const directOpTransaction = new Transaction({\n mutationFn: async (transaction) => {\n // Call the onUpdate handler with the transaction\n return this.config.onUpdate!(transaction)\n },\n })\n\n // Apply mutations to the new transaction\n directOpTransaction.applyMutations(mutations)\n directOpTransaction.commit()\n\n // Add the transaction to the collection's transactions store\n this.transactions.setState((sortedMap) => {\n sortedMap.set(directOpTransaction.id, directOpTransaction)\n return sortedMap\n })\n\n return directOpTransaction\n }\n\n /**\n * Deletes one or more items from the collection\n * @param ids - Single ID or array of IDs to delete\n * @param config - Optional configuration including metadata\n * @returns A TransactionType object representing the delete operation(s)\n * @example\n * // Delete a single item\n * delete(\"todo-1\")\n *\n * // Delete multiple items\n * delete([\"todo-1\", \"todo-2\"])\n *\n * // Delete with metadata\n * delete(\"todo-1\", { metadata: { reason: \"completed\" } })\n */\n delete = (\n ids: Array<string> | string,\n config?: OperationConfig\n ): TransactionType => {\n const ambientTransaction = getActiveTransaction()\n\n // If no ambient transaction exists, check for an onDelete handler early\n if (!ambientTransaction && !this.config.onDelete) {\n throw new Error(\n `Collection.delete called directly (not within an explicit transaction) but no 'onDelete' handler is configured.`\n )\n }\n\n const idsArray = (Array.isArray(ids) ? ids : [ids]).map((id) =>\n this.getKeyFromId(id)\n )\n const mutations: Array<PendingMutation<T>> = []\n\n for (const id of idsArray) {\n const mutation: PendingMutation<T> = {\n mutationId: crypto.randomUUID(),\n original: (this.state.get(id) || {}) as Record<string, unknown>,\n modified: (this.state.get(id) || {}) as Record<string, unknown>,\n changes: (this.state.get(id) || {}) as Record<string, unknown>,\n key: id,\n metadata: config?.metadata as unknown,\n syncMetadata: (this.syncedMetadata.state.get(id) || {}) as Record<\n string,\n unknown\n >,\n type: `delete`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n\n mutations.push(mutation)\n }\n\n // If an ambient transaction exists, use it\n if (ambientTransaction) {\n ambientTransaction.applyMutations(mutations)\n\n this.transactions.setState((sortedMap) => {\n sortedMap.set(ambientTransaction.id, ambientTransaction)\n return sortedMap\n })\n\n return ambientTransaction\n }\n\n // Create a new transaction with a mutation function that calls the onDelete handler\n const directOpTransaction = new Transaction({\n autoCommit: true,\n mutationFn: async (transaction) => {\n // Call the onDelete handler with the transaction\n return this.config.onDelete!(transaction)\n },\n })\n\n // Apply mutations to the new transaction\n directOpTransaction.applyMutations(mutations)\n directOpTransaction.commit()\n\n // Add the transaction to the collection's transactions store\n this.transactions.setState((sortedMap) => {\n sortedMap.set(directOpTransaction.id, directOpTransaction)\n return sortedMap\n })\n\n return directOpTransaction\n }\n\n /**\n * Gets the current state of the collection as a Map\n *\n * @returns A Map containing all items in the collection, with keys as identifiers\n */\n get state() {\n return this.derivedState.state\n }\n\n /**\n * Gets the current state of the collection as a Map, but only resolves when data is available\n * Waits for the first sync commit to complete before resolving\n *\n * @returns Promise that resolves to a Map containing all items in the collection\n */\n stateWhenReady(): Promise<Map<string, T>> {\n // If we already have data or there are no loading collections, resolve immediately\n if (this.state.size > 0 || this.hasReceivedFirstCommit === true) {\n return Promise.resolve(this.state)\n }\n\n // Otherwise, wait for the first commit\n return new Promise<Map<string, T>>((resolve) => {\n this.onFirstCommit(() => {\n resolve(this.state)\n })\n })\n }\n\n /**\n * Gets the current state of the collection as an Array\n *\n * @returns An Array containing all items in the collection\n */\n get toArray() {\n return this.derivedArray.state\n }\n\n /**\n * Gets the current state of the collection as an Array, but only resolves when data is available\n * Waits for the first sync commit to complete before resolving\n *\n * @returns Promise that resolves to an Array containing all items in the collection\n */\n toArrayWhenReady(): Promise<Array<T>> {\n // If we already have data or there are no loading collections, resolve immediately\n if (this.toArray.length > 0 || this.hasReceivedFirstCommit === true) {\n return Promise.resolve(this.toArray)\n }\n\n // Otherwise, wait for the first commit\n return new Promise<Array<T>>((resolve) => {\n this.onFirstCommit(() => {\n resolve(this.toArray)\n })\n })\n }\n\n /**\n * Returns the current state of the collection as an array of changes\n * @returns An array of changes\n */\n public currentStateAsChanges(): Array<ChangeMessage<T>> {\n return [...this.state.entries()].map(([key, value]) => ({\n type: `insert`,\n key,\n value,\n }))\n }\n\n /**\n * Subscribe to changes in the collection\n * @param callback - A function that will be called with the changes in the collection\n * @returns A function that can be called to unsubscribe from the changes\n */\n public subscribeChanges(\n callback: (changes: Array<ChangeMessage<T>>) => void\n ): () => void {\n // First send the current state as changes\n callback(this.currentStateAsChanges())\n\n // Then subscribe to changes, this returns an unsubscribe function\n return this.derivedChanges.subscribe((changes) => {\n if (changes.currentVal.length > 0) {\n callback(changes.currentVal)\n }\n })\n }\n}\n"],"names":["config","result"],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
package/dist/esm/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CollectionImpl, SchemaValidationError, collectionsStore, createCollection, preloadCollection } from "./collection.js";
|
|
2
2
|
import { SortedMap } from "./SortedMap.js";
|
|
3
3
|
import { Transaction, createTransaction, getActiveTransaction } from "./transactions.js";
|
|
4
4
|
import { NonRetriableError } from "./errors.js";
|
|
@@ -9,7 +9,7 @@ import { CompiledQuery, compileQuery } from "./query/compiled-query.js";
|
|
|
9
9
|
import { compileQueryPipeline } from "./query/pipeline-compiler.js";
|
|
10
10
|
export {
|
|
11
11
|
BaseQueryBuilder,
|
|
12
|
-
|
|
12
|
+
CollectionImpl,
|
|
13
13
|
CompiledQuery,
|
|
14
14
|
NonRetriableError,
|
|
15
15
|
SchemaValidationError,
|
|
@@ -13,7 +13,7 @@ export declare class CompiledQuery<TResults extends object = Record<string, unkn
|
|
|
13
13
|
private version;
|
|
14
14
|
private unsubscribeEffect?;
|
|
15
15
|
constructor(queryBuilder: QueryBuilder<Context<Schema>>);
|
|
16
|
-
get results(): Collection<TResults>;
|
|
16
|
+
get results(): Collection<TResults, {}>;
|
|
17
17
|
private sendChangesToInput;
|
|
18
18
|
private sendFrontierToInput;
|
|
19
19
|
private sendFrontierToAllInputs;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { D2, MultiSet, output, MessageType } from "@electric-sql/d2ts";
|
|
2
2
|
import { batch, Effect } from "@tanstack/store";
|
|
3
|
-
import {
|
|
3
|
+
import { createCollection } from "../collection.js";
|
|
4
4
|
import { compileQueryPipeline } from "./pipeline-compiler.js";
|
|
5
5
|
function compileQuery(queryBuilder) {
|
|
6
6
|
return new CompiledQuery(queryBuilder);
|
|
@@ -69,7 +69,7 @@ class CompiledQuery {
|
|
|
69
69
|
};
|
|
70
70
|
this.graph = graph;
|
|
71
71
|
this.inputs = inputs;
|
|
72
|
-
this.resultCollection =
|
|
72
|
+
this.resultCollection = createCollection({
|
|
73
73
|
id: crypto.randomUUID(),
|
|
74
74
|
// TODO: remove when we don't require any more
|
|
75
75
|
getId: (val) => {
|