@oimdb/core 1.0.6 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -127,18 +127,66 @@ var EOIMIndexEventType = /* @__PURE__ */ ((EOIMIndexEventType2) => {
127
127
  return EOIMIndexEventType2;
128
128
  })(EOIMIndexEventType || {});
129
129
 
130
+ // src/abstract/OIMIndexStore.ts
131
+ var OIMIndexStore = class {
132
+ };
133
+
134
+ // src/core/OIMIndexStoreMapDriven.ts
135
+ var OIMIndexStoreMapDriven = class extends OIMIndexStore {
136
+ constructor() {
137
+ super(...arguments);
138
+ this.pks = /* @__PURE__ */ new Map();
139
+ }
140
+ setOneByKey(key, pks) {
141
+ this.pks.set(key, pks);
142
+ }
143
+ removeOneByKey(key) {
144
+ this.pks.delete(key);
145
+ }
146
+ removeManyByKeys(keys) {
147
+ for (const key of keys) {
148
+ this.pks.delete(key);
149
+ }
150
+ }
151
+ getOneByKey(key) {
152
+ return this.pks.get(key);
153
+ }
154
+ getManyByKeys(keys) {
155
+ const result = /* @__PURE__ */ new Map();
156
+ for (const key of keys) {
157
+ const pks = this.getOneByKey(key);
158
+ if (pks !== void 0) {
159
+ result.set(key, pks);
160
+ }
161
+ }
162
+ return result;
163
+ }
164
+ getAllKeys() {
165
+ return Array.from(this.pks.keys());
166
+ }
167
+ getAll() {
168
+ return new Map(this.pks);
169
+ }
170
+ countAll() {
171
+ return this.pks.size;
172
+ }
173
+ clear() {
174
+ this.pks.clear();
175
+ }
176
+ };
177
+
130
178
  // src/abstract/OIMIndex.ts
