@oimdb/core 3.4.0 → 3.6.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.ts CHANGED
@@ -357,6 +357,127 @@ declare abstract class OIMObjectStore<TKey extends string | number | symbol, TVa
357
357
  abstract destroy(): void;
358
358
  }
359
359
 
360
+ /**
361
+ * Keyless base index: a single bucket of entity slots over the whole collection
362
+ * ("all"), with no key dimension. Mirrors {@link OIMIndex} but holds ONE bucket
363
+ * directly instead of a `Map<key, bucket>`, so there is no key parameter
364
+ * anywhere on its surface. Concrete shape (ordered array vs unordered set) is
365
+ * added by {@link OIMGlobalIndexArrayBased} / {@link OIMGlobalIndexSetBased}.
366
+ */
367
+ declare abstract class OIMGlobalIndex<TPk extends TOIMPk> {
368
+ protected readonly comparePks?: TOIMIndexComparator<TPk>;
369
+ readonly emitter: OIMEventEmitter<{
370
+ 0: void;
371
+ }>;
372
+ constructor(comparePks?: TOIMIndexComparator<TPk>);
373
+ protected abstract iterateSlots(): Iterable<TOIMAnyEntitySlot<TPk>>;
374
+ protected abstract clearBucket(): void;
375
+ abstract get size(): number;
376
+ get isEmpty(): boolean;
377
+ /**
378
+ * Materializes the bucket to entities, preserving positional holes: a slot
379
+ * whose entity is not present yet (or was removed) yields `undefined` at its
380
+ * position rather than being dropped — mirroring {@link OIMIndex}.
381
+ */
382
+ getEntities<TEntity extends object = object>(): (TEntity | undefined)[];
383
+ getMetrics(): {
384
+ totalPks: number;
385
+ };
386
+ destroy(): void;
387
+ protected emitUpdate(): void;
388
+ }
389
+
390
+ /**
391
+ * Set-based (unordered, deduped) keyless index. Holds a single `Set<slot>`
392
+ * bucket over the whole collection. Mirrors {@link OIMIndexSetBased} minus the
393
+ * key.
394
+ */
395
+ declare abstract class OIMGlobalIndexSetBased<TPk extends TOIMPk> extends OIMGlobalIndex<TPk> {
396
+ protected slots: Set<TOIMAnyEntitySlot<TPk>>;
397
+ constructor(options?: {
398
+ comparePks?: TOIMIndexComparator<TPk>;
399
+ });
400
+ get size(): number;
401
+ protected iterateSlots(): Iterable<TOIMAnyEntitySlot<TPk>>;
402
+ protected clearBucket(): void;
403
+ getPks(): Set<TPk>;
404
+ getSlots(): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
405
+ protected slotsToPks(slots: Iterable<TOIMAnyEntitySlot<TPk>>): Set<TPk>;
406
+ protected setSlotsWithComparison(newSlots: Set<TOIMAnyEntitySlot<TPk>>): boolean;
407
+ }
408
+
409
+ /**
410
+ * Array-based (ordered) keyless index. Holds a single `slot[]` bucket over the
411
+ * whole collection. Mirrors {@link OIMIndexArrayBased} minus the key.
412
+ */
413
+ declare abstract class OIMGlobalIndexArrayBased<TPk extends TOIMPk> extends OIMGlobalIndex<TPk> {
414
+ protected slots: TOIMAnyEntitySlot<TPk>[];
415
+ constructor(options?: {
416
+ comparePks?: TOIMIndexComparator<TPk>;
417
+ });
418
+ get size(): number;
419
+ protected iterateSlots(): Iterable<TOIMAnyEntitySlot<TPk>>;
420
+ protected clearBucket(): void;
421
+ getPks(): TPk[];
422
+ getSlots(): readonly TOIMAnyEntitySlot<TPk>[];
423
+ protected slotsToPks(slots: readonly TOIMAnyEntitySlot<TPk>[]): TPk[];
424
+ protected setSlotsWithComparison(newSlots: TOIMAnyEntitySlot<TPk>[]): boolean;
425
+ }
426
+
427
+ /**
428
+ * Keyless subscription surface — the counterpart of {@link IOIMKeyedSubscription}
429
+ * for a single (whole-collection) reactive node. A subscriber is notified on
430
+ * `queue.flush()` whenever the node's one bucket changes; there is no key.
431
+ */
432
+ interface IOIMSubscription {
433
+ subscribe(handler: TOIMEventHandler<void>): () => void;
434
+ }
435
+
436
+ /**
437
+ * The keyless pub/sub surface a reactive Global node needs from its update
438
+ * emitter: subscribe + a batched "mark updated" delivery. The counterpart of
439
+ * {@link IOIMKeyedUpdateEmitter}, but for exactly one carrier — so there is no
440
+ * key parameter, no resolver, and no per-key map.
441
+ */
442
+ interface IOIMSingleUpdateEmitter extends IOIMSubscription {
443
+ markUpdated(): void;
444
+ hasSubscriptions(): boolean;
445
+ destroy(): void;
446
+ }
447
+
448
+ /**
449
+ * Reactive wrapper around a keyless {@link OIMGlobalIndex}. Owns a single-carrier
450
+ * emitter (no resolver, no key→carrier map), so `subscribe(handler)` is keyless
451
+ * and directly satisfies `IOIMSelectorSourceDependency`. Mirrors
452
+ * {@link OIMReactiveIndex} minus the key.
453
+ */
454
+ declare abstract class OIMReactiveGlobalIndex<TPk extends TOIMPk, TIndex extends OIMGlobalIndex<TPk>> implements IOIMSubscription {
455
+ readonly index: TIndex;
456
+ protected readonly updateEmitter: IOIMSingleUpdateEmitter;
457
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMSingleUpdateEmitter) => TIndex);
458
+ getEntities<TEntity extends object = object>(): (TEntity | undefined)[];
459
+ get size(): number;
460
+ get isEmpty(): boolean;
461
+ subscribe(handler: TOIMEventHandler<void>): () => void;
462
+ hasSubscriptions(): boolean;
463
+ getMetrics(): {
464
+ totalPks: number;
465
+ };
466
+ destroy(): void;
467
+ }
468
+
469
+ declare abstract class OIMReactiveGlobalIndexSetBased<TPk extends TOIMPk, TIndex extends OIMGlobalIndexSetBased<TPk>> extends OIMReactiveGlobalIndex<TPk, TIndex> {
470
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMSingleUpdateEmitter) => TIndex);
471
+ getPks(): Set<TPk>;
472
+ getSlots(): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
473
+ }
474
+
475
+ declare abstract class OIMReactiveGlobalIndexArrayBased<TPk extends TOIMPk, TIndex extends OIMGlobalIndexArrayBased<TPk>> extends OIMReactiveGlobalIndex<TPk, TIndex> {
476
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMSingleUpdateEmitter) => TIndex);
477
+ getPks(): TPk[];
478
+ getSlots(): readonly TOIMAnyEntitySlot<TPk>[];
479
+ }
480
+
360
481
  type TOIMPkSelector<TEntity extends object, TPk extends TOIMPk> = (entity: TEntity) => TPk;
