@tanstack/db 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import { SortedMap } from './SortedMap.cjs';
2
2
  import { BTreeIndex } from './indexes/btree-index.js';
3
3
  import { IndexProxy } from './indexes/lazy-index.js';
4
+ import { AllCollectionEvents, CollectionEventHandler } from './collection-events.js';
4
5
  import { Transaction } from './transactions.cjs';
5
6
  import { StandardSchemaV1 } from '@standard-schema/spec';
6
7
  import { SingleRowRefProxy } from './query/builder/ref-proxy.cjs';
@@ -131,6 +132,7 @@ export declare class CollectionImpl<TOutput extends object = Record<string, unkn
131
132
  private gcTimeoutId;
132
133
  private preloadPromise;
133
134
  private syncCleanupFn;
135
+ private events;
134
136
  /**
135
137
  * Register a callback to be executed when the collection first becomes ready
136
138
  * Useful for preloading collections
@@ -167,6 +169,10 @@ export declare class CollectionImpl<TOutput extends object = Record<string, unkn
167
169
  * Gets the current status of the collection
168
170
  */
169
171
  get status(): CollectionStatus;
172
+ /**
173
+ * Get the number of subscribers to the collection
174
+ */
175
+ get subscriberCount(): number;
170
176
  /**
171
177
  * Validates that the collection is in a usable state for data operations
172
178
  * @private
@@ -575,5 +581,21 @@ export declare class CollectionImpl<TOutput extends object = Record<string, unkn
575
581
  * This method should be called by the Transaction class when state changes
576
582
  */
577
583
  onTransactionStateChange(): void;
584
+ /**
585
+ * Subscribe to a collection event
586
+ */
587
+ on<T extends keyof AllCollectionEvents>(event: T, callback: CollectionEventHandler<T>): () => void;
588
+ /**
589
+ * Subscribe to a collection event once
590
+ */
591
+ once<T extends keyof AllCollectionEvents>(event: T, callback: CollectionEventHandler<T>): () => void;
592
+ /**
593
+ * Unsubscribe from a collection event
594
+ */
595
+ off<T extends keyof AllCollectionEvents>(event: T, callback: CollectionEventHandler<T>): void;
596
+ /**
597
+ * Wait for a collection event
598
+ */
599
+ waitFor<T extends keyof AllCollectionEvents>(event: T, timeout?: number): Promise<AllCollectionEvents[T]>;
578
600
  }
579
601
  export {};
