@tanstack/db 0.2.3 → 0.2.5

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.
Files changed (39) hide show
  1. package/dist/cjs/collection.cjs +23 -4
  2. package/dist/cjs/collection.cjs.map +1 -1
  3. package/dist/cjs/collection.d.cts +35 -41
  4. package/dist/cjs/local-only.cjs.map +1 -1
  5. package/dist/cjs/local-only.d.cts +17 -43
  6. package/dist/cjs/local-storage.cjs +3 -12
  7. package/dist/cjs/local-storage.cjs.map +1 -1
  8. package/dist/cjs/local-storage.d.cts +16 -39
  9. package/dist/cjs/query/builder/types.d.cts +12 -11
  10. package/dist/cjs/query/compiler/joins.cjs +4 -3
  11. package/dist/cjs/query/compiler/joins.cjs.map +1 -1
  12. package/dist/cjs/query/live/collection-subscriber.cjs +5 -1
  13. package/dist/cjs/query/live/collection-subscriber.cjs.map +1 -1
  14. package/dist/cjs/query/live-query-collection.cjs.map +1 -1
  15. package/dist/cjs/types.d.cts +10 -31
  16. package/dist/esm/collection.d.ts +35 -41
  17. package/dist/esm/collection.js +23 -4
  18. package/dist/esm/collection.js.map +1 -1
  19. package/dist/esm/local-only.d.ts +17 -43
  20. package/dist/esm/local-only.js.map +1 -1
  21. package/dist/esm/local-storage.d.ts +16 -39
  22. package/dist/esm/local-storage.js +3 -12
  23. package/dist/esm/local-storage.js.map +1 -1
  24. package/dist/esm/query/builder/types.d.ts +12 -11
  25. package/dist/esm/query/compiler/joins.js +4 -3
  26. package/dist/esm/query/compiler/joins.js.map +1 -1
  27. package/dist/esm/query/live/collection-subscriber.js +5 -1
  28. package/dist/esm/query/live/collection-subscriber.js.map +1 -1
  29. package/dist/esm/query/live-query-collection.js.map +1 -1
  30. package/dist/esm/types.d.ts +10 -31
  31. package/package.json +2 -2
  32. package/src/collection.ts +148 -196
  33. package/src/local-only.ts +57 -77
  34. package/src/local-storage.ts +53 -85
  35. package/src/query/builder/types.ts +52 -16
  36. package/src/query/compiler/joins.ts +4 -3
  37. package/src/query/live/collection-subscriber.ts +5 -1
  38. package/src/query/live-query-collection.ts +1 -1
  39. package/src/types.ts +25 -55
@@ -4,7 +4,7 @@ import { IndexProxy } from './indexes/lazy-index.js';
4
4
  import { Transaction } from './transactions.js';
5
5
  import { StandardSchemaV1 } from '@standard-schema/spec';
6
6
  import { SingleRowRefProxy } from './query/builder/ref-proxy.js';
7
- import { ChangeListener, ChangeMessage, CollectionConfig, CollectionStatus, CurrentStateAsChangesOptions, Fn, InsertConfig, OperationConfig, OptimisticChangeMessage, ResolveInsertInput, ResolveType, SubscribeChangesOptions, Transaction as TransactionType, UtilsRecord, WritableDeep } from './types.js';
7
+ import { ChangeListener, ChangeMessage, CollectionConfig, CollectionStatus, CurrentStateAsChangesOptions, Fn, InferSchemaInput, InferSchemaOutput, InsertConfig, OperationConfig, OptimisticChangeMessage, SubscribeChangesOptions, Transaction as TransactionType, UtilsRecord, WritableDeep } from './types.js';
8
8
  import { IndexOptions } from './indexes/index-options.js';
9
9
  import { BaseIndex, IndexResolver } from './indexes/base-index.js';