361
482
 
362
483
  type TOIMEntityUpdater<TEntity extends object> = (draft: Partial<TEntity>, prevEntity: TEntity) => TEntity;
@@ -620,28 +741,30 @@ type TOIMRelationsDerivedArrayIndexOptions<TEntity extends object, TKey extends
620
741
  * - supports `move` and `removeAt` without computing diffs
621
742
  * - stores slots directly; collection-bound variants resolve PKs before writes
622
743
  *
623
- * It emits UPDATE events per key on every successful mutation.
744
+ * It emits UPDATE events per key on every successful mutation. It is a plain
745
+ * data structure: it knows nothing about "commands" — turning its mutations
746
+ * into position-addressed commands is the command stream's job.
624
747
  */
625
- declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TItemKey extends TOIMPk> extends OIMIndexArrayBased<TKey, TItemKey> {
748
+ declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexArrayBased<TKey, TPk> {
626
749
  clear(key?: TKey): void;
627
- pushSlot(key: TKey, slot: TOIMAnyEntitySlot<TItemKey>): number;
628
- insertSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TItemKey>): number;
629
- removeAt(key: TKey, index: number): TOIMAnyEntitySlot<TItemKey> | undefined;
750
+ pushSlot(key: TKey, slot: TOIMAnyEntitySlot<TPk>): number;
751
+ insertSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TPk>): number;
752
+ removeAt(key: TKey, index: number): TOIMAnyEntitySlot<TPk> | undefined;
630
753
  /**
631
754
  * Remove up to `count` consecutive slots starting at `index`.
632
755
  * Returns the number actually removed (clamped to bounds; 0 if nothing).
633
756
  */
634
757
  removeRange(key: TKey, index: number, count: number): number;
635
- move(key: TKey, fromIndex: number, toIndex: number): TOIMAnyEntitySlot<TItemKey> | undefined;
758
+ move(key: TKey, fromIndex: number, toIndex: number): TOIMAnyEntitySlot<TPk> | undefined;
636
759
  /** Replace the slot at `index` in place. Returns the safe index, or -1. */
637
- setSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TItemKey>): number;
760
+ setSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TPk>): number;
638
761
  /**
639
762
  * Move up to `count` consecutive slots from `from` to `to`. `to` is in the
640
763
  * coordinate space *after* the block is extracted (same as single `move`).
641
764
  * Returns the number actually moved (0 if a no-op / out of bounds).
642
765
  */
643
766
  moveRange(key: TKey, from: number, to: number, count: number): number;
644
- resetSlots(key: TKey, slots: readonly TOIMAnyEntitySlot<TItemKey>[]): void;
767
+ resetSlots(key: TKey, slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
645
768
  private getOrCreateList;
646
769
  }
647
770
 
@@ -760,24 +883,86 @@ type TOIMOrderedListCommand<TItem> = {
760
883
  };
761
884
 
762
885
  /**
763
- * Slot-first ordered-list command stream.
886
+ * Read/consume side of an ordered-list command stream, generic over the element
887
+ * type it carries.
888
+ *
889
+ * The concrete stream stores entity slots (`TItem = TOIMEntitySlot<...>`); a
890
+ * mapped source ({@link OIMOrderedListMappedCommandStream}) carries whatever the
891
+ * mapping produces. A consumer that depends on this interface works unchanged
892
+ * against either — raw or mapped.
764
893
  *
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
768
- * `OIMCollectionOrderedListCommandStream`.
894
+ * Consumption is pull-based and synchronous: the notification carries no
895
+ * payload, so `consumeCommands(key)` must be called inside the `handler`, before
896
+ * the buffer for that key is cleared.
769
897
  */