@@ -0,0 +1,50 @@
1
+ import { Collection } from './collection.js';
2
+ import { CollectionStatus } from './types.js';
3
+ /**
4
+ * Event emitted when the collection status changes
5
+ */
6
+ export interface CollectionStatusChangeEvent {
7
+ type: `status:change`;
8
+ collection: Collection;
9
+ previousStatus: CollectionStatus;
10
+ status: CollectionStatus;
11
+ }
12
+ /**
13
+ * Event emitted when the collection status changes to a specific status
14
+ */
15
+ export interface CollectionStatusEvent<T extends CollectionStatus> {
16
+ type: `status:${T}`;
17
+ collection: Collection;
18
+ previousStatus: CollectionStatus;
19
+ status: T;
20
+ }
21
+ /**
22
+ * Event emitted when the number of subscribers to the collection changes
23
+ */
24
+ export interface CollectionSubscribersChangeEvent {
25
+ type: `subscribers:change`;
26
+ collection: Collection;
27
+ previousSubscriberCount: number;
28
+ subscriberCount: number;
29
+ }
30
+ export type AllCollectionEvents = {
31
+ "status:change": CollectionStatusChangeEvent;
32
+ "subscribers:change": CollectionSubscribersChangeEvent;
33
+ } & {
34
+ [K in CollectionStatus as `status:${K}`]: CollectionStatusEvent<K>;
35
+ };
36
+ export type CollectionEvent = AllCollectionEvents[keyof AllCollectionEvents] | CollectionStatusChangeEvent | CollectionSubscribersChangeEvent;
37
+ export type CollectionEventHandler<T extends keyof AllCollectionEvents> = (event: AllCollectionEvents[T]) => void;
38
+ export declare class CollectionEvents {
39
+ private collection;
40
+ private listeners;
41
+ constructor(collection: Collection<any, any, any, any, any>);
42
+ on<T extends keyof AllCollectionEvents>(event: T, callback: CollectionEventHandler<T>): () => void;
43
+ once<T extends keyof AllCollectionEvents>(event: T, callback: CollectionEventHandler<T>): () => void;
44
+ off<T extends keyof AllCollectionEvents>(event: T, callback: CollectionEventHandler<T>): void;
45
+ waitFor<T extends keyof AllCollectionEvents>(event: T, timeout?: number): Promise<AllCollectionEvents[T]>;
46
+ emit<T extends keyof AllCollectionEvents>(event: T, eventPayload: AllCollectionEvents[T]): void;
47
+ emitStatusChange<T extends CollectionStatus>(status: T, previousStatus: CollectionStatus): void;
48
+ emitSubscribersChange(subscriberCount: number, previousSubscriberCount: number): void;
49
+ cleanup(): void;
50
+ }
@@ -0,0 +1,88 @@
1
+ class CollectionEvents {
2
+ constructor(collection) {
3
+ this.listeners = /* @__PURE__ */ new Map();
4
+ this.collection = collection;
5
+ }
6
+ on(event, callback) {
7
+ if (!this.listeners.has(event)) {
8
+ this.listeners.set(event, /* @__PURE__ */ new Set());
9
+ }
10
+ this.listeners.get(event).add(callback);
11
+ return () => {
12
+ this.listeners.get(event).delete(callback);
13
+ };
14
+ }
15
+ once(event, callback) {
16
+ const unsubscribe = this.on(event, (eventPayload) => {
17
+ callback(eventPayload);
18
+ unsubscribe();
19
+ });
20
+ return unsubscribe;
21
+ }
22
+ off(event, callback) {
23
+ var _a;
24
+ (_a = this.listeners.get(event)) == null ? void 0 : _a.delete(callback);
25
+ }
26
+ waitFor(event, timeout) {
27
+ return new Promise((resolve, reject) => {
28
+ let timeoutId;
29
+ const unsubscribe = this.on(event, (eventPayload) => {
30
+ if (timeoutId) {
31
+ clearTimeout(timeoutId);
32
+ timeoutId = void 0;
33
+ }
34
+ resolve(eventPayload);
35
+ unsubscribe();
36
+ });
37
+ if (timeout) {
38
+ timeoutId = setTimeout(() => {
39
+ timeoutId = void 0;
40
+ unsubscribe();
41
+ reject(new Error(`Timeout waiting for event ${event}`));
42
+ }, timeout);
43
+ }
44
+ });
45
+ }
46
+ emit(event, eventPayload) {
47
+ var _a;
48
+ (_a = this.listeners.get(event)) == null ? void 0 : _a.forEach((listener) => {
49
+ try {
50
+ listener(eventPayload);
51
+ } catch (error) {
52
+ queueMicrotask(() => {
53
+ throw error;
54
+ });
55
+ }
56
+ });
57
+ }
58
+ emitStatusChange(status, previousStatus) {
59
+ this.emit(`status:change`, {
60
+ type: `status:change`,
61
+ collection: this.collection,
62
+ previousStatus,
63
+ status
64
+ });
65
+ const eventKey = `status:${status}`;
66
+ this.emit(eventKey, {
67
+ type: eventKey,
68
+ collection: this.collection,
69
+ previousStatus,
70
+ status
71
+ });
72
+ }
73
+ emitSubscribersChange(subscriberCount, previousSubscriberCount) {
74
+ this.emit(`subscribers:change`, {
75
+ type: `subscribers:change`,
76
+ collection: this.collection,
77
+ previousSubscriberCount,
78
+ subscriberCount
79
+ });
80
+ }
81
+ cleanup() {
82
+ this.listeners.clear();
83
+ }
84
+ }
85
+ export {
86
+ CollectionEvents
87
+ };
88
+ //# sourceMappingURL=collection-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-events.js","sources":["../../src/collection-events.ts"],"sourcesContent":["import type { Collection } from \"./collection\"\nimport type { CollectionStatus } from \"./types\"\n\n/**\n * Event emitted when the collection status changes\n */\nexport interface CollectionStatusChangeEvent {\n type: `status:change`\n collection: Collection\n previousStatus: CollectionStatus\n status: CollectionStatus\n}\n\n/**\n * Event emitted when the collection status changes to a specific status\n */\nexport interface CollectionStatusEvent<T extends CollectionStatus> {\n type: `status:${T}`\n collection: Collection\n previousStatus: CollectionStatus\n status: T\n}\n\n/**\n * Event emitted when the number of subscribers to the collection changes\n */\nexport interface CollectionSubscribersChangeEvent {\n type: `subscribers:change`\n collection: Collection\n previousSubscriberCount: number\n subscriberCount: number\n}\n\nexport type AllCollectionEvents = {\n \"status:change\": CollectionStatusChangeEvent\n \"subscribers:change\": CollectionSubscribersChangeEvent\n} & {\n [K in CollectionStatus as `status:${K}`]: CollectionStatusEvent<K>\n}\n\nexport type CollectionEvent =\n | AllCollectionEvents[keyof AllCollectionEvents]\n | CollectionStatusChangeEvent\n | CollectionSubscribersChangeEvent\n\nexport type CollectionEventHandler<T extends keyof AllCollectionEvents> = (\n event: AllCollectionEvents[T]\n) => void\n\nexport class CollectionEvents {\n private collection: Collection<any, any, any, any, any>\n private listeners = new Map<\n keyof AllCollectionEvents,\n Set<CollectionEventHandler<any>>\n >()\n\n constructor(collection: Collection<any, any, any, any, any>) {\n this.collection = collection\n }\n\n on<T extends keyof AllCollectionEvents>(\n event: T,\n callback: CollectionEventHandler<T>\n ) {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set())\n }\n this.listeners.get(event)!.add(callback)\n\n return () => {\n this.listeners.get(event)!.delete(callback)\n }\n }\n\n once<T extends keyof AllCollectionEvents>(\n event: T,\n callback: CollectionEventHandler<T>\n ) {\n const unsubscribe = this.on(event, (eventPayload) => {\n callback(eventPayload)\n unsubscribe()\n })\n return unsubscribe\n }\n\n off<T extends keyof AllCollectionEvents>(\n event: T,\n callback: CollectionEventHandler<T>\n ) {\n this.listeners.get(event)?.delete(callback)\n }\n\n waitFor<T extends keyof AllCollectionEvents>(\n event: T,\n timeout?: number\n ): Promise<AllCollectionEvents[T]> {\n return new Promise((resolve, reject) => {\n let timeoutId: NodeJS.Timeout | undefined\n const unsubscribe = this.on(event, (eventPayload) => {\n if (timeoutId) {\n clearTimeout(timeoutId)\n timeoutId = undefined\n }\n resolve(eventPayload)\n unsubscribe()\n })\n if (timeout) {\n timeoutId = setTimeout(() => {\n timeoutId = undefined\n unsubscribe()\n reject(new Error(`Timeout waiting for event ${event}`))\n }, timeout)\n }\n })\n }\n\n emit<T extends keyof AllCollectionEvents>(\n event: T,\n eventPayload: AllCollectionEvents[T]\n ) {\n this.listeners.get(event)?.forEach((listener) => {\n try {\n listener(eventPayload)\n } catch (error) {\n // Re-throw in a microtask to surface the error\n queueMicrotask(() => {\n throw error\n })\n }\n })\n }\n\n emitStatusChange<T extends CollectionStatus>(\n status: T,\n previousStatus: CollectionStatus\n ) {\n this.emit(`status:change`, {\n type: `status:change`,\n collection: this.collection,\n previousStatus,\n status,\n })\n\n // Emit specific status event using type assertion\n const eventKey: `status:${T}` = `status:${status}`\n this.emit(eventKey, {\n type: eventKey,\n collection: this.collection,\n previousStatus,\n status,\n } as AllCollectionEvents[`status:${T}`])\n }\n\n emitSubscribersChange(\n subscriberCount: number,\n previousSubscriberCount: number\n ) {\n this.emit(`subscribers:change`, {\n type: `subscribers:change`,\n collection: this.collection,\n previousSubscriberCount,\n subscriberCount,\n })\n }\n\n cleanup() {\n this.listeners.clear()\n }\n}\n"],"names":[],"mappings":"AAiDO,MAAM,iBAAiB;AAAA,EAO5B,YAAY,YAAiD;AAL7D,SAAQ,gCAAgB,IAAA;AAMtB,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,GACE,OACA,UACA;AACA,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,GAAG;AAC9B,WAAK,UAAU,IAAI,OAAO,oBAAI,KAAK;AAAA,IACrC;AACA,SAAK,UAAU,IAAI,KAAK,EAAG,IAAI,QAAQ;AAEvC,WAAO,MAAM;AACX,WAAK,UAAU,IAAI,KAAK,EAAG,OAAO,QAAQ;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,KACE,OACA,UACA;AACA,UAAM,cAAc,KAAK,GAAG,OAAO,CAAC,iBAAiB;AACnD,eAAS,YAAY;AACrB,kBAAA;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,IACE,OACA,UACA;AAvCG;AAwCH,eAAK,UAAU,IAAI,KAAK,MAAxB,mBAA2B,OAAO;AAAA,EACpC;AAAA,EAEA,QACE,OACA,SACiC;AACjC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI;AACJ,YAAM,cAAc,KAAK,GAAG,OAAO,CAAC,iBAAiB;AACnD,YAAI,WAAW;AACb,uBAAa,SAAS;AACtB,sBAAY;AAAA,QACd;AACA,gBAAQ,YAAY;AACpB,oBAAA;AAAA,MACF,CAAC;AACD,UAAI,SAAS;AACX,oBAAY,WAAW,MAAM;AAC3B,sBAAY;AACZ,sBAAA;AACA,iBAAO,IAAI,MAAM,6BAA6B,KAAK,EAAE,CAAC;AAAA,QACxD,GAAG,OAAO;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,KACE,OACA,cACA;AAtEG;AAuEH,eAAK,UAAU,IAAI,KAAK,MAAxB,mBAA2B,QAAQ,CAAC,aAAa;AAC/C,UAAI;AACF,iBAAS,YAAY;AAAA,MACvB,SAAS,OAAO;AAEd,uBAAe,MAAM;AACnB,gBAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,iBACE,QACA,gBACA;AACA,SAAK,KAAK,iBAAiB;AAAA,MACzB,MAAM;AAAA,MACN,YAAY,KAAK;AAAA,MACjB;AAAA,MACA;AAAA,IAAA,CACD;AAGD,UAAM,WAA0B,UAAU,MAAM;AAChD,SAAK,KAAK,UAAU;AAAA,MAClB,MAAM;AAAA,MACN,YAAY,KAAK;AAAA,MACjB;AAAA,MACA;AAAA,IAAA,CACqC;AAAA,EACzC;AAAA,EAEA,sBACE,iBACA,yBACA;AACA,SAAK,KAAK,sBAAsB;AAAA,MAC9B,MAAM;AAAA,MACN,YAAY,KAAK;AAAA,MACjB;AAAA,MACA;AAAA,IAAA,CACD;AAAA,EACH;AAAA,EAEA,UAAU;AACR,SAAK,UAAU,MAAA;AAAA,EACjB;AACF;"}
@@ -1,6 +1,7 @@
1
1
  import { SortedMap } from './SortedMap.js';
