@oimdb/core 3.2.0 → 3.4.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.d.cts CHANGED
@@ -254,25 +254,15 @@ declare class OIMEventQueue {
254
254
  protected isFlushing: boolean;
255
255
  constructor(options?: TOIMEventQueueOptions);
256
256
  /**
257
- * Enqueue a one-shot task to be executed on the next flush.
258
- * Returns a dequeue function that can be called to cancel the task before it runs.
257
+ * Enqueue a one-shot task to run on the next flush. The function is stored
258
+ * directly (no wrapper, no returned closure) and cancelled via {@link cancel}
259
+ * by passing the same reference. Enqueuing the same reference twice is
260
+ * idempotent — it is Set-deduped and runs once per flush.
259
261
  */
260
- enqueue(fn: () => void): () => void;
261
- /**
262
- * Allocation-free enqueue for a **stable** function reference (e.g. a bound
263
- * `onFlush` method). The function is stored directly — no wrapper, no
264
- * returned closure — and cancelled via {@link cancelTask}. Enqueuing the
265
- * same reference twice is idempotent (Set-deduped); callers that may run a
266
- * task more than once per flush should use {@link enqueue} instead.
267
- */
268
- enqueueTask(fn: () => void): void;
269
- /** Cancel a task scheduled via {@link enqueueTask}; safe to call mid-flush. */
270
- cancelTask(fn: () => void): void;
262
+ enqueue(fn: () => void): void;
263
+ /** Cancel a previously enqueued task by its reference; safe to call mid-flush. */
264
+ cancel(fn: () => void): void;
271
265
  get isInFlush(): boolean;
272
- /**
273
- * Dequeue (cancel) a previously enqueued task by its dequeue function.
274
- */
275
- dequeue(dequeueFn: () => void): void;
276
266
  /**
277
267
  * Execute all pending tasks.
278
268
  *
@@ -637,7 +627,20 @@ declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TItemKey exte
637
627
  pushSlot(key: TKey, slot: TOIMAnyEntitySlot<TItemKey>): number;
638
628
  insertSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TItemKey>): number;
639
629
  removeAt(key: TKey, index: number): TOIMAnyEntitySlot<TItemKey> | undefined;
630
+ /**
631
+ * Remove up to `count` consecutive slots starting at `index`.
632
+ * Returns the number actually removed (clamped to bounds; 0 if nothing).
633
+ */
634
+ removeRange(key: TKey, index: number, count: number): number;
640
635
  move(key: TKey, fromIndex: number, toIndex: number): TOIMAnyEntitySlot<TItemKey> | undefined;
636
+ /** Replace the slot at `index` in place. Returns the safe index, or -1. */
637
+ setSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TItemKey>): number;
638
+ /**
639
+ * Move up to `count` consecutive slots from `from` to `to`. `to` is in the
640
+ * coordinate space *after* the block is extracted (same as single `move`).
641
+ * Returns the number actually moved (0 if a no-op / out of bounds).
642
+ */
643
+ moveRange(key: TKey, from: number, to: number, count: number): number;
641
644
  resetSlots(key: TKey, slots: readonly TOIMAnyEntitySlot<TItemKey>[]): void;
642
645
  private getOrCreateList;
643
646
  }
@@ -722,36 +725,46 @@ declare class OIMUpdateEventEmitter<TKey extends TOIMPk> {
722
725
  unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
723
726
  }
724
727
 