770
- declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> {
898
+ interface IOIMOrderedListCommandSource<TKey extends TOIMPk, TItem> {
899
+ /**
900
+ * Subscribe to per-key command notifications. The handler receives no
901
+ * payload — pull the commands with {@link consumeCommands} synchronously.
902
+ * Returns an unsubscribe function.
903
+ */
904
+ subscribeCommands(key: TKey, handler: () => void): () => void;
905
+ /** Drain the commands buffered for `key` this delivery (a copy). */
906
+ consumeCommands(key: TKey): TOIMOrderedListCommand<TItem>[];
907
+ /** Current ordered items for `key` — the initial state before any command. */
908
+ getItemsByKey(key: TKey): readonly TItem[];
909
+ }
910
+
911
+ /**
912
+ * Abstract base for position-addressed ordered-list command streams.
913
+ *
914
+ * Holds the machinery that is independent of what *produces* the commands:
915
+ * per-key command buffering with reset-coalescing, `after_flush` delivery via
916
+ * {@link commandsEventEmitter}, and the pull-based consume/subscribe surface
917
+ * ({@link IOIMOrderedListCommandSource}). The driver lives in the subclass:
918
+ * `OIMOrderedListCommandStream` appends commands from imperative writers;
919
+ * `OIMOrderedListCommandStreamDiffDriven` appends them by diffing a reactive
920
+ * index.
921
+ *
922
+ * {@link getItemsByKey} is abstract — each driver reads the current order from
923
+ * its own backing (a manual ordered index, or an external reactive index). It is
924
+ * consulted only on the cold reset-coalescing path, so it stays off the hot
925
+ * append path.
926
+ */
927
+ declare abstract class OIMOrderedListCommandBuffer<TKey extends TOIMPk, TItem> implements IOIMOrderedListCommandSource<TKey, TItem> {
771
928
  readonly commandsEventEmitter: OIMUpdateEventEmitter<TKey>;
772
929
  private readonly unsubscribeAfterFlush;
773
- private readonly unsubscribeFromIndexEmitter;
774
- protected isInWrite: boolean;
775
- private readonly commandsByKey;
930
+ protected readonly commandsByKey: Map<TKey, TOIMOrderedListCommand<TItem>[]>;
931
+ constructor(queue: OIMEventQueue);
932
+ /** Current ordered items for `key` (the driver's backing order). */
933
+ abstract getItemsByKey(key: TKey): readonly TItem[];
934
+ subscribeCommands(key: TKey, handler: () => void): () => void;
935
+ getBufferedCommands(key: TKey): readonly TOIMOrderedListCommand<TItem>[];
936
+ consumeCommands(key: TKey): TOIMOrderedListCommand<TItem>[];
937
+ destroy(): void;
938
+ private readonly onAfterFlush;
939
+ protected appendCommand(key: TKey, cmd: TOIMOrderedListCommand<TItem>): void;
940
+ protected appendResetCommand(key: TKey, items: readonly TItem[]): void;
941
+ protected createResetCommand(items: readonly TItem[]): TOIMOrderedListCommand<TItem>;
942
+ }
943
+
944
+ /**
945
+ * Slot-first ordered-list command stream.
946
+ *
947
+ * Emits position-addressed commands whose `item` is the entity slot, driven by
948
+ * its own writer methods (`pushSlot`, `move`, `removeAt`, …) — each mutates the
949
+ * backing ordered index and records the matching command. Write through the
950
+ * stream (not the index directly) to have your edits recorded. For PK writes
951
+ * bound to a collection, use `OIMCollectionOrderedListCommandStream`; to derive
952
+ * commands from an existing reactive index instead of writing them, use
953
+ * `OIMOrderedListCommandStreamDiffDriven`.
954
+ *
955
+ * Command buffering, `after_flush` delivery and the consume/subscribe surface
956
+ * come from {@link OIMOrderedListCommandBuffer}.
957
+ */
958
+ declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMOrderedListCommandBuffer<TKey, TOIMEntitySlot<TEntity, TPk>> {
776
959
  /** Underlying slot-first ordered index. */
777
960
  readonly index: OIMIndexManualOrderedArrayBased<TKey, TPk>;
778
961
  constructor(queue: OIMEventQueue, index?: OIMIndexManualOrderedArrayBased<TKey, TPk>);
779
962
  getPksByKey(key: TKey): readonly TPk[];
780
963
  getSlotsByKey(key: TKey): readonly TOIMEntitySlot<TEntity, TPk>[];
964
+ /** {@link OIMOrderedListCommandBuffer.getItemsByKey} — the slots in order. */
965
+ getItemsByKey(key: TKey): readonly TOIMEntitySlot<TEntity, TPk>[];
781
966
  getEntitiesByKey(key: TKey): (TEntity | undefined)[];
782
967
  hasKey(key: TKey): boolean;
783
968
  getKeys(): readonly TKey[];
@@ -795,22 +980,15 @@ declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMP
795
980
  */
796
981
  moveRange(key: TKey, from: number, to: number, count: number): void;
797
982
  setSlots(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
798
- getBufferedCommands(key: TKey): readonly TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>[];
799
- consumeCommands(key: TKey): TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>[];
800
983
  clear(key?: TKey): void;
801
984
  destroy(): void;
802
- private readonly onAfterFlush;
803
- private readonly onIndexUpdate;
804
- protected withWrite(fn: () => void): void;
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>>;
808
985
  }
809
986
 
810
987
  /**
811
988
  * Collection-bound ordered-list command stream.
812
989
  *
813
- * Public writes use PKs, internally they resolve to canonical collection slots.
990
+ * Public writes use PKs; they resolve to canonical collection slots (throwing on
991
+ * an unresolvable pk) before mutating the index and recording the command.
814
992
  */
815
993
  declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMOrderedListCommandStream<TKey, TPk, TEntity> {
816
994
  readonly index: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
@@ -989,6 +1167,220 @@ declare class OIMDerivedCollectionIndexArrayBased<TKey extends TOIMPk, TPk exten
989
1167
  private normalizeKeys;
990
1168
  }
991
1169
 
1170
+ /**
1171
+ * Manual array-based keyless index — direct raw-slot control of the single
1172
+ * ordered bucket. Mirrors {@link OIMIndexManualArrayBased} minus the key.
1173
+ */
1174
+ declare class OIMGlobalIndexManualArrayBased<TPk extends TOIMPk> extends OIMGlobalIndexArrayBased<TPk> {
1175
+ constructor(options?: {
1176
+ comparePks?: TOIMIndexComparator<TPk>;
1177
+ });
1178
+ setSlots(slots: TOIMAnyEntitySlot<TPk>[]): void;
1179
+ /**
1180
+ * Appends pre-deduplicated slots to the bucket IN PLACE and emits once.
1181
+ * O(added). Callers own dedup (used by collection-bound `addPks`).
1182
+ */
1183
+ appendSlots(slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1184
+ clear(): void;
1185
+ }
1186
+
1187
+ /**
1188
+ * Reactive manual array-based keyless index — raw-slot writes bridged to a
1189
+ * single-carrier emitter. Mirrors {@link OIMReactiveIndexManualArrayBased}.
1190
+ */
1191
+ declare class OIMReactiveGlobalIndexManualArrayBased<TPk extends TOIMPk> extends OIMReactiveGlobalIndexArrayBased<TPk, OIMGlobalIndexManualArrayBased<TPk>> {
1192
+ constructor(queue: OIMEventQueue, opts?: {
1193
+ indexOptions?: {
1194
+ comparePks?: TOIMIndexComparator<TPk>;
1195
+ };
1196
+ });
1197
+ setSlots(slots: TOIMAnyEntitySlot<TPk>[]): void;
1198
+ appendSlots(slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1199
+ clear(): void;
1200
+ }
1201
+
1202
+ /**
1203
+ * Predicate deciding whether an entity belongs to a derived Global index.
1204
+ * Defaults to "the entity exists" (`item !== undefined`) when omitted.
1205
+ */
1206
+ type TOIMGlobalIndexFilter<TEntity extends object> = (entity: TEntity) => boolean;
1207
+ type TOIMCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1208
+ indexOptions?: {
1209
+ comparePks?: TOIMIndexComparator<TPk>;
1210
+ };
1211
+ } & ({
1212
+ collection: OIMReactiveCollection<TEntity, TPk>;
1213
+ resolveSlot?: never;
1214
+ } | {
1215
+ collection?: never;
1216
+ resolveSlot: TOIMEntitySlotResolver<TPk>;
1217
+ });
1218
+ type TOIMCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1219
+ indexOptions?: {
1220
+ comparePks?: TOIMIndexComparator<TPk>;
1221
+ };
1222
+ } & ({
1223
+ collection: OIMReactiveCollection<TEntity, TPk>;
1224
+ resolveSlot?: never;
1225
+ } | {
1226
+ collection?: never;
1227
+ resolveSlot: TOIMEntitySlotResolver<TPk>;
1228
+ });
1229
+ type TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1230
+ /** Build initial state from existing collection slots. Defaults to true. */
1231
+ buildInitial?: boolean;
1232
+ /** Sort the list. Takes priority over `orderBy`. */
1233
+ compareEntities?: TOIMDerivedEntityComparator<TEntity>;
1234
+ /** Convenience ordering selector for common ordered-list cases. */
1235
+ orderBy?: TOIMDerivedEntityOrderSelector<TEntity>;
1236
+ /** Include predicate. Defaults to "entity exists". */
1237
+ filter?: TOIMGlobalIndexFilter<TEntity>;
1238
+ indexOptions?: {
1239
+ comparePks?: TOIMIndexComparator<TPk>;
1240
+ };
1241
+ };
1242
+ type TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1243
+ /** Build initial state from existing collection slots. Defaults to true. */
1244
+ buildInitial?: boolean;
1245
+ /** Include predicate. Defaults to "entity exists". */
1246
+ filter?: TOIMGlobalIndexFilter<TEntity>;
1247
+ indexOptions?: {
1248
+ comparePks?: TOIMIndexComparator<TPk>;
1249
+ };
1250
+ };
1251
+ type TOIMRelationsGlobalArrayIndexOptions<TPk extends TOIMPk> = {
1252
+ indexOptions?: {
1253
+ comparePks?: TOIMIndexComparator<TPk>;
1254
+ };
1255
+ };
1256
+ type TOIMRelationsGlobalSetIndexOptions<TPk extends TOIMPk> = {
1257
+ indexOptions?: {
1258
+ comparePks?: TOIMIndexComparator<TPk>;
1259
+ };
1260
+ };
1261
+ type TOIMRelationsDerivedGlobalArrayIndexOptions<TEntity extends object, TPk extends TOIMPk> = TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity, TPk>;
1262
+ type TOIMRelationsDerivedGlobalSetIndexOptions<TEntity extends object, TPk extends TOIMPk> = TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity, TPk>;
1263
+
1264
+ /**
1265
+ * Collection-bound reactive array-based keyless index.
1266
+ *
1267
+ * PK writes (`setPks`/`addPks`/`removePks`) resolve canonical entity slots
1268
+ * through the collection binding. A single `membership` set gives O(1) `addPks`
1269
+ * dedup. Mirrors {@link OIMReactiveCollectionIndexManualArrayBased} minus the
1270
+ * key (one bucket instead of a per-key map).
1271
+ */
1272
+ declare class OIMReactiveCollectionGlobalIndexManualArrayBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveGlobalIndexManualArrayBased<TPk> {
1273
+ private readonly resolveSlot;
1274
+ private readonly membership;
1275
+ private membershipSeeded;
1276
+ constructor(queue: OIMEventQueue, opts: TOIMCollectionGlobalIndexArrayBasedOptions<TEntity, TPk>);
1277
+ setPks(pks: readonly TPk[]): void;
1278
+ addPks(pks: readonly TPk[]): void;
1279
+ removePks(pks: readonly TPk[]): void;
1280
+ clear(): void;
1281
+ private membershipOf;
1282
+ getEntities<TItem extends object = TEntity>(): (TItem | undefined)[];
1283
+ private resolveSlots;
1284
+ private resolveRequiredSlot;
1285
+ }
1286
+
1287
+ /**
1288
+ * Manual set-based keyless index — direct raw-slot control of the single
1289
+ * unordered bucket. Mirrors {@link OIMIndexManualSetBased} minus the key.
1290
+ */
1291
+ declare class OIMGlobalIndexManualSetBased<TPk extends TOIMPk> extends OIMGlobalIndexSetBased<TPk> {
1292
+ constructor(options?: {
1293
+ comparePks?: TOIMIndexComparator<TPk>;
1294
+ });
1295
+ setSlots(slots: Iterable<TOIMAnyEntitySlot<TPk>>): void;
1296
+ /** Adds slots IN PLACE (O(added)) and emits once if anything changed. */
1297
+ addSlots(slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1298
+ /** Removes slots IN PLACE (O(removed)) and emits once if anything changed. */
1299
+ removeSlots(slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1300
+ clear(): void;
1301
+ }
1302
+
1303
+ /**
1304
+ * Reactive manual set-based keyless index — raw-slot writes bridged to a
1305
+ * single-carrier emitter. Mirrors {@link OIMReactiveIndexManualSetBased}.
1306
+ */
1307
+ declare class OIMReactiveGlobalIndexManualSetBased<TPk extends TOIMPk> extends OIMReactiveGlobalIndexSetBased<TPk, OIMGlobalIndexManualSetBased<TPk>> {
1308
+ constructor(queue: OIMEventQueue, opts?: {
1309
+ indexOptions?: {
1310
+ comparePks?: TOIMIndexComparator<TPk>;
1311
+ };
1312
+ });
1313
+ setSlots(slots: Iterable<TOIMAnyEntitySlot<TPk>>): void;
1314
+ addSlots(slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1315
+ removeSlots(slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1316
+ clear(): void;
1317
+ }
1318
+
1319
+ /**
1320
+ * Collection-bound reactive set-based keyless index.
1321
+ *
1322
+ * PK writes (`setPks`/`addPks`/`removePks`) resolve canonical entity slots
1323
+ * through the collection binding. A single pk→slot `membership` map gives O(1)
1324
+ * add (dedup) and O(1) remove. Mirrors
1325
+ * {@link OIMReactiveCollectionIndexManualSetBased} minus the key.
1326
+ */
1327
+ declare class OIMReactiveCollectionGlobalIndexManualSetBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveGlobalIndexManualSetBased<TPk> {
1328
+ private readonly resolveSlot;
1329
+ private readonly membership;
1330
+ private membershipSeeded;
1331
+ constructor(queue: OIMEventQueue, opts: TOIMCollectionGlobalIndexSetBasedOptions<TEntity, TPk>);
1332
+ setPks(pks: readonly TPk[]): void;
1333
+ addPks(pks: readonly TPk[]): void;
1334
+ removePks(pks: readonly TPk[]): void;
1335
+ clear(): void;
1336
+ private membershipOf;
1337
+ getEntities<TItem extends object = TEntity>(): (TItem | undefined)[];
1338
+ private resolveRequiredSlot;
1339
+ }
1340
+
1341
+ /**
1342
+ * Keyless array-based index derived from the whole collection.
1343
+ *
1344
+ * Auto-maintains a single ordered list of every entity that passes `filter`
1345
+ * (default: "entity exists"), sorted by `orderBy`/`compareEntities`. Mirrors
1346
+ * {@link OIMDerivedCollectionIndexArrayBased}, but membership is a single
1347
+ * boolean set (`presentPks`) instead of a per-pk key-set.
1348
+ */
1349
+ declare class OIMDerivedCollectionGlobalIndexArrayBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionGlobalIndexManualArrayBased<TPk, TEntity> {
1350
+ private readonly collection;
1351
+ private readonly compareEntities?;
1352
+ private readonly orderBy?;
1353
+ private readonly filter?;
1354
+ private readonly unsubscribeFromCollection;
1355
+ private readonly presentPks;
1356
+ private readonly orderValueByPk;
1357
+ constructor(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>, opts: TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity, TPk>);
1358
+ rebuildFromCollection(): void;
1359
+ clear(): void;
1360
+ destroy(): void;
1361
+ private readonly onCollectionUpdate;
1362
+ private sortSlots;
1363
+ }
1364
+
1365
+ /**
1366
+ * Keyless set-based index derived from the whole collection.
1367
+ *
1368
+ * Auto-maintains a single unordered set of every entity that passes `filter`
1369
+ * (default: "entity exists"). Mirrors {@link OIMDerivedCollectionIndexSetBased}
1370
+ * minus the key.
1371
+ */
1372
+ declare class OIMDerivedCollectionGlobalIndexSetBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionGlobalIndexManualSetBased<TPk, TEntity> {
1373
+ private readonly collection;
1374
+ private readonly filter?;
1375
+ private readonly unsubscribeFromCollection;
1376
+ private readonly presentPks;
1377
+ constructor(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>, opts: TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity, TPk>);
1378
+ rebuildFromCollection(): void;
1379
+ clear(): void;
1380
+ destroy(): void;
1381
+ private readonly onCollectionUpdate;
1382
+ }
1383
+
992
1384
  /**
993
1385
  * Factory helper for collection-bound indexes.
994
1386
  *
@@ -1004,6 +1396,20 @@ declare class OIMCollectionIndexFactory<TEntity extends object, TPk extends TOIM
1004
1396
  derivedSetIndex<TKey extends TOIMPk = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedSetIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexSetBased<TKey, TPk, TEntity>;
1005
1397
  arrayBasedIndex<TKey extends TOIMPk = string>(opts?: TOIMRelationsArrayIndexOptions<TKey, TPk>): OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity>;
1006
1398
  derivedArrayIndex<TKey extends TOIMPk = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedArrayIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexArrayBased<TKey, TPk, TEntity>;
1399
+ /**
1400
+ * Keyless (whole-collection / "all") manual array-based index. No key —
1401
+ * write pks directly with `setPks`/`addPks`/`removePks`.
1402
+ */
1403
+ arrayBasedGlobalIndex(opts?: TOIMRelationsGlobalArrayIndexOptions<TPk>): OIMReactiveCollectionGlobalIndexManualArrayBased<TPk, TEntity>;
1404
+ /** Keyless (whole-collection) manual set-based index. */
1405
+ setBasedGlobalIndex(opts?: TOIMRelationsGlobalSetIndexOptions<TPk>): OIMReactiveCollectionGlobalIndexManualSetBased<TPk, TEntity>;
1406
+ /**
1407
+ * Keyless ordered list auto-derived from the whole collection. Pass
1408
+ * `orderBy`/`compareEntities` for order, `filter` to include a subset.
1409
+ */
1410
+ derivedArrayGlobalIndex(opts?: TOIMRelationsDerivedGlobalArrayIndexOptions<TEntity, TPk>): OIMDerivedCollectionGlobalIndexArrayBased<TPk, TEntity>;
1411
+ /** Keyless set auto-derived from the whole collection. */
1412
+ derivedSetGlobalIndex(opts?: TOIMRelationsDerivedGlobalSetIndexOptions<TEntity, TPk>): OIMDerivedCollectionGlobalIndexSetBased<TPk, TEntity>;
1007
1413
  orderedIndex<TKey extends TOIMPk = string>(): OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
1008
1414
  orderedList<TKey extends TOIMPk = string>(opts?: TOIMRelationsOrderedListOptions<TKey, TPk, TEntity>): OIMCollectionOrderedListCommandStream<TKey, TPk, TEntity>;
1009
1415
  }
@@ -1195,6 +1601,38 @@ declare function createInPlaceEntityUpdater<TEntity extends object>(): TOIMEntit
1195
1601
  */
1196
1602
  declare function createMergeEntityUpdater<TEntity extends object>(): TOIMEntityUpdater<TEntity>;
1197
1603
 
1604
+ /**
1605
+ * Keyless (single-carrier) pub/sub. The emitter IS the carrier: it holds one
1606
+ * subscriber set and one dirty flag, so the hot path — marking updated and
1607
+ * delivering — needs no resolver, no `Map`, no per-key hashing, and no
1608
+ * `dirtyCarriers[]` batch (there is only ever one carrier).
1609
+ *
1610
+ * This is the {@link OIMCarrierKeyedEmitter} analogue for a whole-collection
1611
+ * ("Global") reactive index. Every op here is strictly cheaper than its keyed
1612
+ * counterpart: `subscribe` is one `Set.add` (no `getOrReserveCarrier`),
1613
+ * `markUpdated` is a flag flip + a single `queue.enqueue` (no map lookup, no
1614
+ * array push).
1615
+ */
1616
+ declare class OIMCarrierSingleEmitter implements IOIMSingleUpdateEmitter {
1617
+ private readonly queue;
1618
+ private subscribers?;
1619
+ private dirty;
1620
+ private isFlushEnqueued;
1621
+ constructor(queue: OIMEventQueue);
1622
+ subscribe(handler: TOIMEventHandler<void>): () => void;
1623
+ markUpdated(): void;
1624
+ hasSubscriptions(): boolean;
1625
+ getMetrics(): {
1626
+ totalHandlers: number;
1627
+ queueLength: number;
1628
+ };
1629
+ destroy(): void;
1630
+ private assertNotInFlush;
1631
+ private scheduleFlush;
1632
+ private readonly onFlush;
1633
+ private notify;
1634
+ }
1635
+
1198
1636
  /**
1199
1637
  * Factory for creating index comparators.
1200
1638
  * Provides common comparison strategies for primary key arrays.
@@ -1318,6 +1756,10 @@ declare class OIMCollectionSelectors<TEntity extends object, TPk extends TOIMPk>
1318
1756
  byPks(pks: readonly TPk[]): TOIMCollectionEntitiesSelector<TEntity>;
1319
1757
  entitiesBySetIndexKey<TKey extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>>(index: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
1320
1758
  entitiesByArrayIndexKey<TKey extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>>(index: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
1759
+ /** Entities of a keyless (whole-collection) array-based index, ordered. */
1760
+ entitiesByArrayGlobalIndex<TIndex extends OIMGlobalIndexArrayBased<TPk>>(index: OIMReactiveGlobalIndexArrayBased<TPk, TIndex>): TOIMCollectionEntitiesSelector<TEntity>;
1761
+ /** Entities of a keyless (whole-collection) set-based index. */
1762
+ entitiesBySetGlobalIndex<TIndex extends OIMGlobalIndexSetBased<TPk>>(index: OIMReactiveGlobalIndexSetBased<TPk, TIndex>): TOIMCollectionEntitiesSelector<TEntity>;
1321
1763
  }
1322
1764
 
1323
1765
  type TOIMReactiveCollectionFactoryOptions<TEntity extends object, TPk extends TOIMPk> = TOIMCollectionOptions<TEntity, TPk>;
@@ -1398,6 +1840,232 @@ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOI
1398
1840
  private trackPatch;
1399
1841
  }
1400
1842
 
1843
+ /**
1844
+ * Projects an ordered-list command source element-wise, re-emitting the same
1845
+ * position-addressed commands with `item` replaced by `create(item)`.
1846
+ *
1847
+ * It rides the source's batching: there is no queue and no independent
1848
+ * scheduling. On each source notification it pulls the source commands,
1849
+ * translates them (running `create` and updating a positional mirror of the
1850
+ * mapped elements), and notifies its own subscribers synchronously — so the
1851
+ * source's `after_flush` semantics carry through.
1852
+ *
1853
+ * Identity is positional: a `move` reorders the *same* mapped references in the
1854
+ * mirror, so the mapped element is preserved across moves and never recreated.
1855
+ * `create` runs on `insert` / `set` / `reset` / initial build.
1856
+ *
1857
+ * There is no teardown callback by design: the leaving element is already the
1858
+ * `remove` / `reset` / `set` command a consumer applies against its own mirror,
1859
+ * so any DOM/resource cleanup belongs there — a `destroy` hook would only be
1860
+ * duplicating a signal the consumer already receives.
1861
+ *
1862
+ * Wiring to the source for a key is lazy (on first `subscribeCommands` or
1863
+ * `getItemsByKey`) and lives until `destroy()`; subscriber churn does not
1864
+ * create mapped elements.
1865
+ *
1866
+ * The output is itself an {@link IOIMOrderedListCommandSource}, so maps chain:
1867
+ * `source.map(...)` → `.map(...)`.
1868
+ */
1869
+ declare class OIMOrderedListMappedCommandStream<TKey extends TOIMPk, TOut, TIn> implements IOIMOrderedListCommandSource<TKey, TOut> {
1870
+ private readonly source;
1871
+ private readonly create;
1872
+ /** Per-key positional mirror of the mapped elements. */
1873
+ private readonly mirror;
1874
+ /** Mapped commands produced for the current delivery, per key. */
1875
+ private readonly buffer;
1876
+ private readonly subscribers;
1877
+ private readonly sourceUnsubscribers;
1878
+ constructor(source: IOIMOrderedListCommandSource<TKey, TIn>, create: (item: TIn) => TOut);
1879
+ subscribeCommands(key: TKey, handler: () => void): () => void;
1880
+ consumeCommands(key: TKey): TOIMOrderedListCommand<TOut>[];
1881
+ getItemsByKey(key: TKey): readonly TOut[];
1882
+ /** Map this source again, chaining the projection. */
1883
+ map<TNext>(create: (item: TOut) => TNext): OIMOrderedListMappedCommandStream<TKey, TNext, TOut>;
1884
+ destroy(): void;
1885
+ /** Build the initial mirror and subscribe to the source once per key. */
1886
+ private ensureWired;
1887
+ private onSourceCommands;
1888
+ }
1889
+
1890
+ /**
1891
+ * Map an ordered-list command source element-wise. The result is itself a
1892
+ * source, so it can be mapped again (or via its `.map()` method).
1893
+ *
1894
+ * ```ts
1895
+ * const nodes = createOIMOrderedListMappedCommandStream(stream, (slot) =>
1896
+ * engine.makeNode(slot.item)
1897
+ * );
1898
+ * nodes.subscribeCommands(key, () => {
1899
+ * for (const cmd of nodes.consumeCommands(key)) {
1900
+ * // cmd.item is your node; tear it down on `remove` / `set` / `reset`
1901
+ * }
1902
+ * });
1903
+ * ```
1904
+ */
1905
+ declare function createOIMOrderedListMappedCommandStream<TKey extends TOIMPk, TIn, TOut>(source: IOIMOrderedListCommandSource<TKey, TIn>, create: (item: TIn) => TOut): OIMOrderedListMappedCommandStream<TKey, TOut, TIn>;
1906
+
1907
+ /**
1908
+ * Minimal read/subscribe surface a keyed index exposes for slot mapping:
1909
+ * iterate the slots under a key and subscribe to that key's changes.
1910
+ *
1911
+ * Both `OIMReactiveIndexSetBased` (slots as a `ReadonlySet`) and
1912
+ * `OIMReactiveIndexArrayBased` (slots as a `readonly` array) satisfy it
1913
+ * structurally — a `Set` and an array are both `Iterable`.
1914
+ */
1915
+ interface IOIMIndexSlotSource<TKey extends TOIMPk, TPk extends TOIMPk> extends IOIMKeyedSubscription<TKey> {
1916
+ getSlotsByKey(key: TKey): Iterable<TOIMAnyEntitySlot<TPk>>;
1917
+ }
1918
+
1919
+ /**
1920
+ * Stable slot→object memo over a keyed set/array index.
1921
+ *
1922
+ * `create(slot)` runs once per canonical slot; every later read for the same
1923
+ * slot returns the **same** object reference. That lets a consumer re-read a
1924
+ * key's members on each notification and still hand reference-equal objects to
1925
+ * `React.memo` / `Object.is` diffing, or reuse the same view-model instance.
1926
+ *
1927
+ * Identity is the slot object (which a collection-bound index keeps canonical
1928
+ * and shared per pk). The cache is a `WeakMap`, so a mapped object is reclaimed
1929
+ * by GC once its slot is dropped and unreferenced — there is no lifecycle
1930
+ * callback and none is needed for plain values. If your mapped objects hold
1931
+ * resources that need explicit teardown (DOM nodes, subscriptions), use the
1932
+ * ordered command stream (`createOIMOrderedListMappedCommandStream`), which has
1933
+ * an exact removal signal to drive `destroy`.
1934
+ *
1935
+ * This is a thin wrapper: it holds no queue and no standing subscription of its
1936
+ * own — `subscribeOnKey` is a passthrough to the index.
1937
+ */
1938
+ declare class OIMIndexSlotMap<TKey extends TOIMPk, TPk extends TOIMPk, TMapped> {
1939
+ private readonly index;
1940
+ private readonly create;
1941
+ private readonly cache;
1942
+ constructor(index: IOIMIndexSlotSource<TKey, TPk>, create: (slot: TOIMAnyEntitySlot<TPk>) => TMapped);
1943
+ /** The mapped object for a slot, created once and cached by slot identity. */
1944
+ get(slot: TOIMAnyEntitySlot<TPk>): TMapped;
1945
+ /**
1946
+ * Mapped objects for every slot under `key`, with stable references. For a
1947
+ * set-based index the order is unspecified (as the set is); for an
1948
+ * array-based index it follows the index order.
1949
+ */
1950
+ getByKey(key: TKey): TMapped[];
1951
+ /**
1952
+ * Chain another projection. `map(f)` returns a slot map over the SAME index
1953
+ * whose objects are `f(this.get(slot))`, cached by slot identity — so both
1954
+ * levels hand back stable references and each `create` runs once per slot.
1955
+ * Mirrors the command stream's `.map()`.
1956
+ */
1957
+ map<TNext>(create: (mapped: TMapped) => TNext): OIMIndexSlotMap<TKey, TPk, TNext>;
1958
+ /** Subscribe to a key's changes — passthrough to the index. */
1959
+ subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
1960
+ /** Subscribe to several keys — passthrough to the index. */
1961
+ subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
1962
+ }
1963
+
1964
+ /**
1965
+ * Map the slots of a keyed set/array index to stable per-slot objects.
1966
+ *
1967
+ * ```ts
1968
+ * const usersByTeam = users.indexFactory.derivedSetIndex((u) => u.teamId);
1969
+ * const rows = createOIMIndexSlotMap(usersByTeam, (slot) => makeRow(slot.item));
1970
+ *
1971
+ * rows.subscribeOnKey('team1', render);
1972
+ * function render() {
1973
+ * for (const row of rows.getByKey('team1')) { /* same instance per slot *\/ }
1974
+ * }
1975
+ * ```
1976
+ */
1977
+ declare function createOIMIndexSlotMap<TKey extends TOIMPk, TPk extends TOIMPk, TMapped>(index: IOIMIndexSlotSource<TKey, TPk>, create: (slot: TOIMAnyEntitySlot<TPk>) => TMapped): OIMIndexSlotMap<TKey, TPk, TMapped>;
1978
+
1979
+ /**
1980
+ * Options for {@link OIMOrderedListCommandStreamDiffDriven}.
1981
+ */
1982
+ type TOIMOrderedListDiffOptions = {
1983
+ /**
1984
+ * Fraction of shared pks below which a whole `reset` is emitted instead of
1985
+ * fine-grained insert/move/remove commands (when most of a bucket changed,
1986
+ * a reset is cheaper than a pile of edits). Range `(0, 1)`.
1987
+ *
1988
+ * Default `0` — always diff. An unchanged order (same pks in the same
1989
+ * positions) still yields zero commands regardless of this value.
1990
+ */
1991
+ resetThreshold?: number;
1992
+ };
1993
+
1994
+ /**
1995
+ * Diff two ordered lists of pk-identified items into position-addressed
1996
+ * commands (`insert` / `remove` / `move`) that transform `prev` into `next`.
1997
+ *
1998
+ * Identity is `item.pk`; content is not compared (a reordered same-pk item is a
1999
+ * `move`, never recreated). Correctness is by construction: commands are emitted
2000
+ * against a working copy that mirrors what a consumer applying them holds, so
2001
+ * `applyCommands(prev, diffOrderedListByPk(prev, next))` equals `next` by pk.
2002
+ *
2003
+ * Moves are minimal. A longest-increasing-subsequence pass finds the common
2004
+ * items already in relative order — those stay; every other common item moves
2005
+ * exactly once, so the move count is `commonCount − LIS` (the optimum). This is
2006
+ * the standard keyed reconciliation used by imperative DOM renderers: each
2007
+ * non-anchor item is placed immediately before the already-positioned item to
2008
+ * its right (`next[j + 1]`), processed right → left.
2009
+ *
2010
+ * It intentionally does NOT emit `reset`; callers decide when a whole reset is
2011
+ * cheaper (see `OIMOrderedListCommandStreamDiffDriven`). Complexity is O(n·m)
2012
+ * worst case (an index scan per placed item), acceptable for the moderate bucket
2013
+ * sizes indexes produce, where it runs only on an actual change.
2014
+ */
2015
+ declare function diffOrderedListByPk<TPk extends TOIMPk, TItem extends {
2016
+ pk: TPk;
2017
+ }>(prev: readonly TItem[], next: readonly TItem[]): TOIMOrderedListCommand<TItem>[];
2018
+
2019
+ /**
2020
+ * Ordered-list command stream driven by an existing reactive **array-based**
2021
+ * index (derived or manual). Instead of imperative writers, it diffs the
2022
+ * previous per-key order against the new one on every index change and emits the
2023
+ * position-addressed commands that transform one into the other — so a
2024
+ * collection change becomes `insert` / `move` / `remove` (or a `reset`) that an
2025
+ * imperative renderer can apply, moving nodes instead of rebuilding them.
2026
+ *
2027
+ * It rides the index's batching: the index delivers its coalesced per-key change
2028
+ * during the queue flush; this stream diffs there and buffers commands, which
2029
+ * the shared {@link OIMOrderedListCommandBuffer} delivers at `AFTER_FLUSH` — the
2030
+ * same timing contract as the writer stream.
2031
+ *
2032
+ * Wiring to the index for a key is lazy (first `subscribeCommands` or
2033
+ * `getItemsByKey`) and lives until `destroy()`. The output is an
2034
+ * `IOIMOrderedListCommandSource`, so it consumes exactly like the writer stream
2035
+ * and composes with `createOIMOrderedListMappedCommandStream`.
2036
+ */
2037
+ declare class OIMOrderedListCommandStreamDiffDriven<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object, TIndex extends OIMIndexArrayBased<TKey, TPk> = OIMIndexArrayBased<TKey, TPk>> extends OIMOrderedListCommandBuffer<TKey, TOIMEntitySlot<TEntity, TPk>> {
2038
+ private readonly index;
2039
+ private readonly resetThreshold;
2040
+ private readonly prevByKey;
2041
+ private readonly indexUnsubscribeByKey;
2042
+ constructor(queue: OIMEventQueue, index: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, opts?: TOIMOrderedListDiffOptions);
2043
+ getItemsByKey(key: TKey): readonly TOIMEntitySlot<TEntity, TPk>[];
2044
+ subscribeCommands(key: TKey, handler: () => void): () => void;
2045
+ destroy(): void;
2046
+ private currentSlots;
2047
+ /** Snapshot the current order and subscribe to the index once per key. */
2048
+ private ensureWired;
2049
+ private onIndexChange;
2050
+ private emitDiff;
2051
+ }
2052
+
2053
+ /**
2054
+ * Derive an ordered-list command stream from a reactive array-based index — the
2055
+ * index's per-key order changes become position-addressed commands.
2056
+ *
2057
+ * ```ts
2058
+ * const cardsByDeck = cards.indexFactory.derivedArrayIndex(
2059
+ * (c) => c.deckId, { orderBy: (c) => c.position }
2060
+ * );
2061
+ * const stream = createOIMOrderedListCommandStreamDiffDriven(queue, cardsByDeck);
2062
+ * stream.subscribeCommands('deck1', () =>
2063
+ * engine.apply(stream.consumeCommands('deck1')) // insert/move/remove
2064
+ * );
2065
+ * ```
2066
+ */
2067
+ declare function createOIMOrderedListCommandStreamDiffDriven<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object, TIndex extends OIMIndexArrayBased<TKey, TPk> = OIMIndexArrayBased<TKey, TPk>>(queue: OIMEventQueue, index: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, opts?: TOIMOrderedListDiffOptions): OIMOrderedListCommandStreamDiffDriven<TKey, TPk, TEntity, TIndex>;
2068
+
1401
2069
  /**
1402
2070
  * Animation frame-based scheduler that executes flushes synchronized with the browser's repaint cycle.
1403
2071
  * Ideal for UI-related updates that need to be synchronized with rendering.
@@ -1414,7 +2082,7 @@ declare class OIMEventQueueSchedulerAnimationFrame extends OIMEventQueueSchedule
1414
2082
  /**
1415
2083
  * Available scheduler types for event queue configuration.
1416
2084
  */
1417
- type TOIMSchedulerType = 'microtask' | 'animationFrame' | 'timeout' | 'immediate';
2085
+ type TOIMSchedulerType = 'microtask' | 'animationFrame' | 'timeout' | 'immediate' | 'sync';
1418
2086
 
1419
2087
  /**
1420
2088
  * Configuration options for different scheduler types. */
@@ -1425,6 +2093,7 @@ type TOIMSchedulerOptions = {
1425
2093
  delay?: number;
1426
2094
  };
1427
2095
  immediate: never;
2096
+ sync: never;
1428
2097
  };