2
2
  import { BTreeIndex } from './indexes/btree-index.js';
3
3
  import { IndexProxy } from './indexes/lazy-index.js';
4
+ import { AllCollectionEvents, CollectionEventHandler } from './collection-events.js';
4
5
  import { Transaction } from './transactions.js';
5
6
  import { StandardSchemaV1 } from '@standard-schema/spec';
6
7
  import { SingleRowRefProxy } from './query/builder/ref-proxy.js';
@@ -131,6 +132,7 @@ export declare class CollectionImpl<TOutput extends object = Record<string, unkn
131
132
  private gcTimeoutId;
132
133
  private preloadPromise;
133
134
  private syncCleanupFn;
135
+ private events;
134
136
  /**
135
137
  * Register a callback to be executed when the collection first becomes ready
136
138
  * Useful for preloading collections
@@ -167,6 +169,10 @@ export declare class CollectionImpl<TOutput extends object = Record<string, unkn
167
169
  * Gets the current status of the collection
168
170
  */
169
171
  get status(): CollectionStatus;
172
+ /**
173
+ * Get the number of subscribers to the collection
174
+ */
175
+ get subscriberCount(): number;
170
176
  /**
171
177
  * Validates that the collection is in a usable state for data operations
172
178
  * @private
@@ -575,5 +581,21 @@ export declare class CollectionImpl<TOutput extends object = Record<string, unkn
575
581
  * This method should be called by the Transaction class when state changes
576
582
  */