725
- type TOIMOrderedListCommand<TPk extends TOIMPk, TEntity extends object = object> = {
728
+ /**
729
+ * Incremental command for an ordered per-key list, addressed by position.
730
+ *
731
+ * `item` is whatever the stream stores per element — the command stream uses the
732
+ * entity slot (`TOIMEntitySlot`), so a consumer reads `item.item` for the entity.
733
+ *
734
+ * - `insert` — a single element appears at `index`.
735
+ * - `remove` — `count` elements (default 1, may be > 1) disappear from `index`.
736
+ * - `move` — `count` elements (default 1) move from `from` to `to`.
737
+ * - `set` — the element at `index` is replaced in place.
738
+ * - `reset` — the whole list for the key is replaced by `items`.
739
+ */
740
+ type TOIMOrderedListCommand<TItem> = {
726
741
  type: 'insert';
727
- pk: TPk;
728
- slot: TOIMEntitySlot<TEntity, TPk>;
729
742
  index: number;
743
+ item: TItem;
730
744
  } | {
731
745
  type: 'remove';
732
- pk: TPk;
733
- slot: TOIMEntitySlot<TEntity, TPk>;
734
746
  index: number;
747
+ count?: number;
735
748
  } | {
736
749
  type: 'move';
737
- pk: TPk;
738
- slot: TOIMEntitySlot<TEntity, TPk>;
739
- fromIndex: number;
740
- toIndex: number;
750
+ from: number;
751
+ to: number;
752
+ count?: number;
741
753
  } | {
742
- /**
743
- * Replace the whole list for this key (preferred name).
744
- */
745
754
  type: 'set';
746
- pks: readonly TPk[];
747
- slots: readonly TOIMEntitySlot<TEntity, TPk>[];
755
+ index: number;
756
+ item: TItem;
757
+ } | {
758
+ type: 'reset';
759
+ items: readonly TItem[];
748
760
  };
749
761
 
750
762
  /**
751
763
  * Slot-first ordered-list command stream.
752
764
  *
753
- * Use this when you already have slots and want incremental commands for an
754
- * imperative renderer. For PK writes bound to a collection, use
765
+ * Emits position-addressed {@link TOIMOrderedListCommand}s whose `item` is the
766
+ * entity slot. Use this when you already have slots and want incremental
767
+ * commands for an imperative renderer. For PK writes bound to a collection, use
755
768
  * `OIMCollectionOrderedListCommandStream`.
756
769
  */
757
770
  declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> {
@@ -770,19 +783,28 @@ declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMP
770
783
  getKeys(): readonly TKey[];
771
784
  pushSlot(key: TKey, slot: TOIMEntitySlot<TEntity, TPk>): void;
772
785
  insertSlotAt(key: TKey, index: number, slot: TOIMEntitySlot<TEntity, TPk>): void;
786
+ /** Replace the slot at `index` in place. */
787
+ setSlotAt(key: TKey, index: number, slot: TOIMEntitySlot<TEntity, TPk>): void;
773
788
  removeAt(key: TKey, index: number): void;
789
+ /** Remove `count` consecutive elements from `index`; emits `remove` with `count`. */
790
+ removeRange(key: TKey, index: number, count: number): void;
774
791
  move(key: TKey, fromIndex: number, toIndex: number): void;
792
+ /**
793
+ * Move `count` consecutive elements from `from` to `to`; emits `move` with
794
+ * `count`. `to` is in the post-extraction coordinate space (as single `move`).
795
+ */
796
+ moveRange(key: TKey, from: number, to: number, count: number): void;
775
797
  setSlots(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
776
- getBufferedCommands(key: TKey): readonly TOIMOrderedListCommand<TPk, TEntity>[];
777
- consumeCommands(key: TKey): TOIMOrderedListCommand<TPk, TEntity>[];
798
+ getBufferedCommands(key: TKey): readonly TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>[];
799
+ consumeCommands(key: TKey): TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>[];
778
800
  clear(key?: TKey): void;
779
801
  destroy(): void;
780
802
  private readonly onAfterFlush;
781
803
  private readonly onIndexUpdate;
782
804
  protected withWrite(fn: () => void): void;
783
- protected appendCommand(key: TKey, cmd: TOIMOrderedListCommand<TPk, TEntity>): void;
784
- protected appendSetCommand(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
785
- protected createSetCommand(slots: readonly TOIMEntitySlot<TEntity, TPk>[]): TOIMOrderedListCommand<TPk, TEntity>;
805
+ protected appendCommand(key: TKey, cmd: TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>): void;
806
+ protected appendResetCommand(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
807
+ protected createResetCommand(slots: readonly TOIMEntitySlot<TEntity, TPk>[]): TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>;
786
808
  }
787
809
 
788
810
  /**
@@ -795,6 +817,8 @@ declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMPk, TPk ext
795
817
  constructor(queue: OIMEventQueue, opts: TOIMCollectionOrderedListCommandStreamOptions<TKey, TPk, TEntity>);
796
818
  push(key: TKey, pk: TPk): void;
797
819
  insertAt(key: TKey, index: number, pk: TPk): void;
820
+ /** Replace the element at `index` with the slot for `pk`, in place. */
821
+ setAt(key: TKey, index: number, pk: TPk): void;
798
822
  set(key: TKey, pks: readonly TPk[]): void;
799
823
  getSlotsByKey(key: TKey): readonly TOIMEntitySlot<TEntity, TPk>[];
800
824
  getEntitiesByKey(key: TKey): (TEntity | undefined)[];
@@ -1159,6 +1183,18 @@ declare class OIMEntityUpdaterFactory<TEntity extends object> {
1159
1183
  */
1160
1184
  declare function createInPlaceEntityUpdater<TEntity extends object>(): TOIMEntityUpdater<TEntity>;
1161
1185
 
1186
+ /**
1187
+ * Default entity updater: shallow-merges the patch into a NEW object
1188
+ * (`{ ...prev, ...draft }`). Each update produces a fresh entity reference, which
1189
+ * reference-comparison bindings (React's `Object.is` / `useSyncExternalStore`,
1190
+ * `React.memo`, prev/next diffing, time-travel) need to detect a change.
1191
+ *
1192
+ * The new-object allocation is the biggest per-update data-layer cost; for
1193
+ * update-heavy, subscription-driven readers use {@link createInPlaceEntityUpdater}
1194
+ * instead.
1195
+ */
1196
+ declare function createMergeEntityUpdater<TEntity extends object>(): TOIMEntityUpdater<TEntity>;
1197
+
1162
1198
  /**
1163
1199
  * Factory for creating index comparators.
1164
1200
  * Provides common comparison strategies for primary key arrays.
@@ -1307,9 +1343,11 @@ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOI
1307
1343
  readonly collection: OIMCollection<TEntity, TPk>;
1308
1344
  private readonly selectPk;
1309
1345
  private readonly unsubscribeAfterFlush;
1310
- private readonly unsubscribeFromCollectionEmitter;
1346
+ private readonly unsubscribeFromCollectionEmitter?;
1347
+ private readonly detectExternalMutations;
1311
1348
  private isInWrite;
1312
1349
  private readonly lastEntitySnapshotByPk;
1350
+ private readonly writtenThroughThisFlush;
1313
1351
  /**
1314
1352
  * Emits updates scoped by PK. Subscribe, then read state via `getChangedFieldsByPk(...)`
1315
1353
  * or drain via `consumeChangedFieldsByPk(...)`.
@@ -1328,6 +1366,18 @@ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOI
1328
1366
  * If not provided, only `upsertOneByPk(...)` should be used.
1329
1367
  */
1330
1368
  selectPk?: (entity: TEntity | Partial<TEntity>) => TPk;
1369
+ /**
1370
+ * Detect writes that bypass this wrapper (direct collection
1371
+ * mutations) by diffing entity snapshots. Default `true`.
1372
+ *
1373
+ * Set to `false` when you always write through this wrapper: it
1374
+ * drops the per-write snapshot clone and the per-PK snapshot map
1375
+ * (~2x entity memory), since those exist only to power external
1376
+ * detection. The shallow diff also can't see deep in-place
1377
+ * mutations anyway — so if that's your model, opting out costs you
1378
+ * nothing it could have caught.
1379
+ */
1380
+ detectExternalMutations?: boolean;
1331
1381
  });
1332
1382
  upsertOneByPk(pk: TPk, patch: Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
1333
1383
  upsertOne(entity: TEntity | Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
@@ -1700,4 +1750,4 @@ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TP
1700
1750
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1701
1751
  }
1702
1752
 
1703
- export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexStore, type IOIMKeyedUpdateEmitter, type IOIMSubscribable, OIMCarrierKeyedEmitter, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerTimeout, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandStream, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexSetBasedOptions, type TOIMCollectionKit, type TOIMCollectionOptions, type TOIMCollectionOrderedIndexOptions, type TOIMCollectionOrderedListCommandStreamOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMDerivedCollectionIndexArrayBasedOptions, type TOIMDerivedCollectionIndexSetBasedOptions, type TOIMDerivedEntityComparator, type TOIMDerivedEntityOrderSelector, type TOIMDerivedEntityOrderValue, type TOIMDerivedIndexKeySelector, type TOIMEffectOptions, type TOIMEntitySlot, type TOIMEntitySlotResolver, type TOIMEntityUpdater, type TOIMEventHandler, type TOIMEventQueueOptions, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsDerivedArrayIndexOptions, type TOIMRelationsDerivedSetIndexOptions, type TOIMRelationsOrderedListOptions, type TOIMRelationsSetIndexOptions, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload, createInPlaceEntityUpdater, createOIMCollectionIndexFactory, createOIMCollectionKit };
1753
+ export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexStore, type IOIMKeyedUpdateEmitter, type IOIMSubscribable, OIMCarrierKeyedEmitter, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerTimeout, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandStream, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexSetBasedOptions, type TOIMCollectionKit, type TOIMCollectionOptions, type TOIMCollectionOrderedIndexOptions, type TOIMCollectionOrderedListCommandStreamOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMDerivedCollectionIndexArrayBasedOptions, type TOIMDerivedCollectionIndexSetBasedOptions, type TOIMDerivedEntityComparator, type TOIMDerivedEntityOrderSelector, type TOIMDerivedEntityOrderValue, type TOIMDerivedIndexKeySelector, type TOIMEffectOptions, type TOIMEntitySlot, type TOIMEntitySlotResolver, type TOIMEntityUpdater, type TOIMEventHandler, type TOIMEventQueueOptions, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsDerivedArrayIndexOptions, type TOIMRelationsDerivedSetIndexOptions, type TOIMRelationsOrderedListOptions, type TOIMRelationsSetIndexOptions, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload, createInPlaceEntityUpdater, createMergeEntityUpdater, createOIMCollectionIndexFactory, createOIMCollectionKit };
package/dist/index.d.ts CHANGED
@@ -254,25 +254,15 @@ declare class OIMEventQueue {
254
254
  protected isFlushing: boolean;
255
255
  constructor(options?: TOIMEventQueueOptions);
256
256
  /**
257
- * Enqueue a one-shot task to be executed on the next flush.
258
- * Returns a dequeue function that can be called to cancel the task before it runs.
257
+ * Enqueue a one-shot task to run on the next flush. The function is stored
258
+ * directly (no wrapper, no returned closure) and cancelled via {@link cancel}
259
+ * by passing the same reference. Enqueuing the same reference twice is
260
+ * idempotent — it is Set-deduped and runs once per flush.
259
261
  */
260
- enqueue(fn: () => void): () => void;
261
- /**
262
- * Allocation-free enqueue for a **stable** function reference (e.g. a bound
263
- * `onFlush` method). The function is stored directly — no wrapper, no
264
- * returned closure — and cancelled via {@link cancelTask}. Enqueuing the
265
- * same reference twice is idempotent (Set-deduped); callers that may run a
266
- * task more than once per flush should use {@link enqueue} instead.
267
- */
268
- enqueueTask(fn: () => void): void;
269
- /** Cancel a task scheduled via {@link enqueueTask}; safe to call mid-flush. */
270
- cancelTask(fn: () => void): void;
262
+ enqueue(fn: () => void): void;
263
+ /** Cancel a previously enqueued task by its reference; safe to call mid-flush. */
264
+ cancel(fn: () => void): void;
271
265
  get isInFlush(): boolean;
272
- /**
273
- * Dequeue (cancel) a previously enqueued task by its dequeue function.
274
- */
275
- dequeue(dequeueFn: () => void): void;
276
266
  /**
277
267
  * Execute all pending tasks.
278
268
  *
@@ -637,7 +627,20 @@ declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TItemKey exte
637
627
  pushSlot(key: TKey, slot: TOIMAnyEntitySlot<TItemKey>): number;
638
628
  insertSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TItemKey>): number;
639
629
  removeAt(key: TKey, index: number): TOIMAnyEntitySlot<TItemKey> | undefined;
630
+ /**
631
+ * Remove up to `count` consecutive slots starting at `index`.
632
+ * Returns the number actually removed (clamped to bounds; 0 if nothing).
633
+ */
634
+ removeRange(key: TKey, index: number, count: number): number;
640
635
  move(key: TKey, fromIndex: number, toIndex: number): TOIMAnyEntitySlot<TItemKey> | undefined;
636
+ /** Replace the slot at `index` in place. Returns the safe index, or -1. */
637
+ setSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TItemKey>): number;
638
+ /**
639
+ * Move up to `count` consecutive slots from `from` to `to`. `to` is in the
640
+ * coordinate space *after* the block is extracted (same as single `move`).
641
+ * Returns the number actually moved (0 if a no-op / out of bounds).
642
+ */
643
+ moveRange(key: TKey, from: number, to: number, count: number): number;
641
644
  resetSlots(key: TKey, slots: readonly TOIMAnyEntitySlot<TItemKey>[]): void;
642
645
  private getOrCreateList;
643
646
  }
@@ -722,36 +725,46 @@ declare class OIMUpdateEventEmitter<TKey extends TOIMPk> {
722
725
  unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
723
726
  }
724
727
 
725
- type TOIMOrderedListCommand<TPk extends TOIMPk, TEntity extends object = object> = {
728
+ /**
729
+ * Incremental command for an ordered per-key list, addressed by position.
730
+ *
731
+ * `item` is whatever the stream stores per element — the command stream uses the
732
+ * entity slot (`TOIMEntitySlot`), so a consumer reads `item.item` for the entity.
733
+ *
734
+ * - `insert` — a single element appears at `index`.
735
+ * - `remove` — `count` elements (default 1, may be > 1) disappear from `index`.
736
+ * - `move` — `count` elements (default 1) move from `from` to `to`.
737
+ * - `set` — the element at `index` is replaced in place.
738
+ * - `reset` — the whole list for the key is replaced by `items`.
739
+ */
740
+ type TOIMOrderedListCommand<TItem> = {
726
741
  type: 'insert';
727
- pk: TPk;
728
- slot: TOIMEntitySlot<TEntity, TPk>;
729
742
  index: number;
743
+ item: TItem;
730
744
  } | {
731
745
  type: 'remove';
732
- pk: TPk;
733
- slot: TOIMEntitySlot<TEntity, TPk>;
734
746
  index: number;
747
+ count?: number;
735
748
  } | {
736
749
  type: 'move';
737
- pk: TPk;
738
- slot: TOIMEntitySlot<TEntity, TPk>;
739
- fromIndex: number;
740
- toIndex: number;
750
+ from: number;
751
+ to: number;
752
+ count?: number;
741
753
  } | {
742
- /**
743
- * Replace the whole list for this key (preferred name).
744
- */
745
754
  type: 'set';
746
- pks: readonly TPk[];
747
- slots: readonly TOIMEntitySlot<TEntity, TPk>[];
755
+ index: number;
756
+ item: TItem;
757
+ } | {
758
+ type: 'reset';
759
+ items: readonly TItem[];
748
760
  };
749
761
 
750
762
  /**
751
763
  * Slot-first ordered-list command stream.
752
764
  *
753
- * Use this when you already have slots and want incremental commands for an
754
- * imperative renderer. For PK writes bound to a collection, use
765
+ * Emits position-addressed {@link TOIMOrderedListCommand}s whose `item` is the
766
+ * entity slot. Use this when you already have slots and want incremental
767
+ * commands for an imperative renderer. For PK writes bound to a collection, use
755
768
  * `OIMCollectionOrderedListCommandStream`.
756
769
  */
757
770
  declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> {
@@ -770,19 +783,28 @@ declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMP
770
783
  getKeys(): readonly TKey[];
771
784
  pushSlot(key: TKey, slot: TOIMEntitySlot<TEntity, TPk>): void;
772
785
  insertSlotAt(key: TKey, index: number, slot: TOIMEntitySlot<TEntity, TPk>): void;
786
+ /** Replace the slot at `index` in place. */
787
+ setSlotAt(key: TKey, index: number, slot: TOIMEntitySlot<TEntity, TPk>): void;
773
788
  removeAt(key: TKey, index: number): void;
789
+ /** Remove `count` consecutive elements from `index`; emits `remove` with `count`. */
790
+ removeRange(key: TKey, index: number, count: number): void;
774
791
  move(key: TKey, fromIndex: number, toIndex: number): void;
792
+ /**
793
+ * Move `count` consecutive elements from `from` to `to`; emits `move` with
794
+ * `count`. `to` is in the post-extraction coordinate space (as single `move`).
795
+ */
796
+ moveRange(key: TKey, from: number, to: number, count: number): void;
775
797
  setSlots(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
776
- getBufferedCommands(key: TKey): readonly TOIMOrderedListCommand<TPk, TEntity>[];
777
- consumeCommands(key: TKey): TOIMOrderedListCommand<TPk, TEntity>[];
798
+ getBufferedCommands(key: TKey): readonly TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>[];
799
+ consumeCommands(key: TKey): TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>[];
778
800
  clear(key?: TKey): void;
779
801
  destroy(): void;
780
802
  private readonly onAfterFlush;
781
803
  private readonly onIndexUpdate;
782
804
  protected withWrite(fn: () => void): void;
783
- protected appendCommand(key: TKey, cmd: TOIMOrderedListCommand<TPk, TEntity>): void;
784
- protected appendSetCommand(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
785
- protected createSetCommand(slots: readonly TOIMEntitySlot<TEntity, TPk>[]): TOIMOrderedListCommand<TPk, TEntity>;
805
+ protected appendCommand(key: TKey, cmd: TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>): void;
806
+ protected appendResetCommand(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
807
+ protected createResetCommand(slots: readonly TOIMEntitySlot<TEntity, TPk>[]): TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>;
786
808
  }
787
809
 
788
810
  /**
@@ -795,6 +817,8 @@ declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMPk, TPk ext
795
817
  constructor(queue: OIMEventQueue, opts: TOIMCollectionOrderedListCommandStreamOptions<TKey, TPk, TEntity>);
796
818
  push(key: TKey, pk: TPk): void;
797
819
  insertAt(key: TKey, index: number, pk: TPk): void;
820
+ /** Replace the element at `index` with the slot for `pk`, in place. */
821
+ setAt(key: TKey, index: number, pk: TPk): void;
798
822
  set(key: TKey, pks: readonly TPk[]): void;
799
823
  getSlotsByKey(key: TKey): readonly TOIMEntitySlot<TEntity, TPk>[];
800
824
  getEntitiesByKey(key: TKey): (TEntity | undefined)[];
@@ -1159,6 +1183,18 @@ declare class OIMEntityUpdaterFactory<TEntity extends object> {
1159
1183
  */
1160
1184
  declare function createInPlaceEntityUpdater<TEntity extends object>(): TOIMEntityUpdater<TEntity>;
1161
1185
 
1186
+ /**
1187
+ * Default entity updater: shallow-merges the patch into a NEW object
1188
+ * (`{ ...prev, ...draft }`). Each update produces a fresh entity reference, which
1189
+ * reference-comparison bindings (React's `Object.is` / `useSyncExternalStore`,
1190
+ * `React.memo`, prev/next diffing, time-travel) need to detect a change.
1191
+ *
1192
+ * The new-object allocation is the biggest per-update data-layer cost; for
1193
+ * update-heavy, subscription-driven readers use {@link createInPlaceEntityUpdater}
1194
+ * instead.
1195
+ */
1196
+ declare function createMergeEntityUpdater<TEntity extends object>(): TOIMEntityUpdater<TEntity>;
1197
+
1162
1198
  /**
1163
1199
  * Factory for creating index comparators.
1164
1200
  * Provides common comparison strategies for primary key arrays.
@@ -1307,9 +1343,11 @@ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOI
1307
1343
  readonly collection: OIMCollection<TEntity, TPk>;
1308
1344
  private readonly selectPk;
1309
1345
  private readonly unsubscribeAfterFlush;
1310
- private readonly unsubscribeFromCollectionEmitter;
1346
+ private readonly unsubscribeFromCollectionEmitter?;
1347
+ private readonly detectExternalMutations;
1311
1348
  private isInWrite;
1312
1349
  private readonly lastEntitySnapshotByPk;
1350
+ private readonly writtenThroughThisFlush;
1313
1351
  /**
1314
1352
  * Emits updates scoped by PK. Subscribe, then read state via `getChangedFieldsByPk(...)`
1315
1353
  * or drain via `consumeChangedFieldsByPk(...)`.
@@ -1328,6 +1366,18 @@ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOI
1328
1366
  * If not provided, only `upsertOneByPk(...)` should be used.
1329
1367
  */
1330
1368
  selectPk?: (entity: TEntity | Partial<TEntity>) => TPk;
1369
+ /**
1370
+ * Detect writes that bypass this wrapper (direct collection
1371
+ * mutations) by diffing entity snapshots. Default `true`.
1372
+ *
1373
+ * Set to `false` when you always write through this wrapper: it
1374
+ * drops the per-write snapshot clone and the per-PK snapshot map
1375
+ * (~2x entity memory), since those exist only to power external
1376
+ * detection. The shallow diff also can't see deep in-place
1377
+ * mutations anyway — so if that's your model, opting out costs you
1378
+ * nothing it could have caught.
1379
+ */
1380
+ detectExternalMutations?: boolean;
1331
1381
  });
1332
1382
  upsertOneByPk(pk: TPk, patch: Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
1333
1383
  upsertOne(entity: TEntity | Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
@@ -1700,4 +1750,4 @@ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TP
1700
1750
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1701
1751
  }
1702
1752
 
1703
- export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexStore, type IOIMKeyedUpdateEmitter, type IOIMSubscribable, OIMCarrierKeyedEmitter, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerTimeout, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandStream, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexSetBasedOptions, type TOIMCollectionKit, type TOIMCollectionOptions, type TOIMCollectionOrderedIndexOptions, type TOIMCollectionOrderedListCommandStreamOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMDerivedCollectionIndexArrayBasedOptions, type TOIMDerivedCollectionIndexSetBasedOptions, type TOIMDerivedEntityComparator, type TOIMDerivedEntityOrderSelector, type TOIMDerivedEntityOrderValue, type TOIMDerivedIndexKeySelector, type TOIMEffectOptions, type TOIMEntitySlot, type TOIMEntitySlotResolver, type TOIMEntityUpdater, type TOIMEventHandler, type TOIMEventQueueOptions, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsDerivedArrayIndexOptions, type TOIMRelationsDerivedSetIndexOptions, type TOIMRelationsOrderedListOptions, type TOIMRelationsSetIndexOptions, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload, createInPlaceEntityUpdater, createOIMCollectionIndexFactory, createOIMCollectionKit };
1753
+ export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexStore, type IOIMKeyedUpdateEmitter, type IOIMSubscribable, OIMCarrierKeyedEmitter, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerTimeout, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandStream, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexSetBasedOptions, type TOIMCollectionKit, type TOIMCollectionOptions, type TOIMCollectionOrderedIndexOptions, type TOIMCollectionOrderedListCommandStreamOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMDerivedCollectionIndexArrayBasedOptions, type TOIMDerivedCollectionIndexSetBasedOptions, type TOIMDerivedEntityComparator, type TOIMDerivedEntityOrderSelector, type TOIMDerivedEntityOrderValue, type TOIMDerivedIndexKeySelector, type TOIMEffectOptions, type TOIMEntitySlot, type TOIMEntitySlotResolver, type TOIMEntityUpdater, type TOIMEventHandler, type TOIMEventQueueOptions, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsDerivedArrayIndexOptions, type TOIMRelationsDerivedSetIndexOptions, type TOIMRelationsOrderedListOptions, type TOIMRelationsSetIndexOptions, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload, createInPlaceEntityUpdater, createMergeEntityUpdater, createOIMCollectionIndexFactory, createOIMCollectionKit };