1429
2098
 
1430
2099
  /**
@@ -1469,6 +2138,28 @@ declare class OIMEventQueueSchedulerImmediate extends OIMEventQueueScheduler {
1469
2138
  cancel(): void;
1470
2139
  }
1471
2140
 
2141
+ /**
2142
+ * Synchronous scheduler — flushes immediately, in the same call stack, on the
2143
+ * enqueue that triggers scheduling. It performs NO batching: every write that
2144
+ * schedules a flush is delivered right away.
2145
+ *
2146
+ * This is a DEBUG / diagnostic tool, not a production scheduler. Swap it in at
2147
+ * the root to strip all coalescing and test whether a suspected bug is caused by
2148
+ * batch timing: if the bug disappears under synchronous delivery it is
2149
+ * coalescing-related, if it persists it is not. It automates what manually
2150
+ * calling `queue.flush()` after every write would do.
2151
+ *
2152
+ * Caveats (all inherent to removing batching):
2153
+ * - subscribers observe intermediate, un-coalesced states the batched schedulers
2154
+ * hide (e.g. a collection updated but its index not yet);
2155
+ * - a cyclic reactive graph that would loop across ticks under an async
2156
+ * scheduler recurses here and can overflow the stack.
2157
+ */
2158
+ declare class OIMEventQueueSchedulerSync extends OIMEventQueueScheduler {
2159
+ schedule(): void;
2160
+ cancel(): void;
2161
+ }
2162
+
1472
2163
  /**
1473
2164
  * Factory for creating event queue schedulers.
1474
2165
  * Provides a convenient way to create schedulers with type-safe configuration.
@@ -1491,9 +2182,14 @@ declare class OIMEventQueueSchedulerFactory {
1491
2182
  */