577
583
  onTransactionStateChange(): void;
584
+ /**
585
+ * Subscribe to a collection event
586
+ */
587
+ on<T extends keyof AllCollectionEvents>(event: T, callback: CollectionEventHandler<T>): () => void;
588
+ /**
589
+ * Subscribe to a collection event once
590
+ */
591
+ once<T extends keyof AllCollectionEvents>(event: T, callback: CollectionEventHandler<T>): () => void;
592
+ /**
593
+ * Unsubscribe from a collection event
594
+ */
595
+ off<T extends keyof AllCollectionEvents>(event: T, callback: CollectionEventHandler<T>): void;
596
+ /**
597
+ * Wait for a collection event
598
+ */
599
+ waitFor<T extends keyof AllCollectionEvents>(event: T, timeout?: number): Promise<AllCollectionEvents[T]>;
578
600
  }
579
601
  export {};
@@ -8,6 +8,7 @@ import { ensureIndexForExpression } from "./indexes/auto-index.js";
8
8
  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
+ import { CollectionEvents } from "./collection-events.js";
11
12
  function createCollection(options) {
12
13
  const collection = new CollectionImpl(
13
14
  options
@@ -460,6 +461,7 @@ class CollectionImpl {
460
461
  } else {
461
462
  this.syncedData = /* @__PURE__ */ new Map();
462
463
  }
464
+ this.events = new CollectionEvents(this);
463
465
  if (config.startSync === true) {
464
466
  this.startSync();
465
467
  }
@@ -525,6 +527,12 @@ class CollectionImpl {
525
527
  get status() {
526
528
  return this._status;
527
529
  }
530
+ /**
531
+ * Get the number of subscribers to the collection
532
+ */
533
+ get subscriberCount() {
534
+ return this.activeSubscribersCount;
535
+ }
528
536
  /**
529
537
  * Validates that the collection is in a usable state for data operations
530
538
  * @private
@@ -564,12 +572,14 @@ class CollectionImpl {
564
572
  */
565
573
  setStatus(newStatus) {
566
574
  this.validateStatusTransition(this._status, newStatus);
575
+ const previousStatus = this._status;
567
576
  this._status = newStatus;
568
577
  if (newStatus === `ready` && !this.isIndexesResolved) {
569
578
  this.resolveAllIndexes().catch((error) => {
570
579
  console.warn(`Failed to resolve indexes:`, error);
571
580
  });
572
581
  }
582
+ this.events.emitStatusChange(newStatus, previousStatus);
573
583
  }
574
584
  /**
575
585
  * Start sync immediately - internal method for compiled queries
@@ -729,6 +739,7 @@ class CollectionImpl {
729
739
  this.preloadPromise = null;
730
740
  this.batchedEvents = [];
731
741
  this.shouldBatchEvents = false;
742
+ this.events.cleanup();
732
743
  this.setStatus(`cleaned-up`);
733
744
  return Promise.resolve();
734
745
  }
@@ -764,22 +775,32 @@ class CollectionImpl {
764
775
  * Increment the active subscribers count and start sync if needed
765
776
  */
766
777
  addSubscriber() {
778
+ const previousSubscriberCount = this.activeSubscribersCount;
767
779
  this.activeSubscribersCount++;
768
780
  this.cancelGCTimer();
769
781
  if (this._status === `cleaned-up` || this._status === `idle`) {
770
782
  this.startSync();
771
783
  }
784
+ this.events.emitSubscribersChange(
785
+ this.activeSubscribersCount,
786
+ previousSubscriberCount
787
+ );
772
788
  }
773
789
  /**
774
790
  * Decrement the active subscribers count and start GC timer if needed
775
791
  */
776
792
  removeSubscriber() {
793
+ const previousSubscriberCount = this.activeSubscribersCount;
777
794
  this.activeSubscribersCount--;
778
795
  if (this.activeSubscribersCount === 0) {
779
796
  this.startGCTimer();
780
797
  } else if (this.activeSubscribersCount < 0) {
781
798
  throw new NegativeActiveSubscribersError();
782
799
  }
800
+ this.events.emitSubscribersChange(
801
+ this.activeSubscribersCount,
802
+ previousSubscriberCount
803
+ );
783
804
  }
784
805
  /**
785
806
  * Recompute optimistic state from active transactions
@@ -1410,11 +1431,7 @@ class CollectionImpl {
1410
1431
  if (this.size > 0 || this.isReady()) {
1411
1432
  return Promise.resolve(this.state);
1412
1433
  }
1413
- return new Promise((resolve) => {
1414
- this.onFirstReady(() => {
1415
- resolve(this.state);
1416
- });
1417
- });
1434
+ return this.preload().then(() => this.state);
1418
1435
  }
1419
1436
  /**
1420
1437
  * Gets the current state of the collection as an Array
@@ -1434,11 +1451,7 @@ class CollectionImpl {
1434
1451
  if (this.size > 0 || this.isReady()) {
1435
1452
  return Promise.resolve(this.toArray);
1436
1453
  }
1437
- return new Promise((resolve) => {
1438
- this.onFirstReady(() => {
1439
- resolve(this.toArray);
1440
- });
1441
- });
1454
+ return this.preload().then(() => this.toArray);
1442
1455
  }
1443
1456
  /**
1444
1457
  * Returns the current state of the collection as an array of changes
@@ -1580,6 +1593,30 @@ class CollectionImpl {
1580
1593
  this.capturePreSyncVisibleState();
1581
1594
  this.recomputeOptimisticState(false);
1582
1595
  }
1596
+ /**
1597
+ * Subscribe to a collection event
1598
+ */
1599
+ on(event, callback) {
1600
+ return this.events.on(event, callback);
1601
+ }
1602
+ /**
1603
+ * Subscribe to a collection event once
1604
+ */
1605
+ once(event, callback) {
1606
+ return this.events.once(event, callback);
1607
+ }
1608
+ /**
1609
+ * Unsubscribe from a collection event
1610
+ */
1611
+ off(event, callback) {
1612
+ this.events.off(event, callback);
1613
+ }
1614
+ /**
1615
+ * Wait for a collection event
1616
+ */
1617
+ waitFor(event, timeout) {
1618
+ return this.events.waitFor(event, timeout);
1619
+ }
1583
1620
  }
1584
1621
  export {
1585
1622
  CollectionImpl,