131
179
  var OIMIndex = class {
132
180
  constructor(options = {}) {
133
- this.pks = /* @__PURE__ */ new Map();
134
181
  this.emitter = new OIMEventEmitter();
135
182
  this.comparePks = options.comparePks;
183
+ this.store = options.store ?? new OIMIndexStoreMapDriven();
136
184
  }
137
185
  /**
138
186
  * Get primary keys for multiple index keys
139
187
  */
140
188
  getPksByKeys(keys) {
141
- return new Map(keys.map((key) => [key, this.getPks(key)]));
189
+ return this.store.getManyByKeys(keys);
142
190
  }
143
191
  /**
144
192
  * @deprecated Use getPksByKey instead
@@ -151,39 +199,39 @@ var OIMIndex = class {
151
199
  * Get primary keys for a specific index key
152
200
  */
153
201
  getPksByKey(key) {
154
- const pksSet = this.pks.get(key);
202
+ const pksSet = this.store.getOneByKey(key);
155
203
  return pksSet ? pksSet : /* @__PURE__ */ new Set();
156
204
  }
157
205
  /**
158
206
  * Check if an index key exists
159
207
  */
160
208
  hasKey(key) {
161
- return this.pks.has(key);
209
+ return this.store.getOneByKey(key) !== void 0;
162
210
  }
163
211
  /**
164
212
  * Get all index keys
165
213
  */
166
214
  getKeys() {
167
- return Array.from(this.pks.keys());
215
+ return this.store.getAllKeys();
168
216
  }
169
217
  /**
170
218
  * Get the number of primary keys for a specific index key
171
219
  */
172
220
  getKeySize(key) {
173
- const pksSet = this.pks.get(key);
221
+ const pksSet = this.store.getOneByKey(key);
174
222
  return pksSet ? pksSet.size : 0;
175
223
  }
176
224
  /**
177
225
  * Get total number of index keys
178
226
  */
179
227
  get size() {
180
- return this.pks.size;
228
+ return this.store.countAll();
181
229
  }
182
230
  /**
183
231
  * Check if the index is empty
184
232
  */
185
233
  get isEmpty() {
186
- return this.pks.size === 0;
234
+ return this.store.countAll() === 0;
187
235
  }
188
236
  /**
189
237
  * Get performance metrics for monitoring and debugging
@@ -192,15 +240,16 @@ var OIMIndex = class {
192
240
  let totalPks = 0;
193
241
  let maxBucketSize = 0;
194
242
  let minBucketSize = Infinity;
195
- for (const pksSet of this.pks.values()) {
243
+ const allPks = this.store.getAll();
244
+ for (const pksSet of allPks.values()) {
196
245
  totalPks += pksSet.size;
197
246
  maxBucketSize = Math.max(maxBucketSize, pksSet.size);
198
247
  minBucketSize = Math.min(minBucketSize, pksSet.size);
199
248
  }
200
249
  return {
201
- totalKeys: this.pks.size,
250
+ totalKeys: allPks.size,
202
251
  totalPks,
203
- averagePksPerKey: this.pks.size > 0 ? totalPks / this.pks.size : 0,
252
+ averagePksPerKey: allPks.size > 0 ? totalPks / allPks.size : 0,
204
253
  maxBucketSize: maxBucketSize === -Infinity ? 0 : maxBucketSize,
205
254
  minBucketSize: minBucketSize === Infinity ? 0 : minBucketSize
206
255
  };
@@ -210,21 +259,26 @@ var OIMIndex = class {
210
259
  */
211
260
  destroy() {
212
261
  this.emitter.offAll();
213
- this.pks.clear();
262
+ this.store.clear();
214
263
  }
215
264
  /**
216
265
  * Set primary keys for a specific index key with optional comparison.
217
266
  * If comparator is provided and returns true (no changes), skip the update.
218
267
  */
219
268
  setPksWithComparison(key, newPks) {
220
- const existingPks = this.getPks(key).values();
221
- if (this.comparePks && this.comparePks(
222
- Array.from(existingPks),
223
- Array.from(newPks.values())
224
- )) {
225
- return false;
269
+ if (this.comparePks) {
270
+ const existingPksSet = this.store.getOneByKey(key);
271
+ if (existingPksSet && existingPksSet.size === newPks.size) {
272
+ const existingPksArray = existingPksSet.size > 0 ? [...existingPksSet] : [];
273
+ const newPksArray = newPks.size > 0 ? [...newPks] : [];
274
+ if (this.comparePks(existingPksArray, newPksArray)) {
275
+ return false;
276
+ }
277
+ } else if (!existingPksSet && newPks.size === 0) {
278
+ return false;
279
+ }
226
280
  }
227
- this.pks.set(key, newPks);
281
+ this.store.setOneByKey(key, newPks);
228
282
  return true;
229
283
  }
230
284
  /**
@@ -238,6 +292,8 @@ var OIMIndex = class {
238
292
  // src/enum/EOIMUpdateEventCoalescerEventType.ts
239
293
  var EOIMUpdateEventCoalescerEventType = /* @__PURE__ */ ((EOIMUpdateEventCoalescerEventType2) => {
240
294
  EOIMUpdateEventCoalescerEventType2[EOIMUpdateEventCoalescerEventType2["HAS_CHANGES"] = 0] = "HAS_CHANGES";
295
+ EOIMUpdateEventCoalescerEventType2[EOIMUpdateEventCoalescerEventType2["BEFORE_FLUSH"] = 1] = "BEFORE_FLUSH";
296
+ EOIMUpdateEventCoalescerEventType2[EOIMUpdateEventCoalescerEventType2["AFTER_FLUSH"] = 2] = "AFTER_FLUSH";
241
297
  return EOIMUpdateEventCoalescerEventType2;
242
298
  })(EOIMUpdateEventCoalescerEventType || {});
243
299
 
@@ -359,35 +415,141 @@ var OIMUpdateEventEmitter = class {
359
415
  }
360
416
  };
361
417
 
418
+ // src/core/OIMIndexManual.ts
419
+ var OIMIndexManual = class extends OIMIndex {
420
+ constructor(options = {}) {
421
+ super(options);
422
+ }
423
+ /**
424
+ * Set primary keys for a specific index key, replacing any existing values.
425
+ * Uses optional comparator to skip updates if PKs haven't actually changed.
426
+ */
427
+ setPks(key, pks) {
428
+ const hasChanges = this.setPksWithComparison(key, new Set(pks));
429
+ if (hasChanges) {
430
+ this.emitUpdate([key]);
431
+ }
432
+ }
433
+ /**
434
+ * Add primary keys to a specific index key
435
+ */
436
+ addPks(key, pks) {
437
+ if (pks.length === 0) return;
438
+ let pksSet = this.store.getOneByKey(key);
439
+ if (!pksSet) {
440
+ pksSet = /* @__PURE__ */ new Set();
441
+ this.store.setOneByKey(key, pksSet);
442
+ }
443
+ let hasChanges = false;
444
+ for (const pk of pks) {
445
+ if (!pksSet.has(pk)) {
446
+ pksSet.add(pk);
447
+ hasChanges = true;
448
+ }
449
+ }
450
+ if (hasChanges) {
451
+ this.store.setOneByKey(key, pksSet);
452
+ this.emitUpdate([key]);
453
+ }
454
+ }
455
+ /**
456
+ * Remove primary keys from a specific index key
457
+ */
458
+ removePks(key, pks) {
459
+ if (pks.length === 0) return;
460
+ const pksSet = this.store.getOneByKey(key);
461
+ if (!pksSet) return;
462
+ let hasChanges = false;
463
+ for (const pk of pks) {
464
+ if (pksSet.delete(pk)) {
465
+ hasChanges = true;
466
+ }
467
+ }
468
+ if (pksSet.size === 0) {
469
+ this.store.removeOneByKey(key);
470
+ hasChanges = true;
471
+ } else if (hasChanges) {
472
+ this.store.setOneByKey(key, pksSet);
473
+ }
474
+ if (hasChanges) {
475
+ this.emitUpdate([key]);
476
+ }
477
+ }
478
+ /**
479
+ * Clear all primary keys for a specific index key, or all keys if no key specified
480
+ */
481
+ clear(key) {
482
+ if (key === void 0) {
483
+ const allKeys = this.store.getAllKeys();
484
+ if (allKeys.length > 0) {
485
+ this.store.clear();
486
+ this.emitUpdate(allKeys);
487
+ }
488
+ } else {
489
+ if (this.store.getOneByKey(key) !== void 0) {
490
+ this.store.removeOneByKey(key);
491
+ this.emitUpdate([key]);
492
+ }
493
+ }
494
+ }
495
+ };
496
+
497
+ // src/const/OIMDBSettings.ts
498
+ var OIMDBSettings = class {
499
+ };
500
+ /**
501
+ * Fixed key used in the manual index to store updated keys set in coalescers.
502
+ * This constant is exported so users can create their own indexes and pass them to coalescers.
503
+ */
504
+ OIMDBSettings.UPDATED_KEYS_INDEX_KEY = "__updatedKeys__";
505
+
362
506
  // src/core/OIMUpdateEventCoalescer.ts
363
507
  var OIMUpdateEventCoalescer = class {
364
- constructor() {
508
+ constructor(index) {
365
509
  this.emitter = new OIMEventEmitter();
366
- this.updatedKeys = /* @__PURE__ */ new Set();
367
510
  this.hasEmittedChanges = false;
511
+ this.updatedKeysIndex = index ?? new OIMIndexManual({
512
+ store: new OIMIndexStoreMapDriven()
513
+ });
514
+ if (!this.updatedKeysIndex.hasKey(OIMDBSettings.UPDATED_KEYS_INDEX_KEY)) {
515
+ this.updatedKeysIndex.setPks(
516
+ OIMDBSettings.UPDATED_KEYS_INDEX_KEY,
517
+ []
518
+ );
519
+ }
368
520
  }
369
521
  /**
370
522
  * Get the set of keys that have been updated since last clear
371
523
  */
372
524
  getUpdatedKeys() {
373
- return this.updatedKeys;
525
+ return this.updatedKeysIndex.getPksByKey(
526
+ OIMDBSettings.UPDATED_KEYS_INDEX_KEY
527
+ );
374
528
  }
375
529
  /**
376
530
  * Clear all updated keys and reset the changed state
377
531
  */
378
532
  clearUpdatedKeys() {
379
- this.updatedKeys.clear();
533
+ this.emitter.emit(
534
+ 1 /* BEFORE_FLUSH */,
535
+ void 0
536
+ );
537
+ this.updatedKeysIndex.setPks(OIMDBSettings.UPDATED_KEYS_INDEX_KEY, []);
380
538
  this.hasEmittedChanges = false;
539
+ this.emitter.emit(
540
+ 2 /* AFTER_FLUSH */,
541
+ void 0
542
+ );
381
543
  }
382
544
  /**
383
545
  * Add keys to the updated set and emit HAS_CHANGES event if needed
384
546
  */
385
547
  addUpdatedKeys(keys) {
386
- const hadChanges = this.updatedKeys.size > 0;
387
- for (const key of keys) {
388
- this.updatedKeys.add(key);
389
- }
390
- if (!hadChanges && this.updatedKeys.size > 0 && !this.hasEmittedChanges) {
548
+ this.updatedKeysIndex.addPks(
549
+ OIMDBSettings.UPDATED_KEYS_INDEX_KEY,
550
+ keys
551
+ );
552
+ if (!this.hasEmittedChanges) {
391
553
  this.hasEmittedChanges = true;
392
554
  this.emitter.emit(
393
555
  0 /* HAS_CHANGES */,
@@ -406,23 +568,14 @@ var OIMUpdateEventCoalescerIndex = class extends OIMUpdateEventCoalescer {
406
568
  * When the index is updated, we keep track of the updated keys.
407
569
  */
408
570
  this.handleUpdate = (payload) => {
409
- const hadChanges = this.updatedKeys.size > 0;
410
- for (const key of payload.keys) {
411
- this.updatedKeys.add(key);
412
- }
413
- if (!hadChanges && this.updatedKeys.size > 0) {
414
- this.emitter.emit(
415
- 0 /* HAS_CHANGES */,
416
- void 0
417
- );
418
- }
571
+ this.addUpdatedKeys(payload.keys);
419
572
  };
420
573
  this.indexEmitter.on(0 /* UPDATE */, this.handleUpdate);
421
574
  }
422
575
  destroy() {
423
576
  this.indexEmitter.off(0 /* UPDATE */, this.handleUpdate);
424
577
  this.emitter.offAll();
425
- this.updatedKeys.clear();
578
+ this.clearUpdatedKeys();
426
579
  }
427
580
  };
428
581
 
@@ -493,14 +646,24 @@ var OIMCollectionStoreMapDriven = class extends OIMCollectionStore {
493
646
  }
494
647
  removeManyByPks(pks) {
495
648
  for (const pk of pks) {
496
- this.removeOneByPk(pk);
649
+ this.entities.delete(pk);
497
650
  }
498
651
  }
499
652
  getOneByPk(pk) {
500
653
  return this.entities.get(pk);
501
654
  }
502
655
  getManyByPks(pks) {
503
- return pks.map((pk) => this.getOneByPk(pk)).filter(Boolean);
656
+ const result = [];
657
+ result.length = pks.length;
658
+ let writeIndex = 0;
659
+ for (let i = 0; i < pks.length; i++) {
660
+ const entity = this.getOneByPk(pks[i]);
661
+ if (entity !== void 0) {
662
+ result[writeIndex++] = entity;
663
+ }
664
+ }
665
+ result.length = writeIndex;
666
+ return result;
504
667
  }
505
668
  getAll() {
506
669
  return Array.from(this.entities.values());
@@ -565,6 +728,14 @@ var OIMCollection = class {
565
728
  this.store.removeManyByPks(pks);
566
729
  this.emitter.emit(0 /* UPDATE */, { pks });
567
730
  }
731
+ removeOneByPk(pk) {
732
+ this.store.removeOneByPk(pk);
733
+ this.emitter.emit(0 /* UPDATE */, { pks: [pk] });
734
+ }
735
+ removeManyByPks(pks) {
736
+ this.store.removeManyByPks(pks);
737
+ this.emitter.emit(0 /* UPDATE */, { pks });
738
+ }
568
739
  clear() {
569
740
  this.store.clear();
570
741
  this.emitter.emit(0 /* UPDATE */, { pks: [] });
@@ -602,16 +773,7 @@ var OIMUpdateEventCoalescerCollection = class extends OIMUpdateEventCoalescer {
602
773
  * When the collection is updated, we keep track of the updated pks.
603
774
  */
604
775
  this.handleUpdate = (payload) => {
605
- const hadChanges = this.updatedKeys.size > 0;
606
- for (const pk of payload.pks) {
607
- this.updatedKeys.add(pk);
608
- }
609
- if (!hadChanges && this.updatedKeys.size > 0) {
610
- this.emitter.emit(
611
- 0 /* HAS_CHANGES */,
612
- void 0
613
- );
614
- }
776
+ this.addUpdatedKeys(payload.pks);
615
777
  };
616
778
  this.collectionEmitter.on(
617
779
  0 /* UPDATE */,
@@ -624,129 +786,22 @@ var OIMUpdateEventCoalescerCollection = class extends OIMUpdateEventCoalescer {
624
786
  this.handleUpdate
625
787
  );
626
788
  this.emitter.offAll();
627
- this.updatedKeys.clear();
789
+ this.clearUpdatedKeys();
628
790
  }
629
791
  };
630
792
 
631
793
  // src/core/OIMReactiveCollection.ts
632
- var OIMReactiveCollection = class {
794
+ var OIMReactiveCollection = class extends OIMCollection {
633
795
  constructor(queue, opts) {
634
- this.collection = new OIMCollection(opts?.collectionOpts);
796
+ super(opts);
635
797
  this.coalescer = new OIMUpdateEventCoalescerCollection(
636
- this.collection.emitter
798
+ this.emitter
637
799
  );
638
800
  this.updateEventEmitter = new OIMUpdateEventEmitter({
639
801
  coalescer: this.coalescer,
640
802
  queue
641
803
  });
642
804
  }
643
- upsertMany(entities) {
644
- this.collection.upsertMany(entities);
645
- }
646
- upsertOne(entity) {
647
- this.collection.upsertOne(entity);
648
- }
649
- removeMany(entities) {
650
- this.collection.removeMany(entities);
651
- }
652
- removeOne(entity) {
653
- this.collection.removeOne(entity);
654
- }
655
- getOneByPk(pk) {
656
- return this.collection.getOneByPk(pk);
657
- }
658
- getManyByPks(pks) {
659
- return this.collection.getManyByPks(pks);
660
- }
661
- clear() {
662
- this.collection.clear();
663
- }
664
- countAll() {
665
- return this.collection.countAll();
666
- }
667
- getAll() {
668
- return this.collection.getAll();
669
- }
670
- getAllPks() {
671
- return this.collection.getAllPks();
672
- }
673
- };
674
-
675
- // src/core/OIMIndexManual.ts
676
- var OIMIndexManual = class extends OIMIndex {
677
- constructor(options = {}) {
678
- super(options);
679
- }
680
- /**
681
- * Set primary keys for a specific index key, replacing any existing values.
682
- * Uses optional comparator to skip updates if PKs haven't actually changed.
683
- */
684
- setPks(key, pks) {
685
- const hasChanges = this.setPksWithComparison(key, new Set(pks));
686
- if (hasChanges) {
687
- this.emitUpdate([key]);
688
- }
689
- }
690
- /**
691
- * Add primary keys to a specific index key
692
- */
693
- addPks(key, pks) {
694
- if (pks.length === 0) return;
695
- let pksSet = this.pks.get(key);
696
- if (!pksSet) {
697
- pksSet = /* @__PURE__ */ new Set();
698
- this.pks.set(key, pksSet);
699
- }
700
- let hasChanges = false;
701
- for (const pk of pks) {
702
- const sizeBefore = pksSet.size;
703
- pksSet.add(pk);
704
- if (pksSet.size > sizeBefore) {
705
- hasChanges = true;
706
- }
707
- }
708
- if (hasChanges) {
709
- this.emitUpdate([key]);
710
- }
711
- }
712
- /**
713
- * Remove primary keys from a specific index key
714
- */
715
- removePks(key, pks) {
716
- if (pks.length === 0) return;
717
- const pksSet = this.pks.get(key);
718
- if (!pksSet) return;
719
- let hasChanges = false;
720
- for (const pk of pks) {
721
- if (pksSet.delete(pk)) {
722
- hasChanges = true;
723
- }
724
- }
725
- if (pksSet.size === 0) {
726
- this.pks.delete(key);
727
- hasChanges = true;
728
- }
729
- if (hasChanges) {
730
- this.emitUpdate([key]);
731
- }
732
- }
733
- /**
734
- * Clear all primary keys for a specific index key, or all keys if no key specified
735
- */
736
- clear(key) {
737
- if (key === void 0) {
738
- if (this.pks.size > 0) {
739
- const allKeys = Array.from(this.pks.keys());
740
- this.pks.clear();
741
- this.emitUpdate(allKeys);
742
- }
743
- } else {
744
- if (this.pks.has(key)) {
745
- this.pks.delete(key);
746
- this.emitUpdate([key]);
747
- }
748
- }
749
- }
750
805
  };
751
806
 
752
807
  // src/core/OIMReactiveIndexManual.ts
@@ -774,10 +829,8 @@ var OIMReactiveIndexManual = class extends OIMReactiveIndex {
774
829
  // src/core/OIMRICollection.ts
775
830
  var OIMRICollection = class extends OIMReactiveCollection {
776
831
  constructor(queue, opts) {
777
- super(queue, {
778
- collectionOpts: opts.collectionOpts
779
- });
780
- this.indexes = opts.indexes || {};
832
+ super(queue, opts.collectionOpts);
833
+ this.indexes = opts.indexes;
781
834
  }
782
835
  };
783
836
 
@@ -799,9 +852,17 @@ var OIMComparatorFactory = class {
799
852
  }
800
853
  };
801
854
 
855
+ // src/enum/EOIMEventQueueEventType.ts
856
+ var EOIMEventQueueEventType = /* @__PURE__ */ ((EOIMEventQueueEventType2) => {
857
+ EOIMEventQueueEventType2[EOIMEventQueueEventType2["AFTER_FLUSH"] = 0] = "AFTER_FLUSH";
858
+ EOIMEventQueueEventType2[EOIMEventQueueEventType2["BEFORE_FLUSH"] = 1] = "BEFORE_FLUSH";
859
+ return EOIMEventQueueEventType2;
860
+ })(EOIMEventQueueEventType || {});
861
+
802
862
  // src/core/OIMEventQueue.ts
803
863
  var OIMEventQueue = class {
804
864
  constructor(options = {}) {
865
+ this.emitter = new OIMEventEmitter();
805
866
  this.queue = [];
806
867
  this.scheduler = options.scheduler;
807
868
  if (this.scheduler) {
@@ -828,11 +889,13 @@ var OIMEventQueue = class {
828
889
  */
829
890
  flush() {
830
891
  if (this.queue.length === 0) return;
892
+ this.emitter.emit(1 /* BEFORE_FLUSH */, void 0);
831
893
  const currentQueue = this.queue.slice();
832
894
  this.queue.length = 0;
833
895
  for (let i = 0; i < currentQueue.length; i++) {
834
896
  currentQueue[i]();
835
897
  }
898
+ this.emitter.emit(0 /* AFTER_FLUSH */, void 0);
836
899
  }
837
900
  /**
838
901
  * Get the current number of queued functions.
@@ -900,9 +963,7 @@ var OIMIndexComparatorFactory = class {
900
963
  if (existingSet.size !== newSet.size || existingSet.size !== existingPks.length) {
901
964
  return false;
902
965
  }
903
- const setValues = Array.from(existingSet);
904
- for (let i = 0; i < setValues.length; i++) {
905
- const pk = setValues[i];
966
+ for (const pk of existingSet) {
906
967
  if (!newSet.has(pk)) {
907
968
  return false;
908
969
  }
@@ -1138,6 +1199,7 @@ var OIMEventQueueSchedulerFactory = class {
1138
1199
  };
1139
1200
  export {
1140
1201
  EOIMCollectionEventType,
1202
+ EOIMEventQueueEventType,
1141
1203
  EOIMEventQueueSchedulerEventType,
1142
1204
  EOIMIndexEventType,
1143
1205
  EOIMUpdateEventCoalescerEventType,
@@ -1145,6 +1207,7 @@ export {
1145
1207
  OIMCollectionStore,
1146
1208
  OIMCollectionStoreMapDriven,
1147
1209
  OIMComparatorFactory,
1210
+ OIMDBSettings,
1148
1211
  OIMEntityUpdaterFactory,
1149
1212
  OIMEventEmitter,
1150
1213
  OIMEventQueue,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oimdb/core",
3
- "version": "1.0.6",
3
+ "version": "1.2.0",
4
4
  "description": "Core in-memory data library with type-safe indices, reactive subscriptions, and event processing",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -24,8 +24,10 @@
24
24
  },
25
25
  "scripts": {
26
26
  "build": "tsup src/index.ts --dts --format esm,cjs",
27
+ "test": "jest",
28
+ "type-check": "tsc --noEmit",
27
29
  "clean": "rimraf dist",
28
- "prepublishOnly": "npm run build"
30
+ "prepublishOnly": "npm run type-check && npm test && npm run build"
29
31
  },
30
32
  "files": [
31
33
  "dist"
@@ -33,6 +35,9 @@
33
35
  "author": "Andrei Baikov",
34
36
  "license": "MIT",
35
37
  "devDependencies": {
38
+ "@types/jest": "^29.5.8",
39
+ "jest": "^29.7.0",
40
+ "ts-jest": "^29.1.1",
36
41
  "tsup": "^8.5.0",
37
42
  "typescript": "^5.2.2",
38
43
  "rimraf": "^5.0.5"