1492
2183
  static createTimeout(delay?: number): OIMEventQueueSchedulerTimeout;
1493
2184
  /**
1494
- * Create an immediate scheduler (fastest execution).
2185
+ * Create an immediate scheduler (setImmediate / MessageChannel / setTimeout(0)).
1495
2186
  */
1496
2187
  static createImmediate(): OIMEventQueueSchedulerImmediate;
2188
+ /**
2189
+ * Create a synchronous scheduler — flushes in the same call stack, no
2190
+ * batching. Debug/diagnostic use only (see {@link OIMEventQueueSchedulerSync}).
2191
+ */
2192
+ static createSync(): OIMEventQueueSchedulerSync;
1497
2193
  }
1498
2194
 
1499
2195
  declare enum EOIMCollectionEventType {
@@ -1750,4 +2446,20 @@ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TP
1750
2446
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1751
2447
  }
1752
2448
 
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 };
2449
+ declare class OIMEntitiesByGlobalIndexSetBasedSelector<TEntity extends object, TPk extends TOIMPk, TIndex extends OIMGlobalIndexSetBased<TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
2450
+ private readonly collection;
2451
+ private readonly reactiveIndex;
2452
+ constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveGlobalIndexSetBased<TPk, TIndex>);
2453
+ getValue(): readonly (TEntity | undefined)[];
2454
+ protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
2455
+ }
2456
+
2457
+ declare class OIMEntitiesByGlobalIndexArrayBasedSelector<TEntity extends object, TPk extends TOIMPk, TIndex extends OIMGlobalIndexArrayBased<TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
2458
+ private readonly collection;
2459
+ private readonly reactiveIndex;
2460
+ constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveGlobalIndexArrayBased<TPk, TIndex>);
2461
+ getValue(): readonly (TEntity | undefined)[];
2462
+ protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
2463
+ }
2464
+
2465
+ export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexSlotSource, type IOIMIndexStore, type IOIMKeyedUpdateEmitter, type IOIMOrderedListCommandSource, type IOIMSingleUpdateEmitter, type IOIMSubscribable, type IOIMSubscription, OIMCarrierKeyedEmitter, OIMCarrierSingleEmitter, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionGlobalIndexArrayBased, OIMDerivedCollectionGlobalIndexSetBased, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByGlobalIndexArrayBasedSelector, OIMEntitiesByGlobalIndexSetBasedSelector, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerSync, OIMEventQueueSchedulerTimeout, OIMGlobalIndex, OIMGlobalIndexArrayBased, OIMGlobalIndexManualArrayBased, OIMGlobalIndexManualSetBased, OIMGlobalIndexSetBased, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexSlotMap, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandBuffer, OIMOrderedListCommandStream, OIMOrderedListCommandStreamDiffDriven, OIMOrderedListMappedCommandStream, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionGlobalIndexManualArrayBased, OIMReactiveCollectionGlobalIndexManualSetBased, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveGlobalIndex, OIMReactiveGlobalIndexArrayBased, OIMReactiveGlobalIndexManualArrayBased, OIMReactiveGlobalIndexManualSetBased, OIMReactiveGlobalIndexSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionGlobalIndexArrayBasedOptions, type TOIMCollectionGlobalIndexSetBasedOptions, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexSetBasedOptions, type TOIMCollectionKit, type TOIMCollectionOptions, type TOIMCollectionOrderedIndexOptions, type TOIMCollectionOrderedListCommandStreamOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMDerivedCollectionGlobalIndexArrayBasedOptions, type TOIMDerivedCollectionGlobalIndexSetBasedOptions, 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 TOIMGlobalIndexFilter, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMOrderedListDiffOptions, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsDerivedArrayIndexOptions, type TOIMRelationsDerivedGlobalArrayIndexOptions, type TOIMRelationsDerivedGlobalSetIndexOptions, type TOIMRelationsDerivedSetIndexOptions, type TOIMRelationsGlobalArrayIndexOptions, type TOIMRelationsGlobalSetIndexOptions, type TOIMRelationsOrderedListOptions, type TOIMRelationsSetIndexOptions, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload, createInPlaceEntityUpdater, createMergeEntityUpdater, createOIMCollectionIndexFactory, createOIMCollectionKit, createOIMIndexSlotMap, createOIMOrderedListCommandStreamDiffDriven, createOIMOrderedListMappedCommandStream, diffOrderedListByPk };