10
10
  interface PendingSyncedTransaction<T extends object = Record<string, unknown>> {
@@ -26,11 +26,9 @@ export interface Collection<T extends object = Record<string, unknown>, TKey ext
26
26
  /**
27
27
  * Creates a new Collection instance with the given configuration
28
28
  *
29
- * @template TExplicit - The explicit type of items in the collection (highest priority)
29
+ * @template T - The schema type if a schema is provided, otherwise the type of items in the collection
30
30
  * @template TKey - The type of the key for the collection
31
31
  * @template TUtils - The utilities record type
32
- * @template TSchema - The schema type for validation and type inference (second priority)
33
- * @template TFallback - The fallback type if no explicit or schema type is provided
34
32
  * @param options - Collection options with optional utilities
35
33
  * @returns A new Collection with utilities exposed both at top level and under .utils
36
34
  *
@@ -94,26 +92,22 @@ export interface Collection<T extends object = Record<string, unknown>, TKey ext
94
92
  * sync: { sync: () => {} }
95
93
  * })
96
94
  *
97
- * // Note: You can provide an explicit type, a schema, or both. When both are provided, the explicit type takes precedence.
98
95
  */
99
- export declare function createCollection<TSchema extends StandardSchemaV1, TKey extends string | number = string | number, TUtils extends UtilsRecord = {}, TFallback extends object = Record<string, unknown>>(options: CollectionConfig<ResolveType<unknown, TSchema, TFallback>, TKey, TSchema, ResolveInsertInput<unknown, TSchema, TFallback>> & {
100
- schema: TSchema;
96
+ export declare function createCollection<T extends StandardSchemaV1, TKey extends string | number = string | number, TUtils extends UtilsRecord = {}>(options: CollectionConfig<InferSchemaOutput<T>, TKey, T> & {
97
+ schema: T;
101
98
  utils?: TUtils;
102
- }): Collection<ResolveType<unknown, TSchema, TFallback>, TKey, TUtils, TSchema, ResolveInsertInput<unknown, TSchema, TFallback>>;
103
- export declare function createCollection<TExplicit extends object, TKey extends string | number = string | number, TUtils extends UtilsRecord = {}, TSchema extends StandardSchemaV1 = StandardSchemaV1, TFallback extends object = Record<string, unknown>>(options: CollectionConfig<ResolveType<TExplicit, TSchema, TFallback>, TKey, TSchema, ResolveInsertInput<TExplicit, TSchema, TFallback>> & {
104
- schema: TSchema;
99
+ }): Collection<InferSchemaOutput<T>, TKey, TUtils, T, InferSchemaInput<T>>;
100
+ export declare function createCollection<T extends object, TKey extends string | number = string | number, TUtils extends UtilsRecord = {}>(options: CollectionConfig<T, TKey, never> & {
101
+ schema?: never;
105
102
  utils?: TUtils;
106
- }): Collection<ResolveType<TExplicit, TSchema, TFallback>, TKey, TUtils, TSchema, ResolveInsertInput<TExplicit, TSchema, TFallback>>;
107
- export declare function createCollection<TExplicit = unknown, TKey extends string | number = string | number, TUtils extends UtilsRecord = {}, TSchema extends StandardSchemaV1 = StandardSchemaV1, TFallback extends object = Record<string, unknown>>(options: CollectionConfig<ResolveType<TExplicit, TSchema, TFallback>, TKey, TSchema, ResolveInsertInput<TExplicit, TSchema, TFallback>> & {
108
- utils?: TUtils;
109
- }): Collection<ResolveType<TExplicit, TSchema, TFallback>, TKey, TUtils, TSchema, ResolveInsertInput<TExplicit, TSchema, TFallback>>;
110
- export declare class CollectionImpl<T extends object = Record<string, unknown>, TKey extends string | number = string | number, TUtils extends UtilsRecord = {}, TSchema extends StandardSchemaV1 = StandardSchemaV1, TInsertInput extends object = T> {
111
- config: CollectionConfig<T, TKey, TSchema, TInsertInput>;
103
+ }): Collection<T, TKey, TUtils, never, T>;
104
+ export declare class CollectionImpl<TOutput extends object = Record<string, unknown>, TKey extends string | number = string | number, TUtils extends UtilsRecord = {}, TSchema extends StandardSchemaV1 = StandardSchemaV1, TInput extends object = TOutput> {
105
+ config: CollectionConfig<TOutput, TKey, TSchema>;
112
106
  transactions: SortedMap<string, Transaction<any>>;
113
- pendingSyncedTransactions: Array<PendingSyncedTransaction<T>>;
114
- syncedData: Map<TKey, T> | SortedMap<TKey, T>;
107
+ pendingSyncedTransactions: Array<PendingSyncedTransaction<TOutput>>;
108
+ syncedData: Map<TKey, TOutput> | SortedMap<TKey, TOutput>;
115
109
  syncedMetadata: Map<TKey, unknown>;
116
- optimisticUpserts: Map<TKey, T>;
110
+ optimisticUpserts: Map<TKey, TOutput>;
117
111
  optimisticDeletes: Set<TKey>;
118
112
  private _size;
119
113
  private lazyIndexes;
@@ -194,7 +188,7 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
194
188
  * @param config - Configuration object for the collection
195
189
  * @throws Error if sync config is missing
196
190
  */
197
- constructor(config: CollectionConfig<T, TKey, TSchema, TInsertInput>);
191
+ constructor(config: CollectionConfig<TOutput, TKey, TSchema>);
198
192
  /**
199
193
  * Start sync immediately - internal method for compiled queries
200
194
  * This bypasses lazy loading for special cases like live query results
@@ -261,7 +255,7 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
261
255
  /**
262
256
  * Get the current value for a key (virtual derived state)
263
257
  */
264
- get(key: TKey): T | undefined;
258
+ get(key: TKey): TOutput | undefined;
265
259
  /**
266
260
  * Check if a key exists in the collection (virtual derived state)
267
261
  */
@@ -277,23 +271,23 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
277
271
  /**
278
272
  * Get all values (virtual derived state)
279
273
  */
280
- values(): IterableIterator<T>;
274
+ values(): IterableIterator<TOutput>;
281
275
  /**
282
276
  * Get all entries (virtual derived state)
283
277
  */
284
- entries(): IterableIterator<[TKey, T]>;
278
+ entries(): IterableIterator<[TKey, TOutput]>;
285
279
  /**
286
280
  * Get all entries (virtual derived state)
287
281
  */
288
- [Symbol.iterator](): IterableIterator<[TKey, T]>;
282
+ [Symbol.iterator](): IterableIterator<[TKey, TOutput]>;
289
283
  /**
290
284
  * Execute a callback for each entry in the collection
291
285
  */
292
- forEach(callbackfn: (value: T, key: TKey, index: number) => void): void;
286
+ forEach(callbackfn: (value: TOutput, key: TKey, index: number) => void): void;
293
287
  /**
294
288
  * Create a new array with the results of calling a function for each entry in the collection
295
289
  */
296
- map<U>(callbackfn: (value: T, key: TKey, index: number) => U): Array<U>;
290
+ map<U>(callbackfn: (value: TOutput, key: TKey, index: number) => U): Array<U>;
297
291
  /**
298
292
  * Attempts to commit pending synced transactions if there are no active transactions
299
293
  * This method processes operations from pending transactions and applies them to the synced data
@@ -305,7 +299,7 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
305
299
  */
306
300
  private scheduleTransactionCleanup;
307
301
  private ensureStandardSchema;
308
- getKeyFromItem(item: T): TKey;
302
+ getKeyFromItem(item: TOutput): TKey;
309
303
  generateGlobalKey(key: any, item: any): string;
310
304
  /**
311
305
  * Creates an index on a collection for faster queries.
@@ -337,7 +331,7 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
337
331
  * options: { language: 'en' }
338
332
  * })
339
333
  */
340
- createIndex<TResolver extends IndexResolver<TKey> = typeof BTreeIndex>(indexCallback: (row: SingleRowRefProxy<T>) => any, config?: IndexOptions<TResolver>): IndexProxy<TKey>;
334
+ createIndex<TResolver extends IndexResolver<TKey> = typeof BTreeIndex>(indexCallback: (row: SingleRowRefProxy<TOutput>) => any, config?: IndexOptions<TResolver>): IndexProxy<TKey>;
341
335
  /**
342
336
  * Resolve all lazy indexes (called when collection first syncs)
343
337
  * @private
@@ -357,7 +351,7 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
357
351
  * @private
358
352
  */
359
353
  private updateIndexes;
360
- validateData(data: unknown, type: `insert` | `update`, key?: TKey): T | never;
354
+ validateData(data: unknown, type: `insert` | `update`, key?: TKey): TOutput | never;
361
355
  /**
362
356
  * Inserts one or more items into the collection
363
357
  * @param items - Single item or array of items to insert
@@ -394,7 +388,7 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
394
388
  * console.log('Insert failed:', error)
395
389
  * }
396
390
  */
397
- insert: (data: TInsertInput | Array<TInsertInput>, config?: InsertConfig) => Transaction<Record<string, unknown>> | Transaction<T>;
391
+ insert: (data: TInput | Array<TInput>, config?: InsertConfig) => Transaction<Record<string, unknown>> | Transaction<TOutput>;
398
392
  /**
399
393
  * Updates one or more items in the collection using a callback function
400
394
  * @param keys - Single key or array of keys to update
@@ -434,10 +428,10 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
434
428
  * console.log('Update failed:', error)
435
429
  * }
436
430
  */
437
- update<TItem extends object = T>(key: Array<TKey | unknown>, callback: (drafts: Array<WritableDeep<TItem>>) => void): TransactionType;
438
- update<TItem extends object = T>(keys: Array<TKey | unknown>, config: OperationConfig, callback: (drafts: Array<WritableDeep<TItem>>) => void): TransactionType;
439
- update<TItem extends object = T>(id: TKey | unknown, callback: (draft: WritableDeep<TItem>) => void): TransactionType;
440
- update<TItem extends object = T>(id: TKey | unknown, config: OperationConfig, callback: (draft: WritableDeep<TItem>) => void): TransactionType;
431
+ update(key: Array<TKey | unknown>, callback: (drafts: Array<WritableDeep<TInput>>) => void): TransactionType;
432
+ update(keys: Array<TKey | unknown>, config: OperationConfig, callback: (drafts: Array<WritableDeep<TInput>>) => void): TransactionType;
433
+ update(id: TKey | unknown, callback: (draft: WritableDeep<TInput>) => void): TransactionType;
434
+ update(id: TKey | unknown, config: OperationConfig, callback: (draft: WritableDeep<TInput>) => void): TransactionType;
441
435
  /**
442
436
  * Deletes one or more items from the collection
443
437
  * @param keys - Single key or array of keys to delete
@@ -485,27 +479,27 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
485
479
  * console.log("Todo 1 exists:", itemsMap.get("todo-1"))
486
480
  * }
487
481
  */
488
- get state(): Map<TKey, T>;
482
+ get state(): Map<TKey, TOutput>;
489
483
  /**
490
484
  * Gets the current state of the collection as a Map, but only resolves when data is available
491
485
  * Waits for the first sync commit to complete before resolving
492
486
  *
493
487
  * @returns Promise that resolves to a Map containing all items in the collection
494
488
  */
495
- stateWhenReady(): Promise<Map<TKey, T>>;
489
+ stateWhenReady(): Promise<Map<TKey, TOutput>>;
496
490
  /**
497
491
  * Gets the current state of the collection as an Array
498
492
  *
499
493
  * @returns An Array containing all items in the collection
500
494
  */
501
- get toArray(): T[];
495
+ get toArray(): TOutput[];
502
496
  /**
503
497
  * Gets the current state of the collection as an Array, but only resolves when data is available
504
498
  * Waits for the first sync commit to complete before resolving
505
499
  *
506
500
  * @returns Promise that resolves to an Array containing all items in the collection
507
501
  */
508
- toArrayWhenReady(): Promise<Array<T>>;
502
+ toArrayWhenReady(): Promise<Array<TOutput>>;
509
503
  /**
510
504
  * Returns the current state of the collection as an array of changes
511
505
  * @param options - Options including optional where filter
@@ -524,7 +518,7 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
524
518
  * whereExpression: eq(row.status, 'active')
525
519
  * })
526
520
  */
527
- currentStateAsChanges(options?: CurrentStateAsChangesOptions<T>): Array<ChangeMessage<T>>;
521
+ currentStateAsChanges(options?: CurrentStateAsChangesOptions<TOutput>): Array<ChangeMessage<TOutput>>;
528
522
  /**
529
523
  * Subscribe to changes in the collection
530
524
  * @param callback - Function called when items change
@@ -564,11 +558,11 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
564
558
  * whereExpression: eq(row.status, 'active')
565
559
  * })
566
560
  */
567
- subscribeChanges(callback: (changes: Array<ChangeMessage<T>>) => void, options?: SubscribeChangesOptions<T>): () => void;
561
+ subscribeChanges(callback: (changes: Array<ChangeMessage<TOutput>>) => void, options?: SubscribeChangesOptions<TOutput>): () => void;
568
562
  /**
569
563
  * Subscribe to changes for a specific key
570
564
  */
571
- subscribeChangesKey(key: TKey, listener: ChangeListener<T, TKey>, { includeInitialState }?: {
565
+ subscribeChangesKey(key: TKey, listener: ChangeListener<TOutput, TKey>, { includeInitialState }?: {
572
566
  includeInitialState?: boolean;
573
567
  }): () => void;
574
568
  /**
@@ -9,7 +9,9 @@ import { getActiveTransaction, createTransaction } from "./transactions.js";
9
9
  import { MissingInsertHandlerError, DuplicateKeyError, MissingDeleteHandlerError, NoKeysPassedToDeleteError, DeleteKeyNotFoundError, CollectionRequiresConfigError, CollectionRequiresSyncConfigError, CollectionInErrorStateError, InvalidCollectionStatusTransitionError, NoPendingSyncTransactionWriteError, SyncTransactionAlreadyCommittedWriteError, NoPendingSyncTransactionCommitError, SyncTransactionAlreadyCommittedError, DuplicateKeySyncError, CollectionIsInErrorStateError, SyncCleanupError, NegativeActiveSubscribersError, InvalidSchemaError, UndefinedKeyError, SchemaMustBeSynchronousError, SchemaValidationError, MissingUpdateArgumentError, MissingUpdateHandlerError, NoKeysPassedToUpdateError, UpdateKeyNotFoundError, KeyUpdateNotAllowedError } from "./errors.js";
10
10
  import { currentStateAsChanges, createFilteredCallback } from "./change-events.js";
11
11
  function createCollection(options) {
12
- const collection = new CollectionImpl(options);
12
+ const collection = new CollectionImpl(
13
+ options
14
+ );
13
15
  if (options.utils) {
14
16
  collection.utils = { ...options.utils };
15
17
  } else {
@@ -802,7 +804,10 @@ class CollectionImpl {
802
804
  switch (mutation.type) {
803
805
  case `insert`:
804
806
  case `update`:
805
- this.optimisticUpserts.set(mutation.key, mutation.modified);
807
+ this.optimisticUpserts.set(
808
+ mutation.key,
809
+ mutation.modified
810
+ );
806
811
  this.optimisticDeletes.delete(mutation.key);
807
812
  break;
808
813
  case `delete`:
@@ -1234,7 +1239,12 @@ class CollectionImpl {
1234
1239
  });
1235
1240
  throw new SchemaValidationError(type, typedIssues);
1236
1241
  }
1237
- return data;
1242
+ const validatedMergedData = result2.value;
1243
+ const modifiedKeys = Object.keys(data);
1244
+ const extractedChanges = Object.fromEntries(
1245
+ modifiedKeys.map((k) => [k, validatedMergedData[k]])
1246
+ );
1247
+ return extractedChanges;
1238
1248
  }
1239
1249
  }
1240
1250
  const result = standardSchema[`~standard`].validate(data);
@@ -1315,7 +1325,16 @@ class CollectionImpl {
1315
1325
  mutationId: crypto.randomUUID(),
1316
1326
  original: originalItem,
1317
1327
  modified: modifiedItem,
1318
- changes: validatedUpdatePayload,
1328
+ // Pick the values from modifiedItem based on what's passed in - this is for cases
1329
+ // where a schema has default values or transforms. The modified data has the extra
1330
+ // default or transformed values but for changes, we just want to show the data that
1331
+ // was actually passed in.
1332
+ changes: Object.fromEntries(
1333
+ Object.keys(itemChanges).map((k) => [
1334
+ k,
1335
+ modifiedItem[k]
1336
+ ])
1337
+ ),
1319
1338
  globalKey,
1320
1339
  key,
1321
1340
  metadata: config.metadata,