@oimdb/core 3.5.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.cts 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
 
@@ -786,32 +909,60 @@ interface IOIMOrderedListCommandSource<TKey extends TOIMPk, TItem> {
786
909
  }
787
910
 
788
911
  /**
789
- * Slot-first ordered-list command stream.
912
+ * Abstract base for position-addressed ordered-list command streams.
790
913
  *
791
- * Emits position-addressed {@link TOIMOrderedListCommand}s whose `item` is the
792
- * entity slot. Use this when you already have slots and want incremental
793
- * commands for an imperative renderer. For PK writes bound to a collection, use
794
- * `OIMCollectionOrderedListCommandStream`.
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.
795
921
  *
796
- * Implements {@link IOIMOrderedListCommandSource} (with the slot as the element)
797
- * so it can be projected element-wise via
798
- * `createOIMOrderedListMappedCommandStream`.
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.
799
926
  */
800
- declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> implements IOIMOrderedListCommandSource<TKey, TOIMEntitySlot<TEntity, TPk>> {
927
+ declare abstract class OIMOrderedListCommandBuffer<TKey extends TOIMPk, TItem> implements IOIMOrderedListCommandSource<TKey, TItem> {
801
928
  readonly commandsEventEmitter: OIMUpdateEventEmitter<TKey>;
802
929
  private readonly unsubscribeAfterFlush;
803
- private readonly unsubscribeFromIndexEmitter;
804
- protected isInWrite: boolean;
805
- 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>> {
806
959
  /** Underlying slot-first ordered index. */
807
960
  readonly index: OIMIndexManualOrderedArrayBased<TKey, TPk>;
808
961
  constructor(queue: OIMEventQueue, index?: OIMIndexManualOrderedArrayBased<TKey, TPk>);
809
962
  getPksByKey(key: TKey): readonly TPk[];
810
963
  getSlotsByKey(key: TKey): readonly TOIMEntitySlot<TEntity, TPk>[];
811
- /** {@link IOIMOrderedListCommandSource} — alias of {@link getSlotsByKey}. */
964
+ /** {@link OIMOrderedListCommandBuffer.getItemsByKey} — the slots in order. */
812
965
  getItemsByKey(key: TKey): readonly TOIMEntitySlot<TEntity, TPk>[];
813
- /** {@link IOIMOrderedListCommandSource} — per-key command subscription. */
814
- subscribeCommands(key: TKey, handler: () => void): () => void;
815
966
  getEntitiesByKey(key: TKey): (TEntity | undefined)[];
816
967
  hasKey(key: TKey): boolean;
817
968
  getKeys(): readonly TKey[];
@@ -829,22 +980,15 @@ declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMP
829
980
  */
830
981
  moveRange(key: TKey, from: number, to: number, count: number): void;
831
982
  setSlots(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
832
- getBufferedCommands(key: TKey): readonly TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>[];
833
- consumeCommands(key: TKey): TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>[];
834
983
  clear(key?: TKey): void;
835
984
  destroy(): void;
836
- private readonly onAfterFlush;
837
- private readonly onIndexUpdate;
838
- protected withWrite(fn: () => void): void;
839
- protected appendCommand(key: TKey, cmd: TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>): void;
840
- protected appendResetCommand(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
841
- protected createResetCommand(slots: readonly TOIMEntitySlot<TEntity, TPk>[]): TOIMOrderedListCommand<TOIMEntitySlot<TEntity, TPk>>;
842
985
  }
843
986
 
844
987
  /**
845
988
  * Collection-bound ordered-list command stream.
846
989
  *
847
- * 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.
848
992
  */
849
993
  declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMOrderedListCommandStream<TKey, TPk, TEntity> {
850
994
  readonly index: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
@@ -1023,6 +1167,220 @@ declare class OIMDerivedCollectionIndexArrayBased<TKey extends TOIMPk, TPk exten
1023
1167
  private normalizeKeys;
1024
1168
  }
1025
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
+
1026
1384
  /**
1027
1385
  * Factory helper for collection-bound indexes.
1028
1386
  *
@@ -1038,6 +1396,20 @@ declare class OIMCollectionIndexFactory<TEntity extends object, TPk extends TOIM
1038
1396
  derivedSetIndex<TKey extends TOIMPk = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedSetIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexSetBased<TKey, TPk, TEntity>;
1039
1397
  arrayBasedIndex<TKey extends TOIMPk = string>(opts?: TOIMRelationsArrayIndexOptions<TKey, TPk>): OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity>;
1040
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>;
1041
1413
  orderedIndex<TKey extends TOIMPk = string>(): OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
1042
1414
  orderedList<TKey extends TOIMPk = string>(opts?: TOIMRelationsOrderedListOptions<TKey, TPk, TEntity>): OIMCollectionOrderedListCommandStream<TKey, TPk, TEntity>;
1043
1415
  }
@@ -1229,6 +1601,38 @@ declare function createInPlaceEntityUpdater<TEntity extends object>(): TOIMEntit
1229
1601
  */
1230
1602
  declare function createMergeEntityUpdater<TEntity extends object>(): TOIMEntityUpdater<TEntity>;
1231
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
+
1232
1636
  /**
1233
1637
  * Factory for creating index comparators.
1234
1638
  * Provides common comparison strategies for primary key arrays.
@@ -1352,6 +1756,10 @@ declare class OIMCollectionSelectors<TEntity extends object, TPk extends TOIMPk>
1352
1756
  byPks(pks: readonly TPk[]): TOIMCollectionEntitiesSelector<TEntity>;
1353
1757
  entitiesBySetIndexKey<TKey extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>>(index: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
1354
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>;
1355
1763
  }
1356
1764
 
1357
1765
  type TOIMReactiveCollectionFactoryOptions<TEntity extends object, TPk extends TOIMPk> = TOIMCollectionOptions<TEntity, TPk>;
@@ -1432,38 +1840,28 @@ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOI
1432
1840
  private trackPatch;
1433
1841
  }
1434
1842
 
1435
- /**
1436
- * Options for {@link OIMOrderedListMappedCommandStream} — how a source element
1437
- * (`TIn`) is projected to a downstream element (`TOut`) and torn down.
1438
- *
1439
- * `create` runs once per element when it enters the list (an `insert`, a `set`
1440
- * replacement, or list build / `reset`). `destroy` runs when it leaves (a
1441
- * `remove`, the replaced half of a `set`, every element on `reset`, and on
1442
- * stream `destroy()`). A `move` reuses the same `TOut` — it is never recreated.
1443
- */
1444
- type TOIMOrderedListMapOptions<TIn, TOut> = {
1445
- create: (item: TIn) => TOut;
1446
- destroy?: (mapped: TOut) => void;
1447
- };
1448
-
1449
1843
  /**
1450
1844
  * Projects an ordered-list command source element-wise, re-emitting the same
1451
- * position-addressed commands with `item` replaced by the mapped value.
1845
+ * position-addressed commands with `item` replaced by `create(item)`.
1452
1846
  *
1453
1847
  * It rides the source's batching: there is no queue and no independent
1454
1848
  * scheduling. On each source notification it pulls the source commands,
1455
- * translates them (running `create` / `destroy` and updating a positional
1456
- * mirror of the mapped elements), and notifies its own subscribers
1457
- * synchronously — so the source's `after_flush` semantics carry through.
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.
1458
1852
  *
1459
1853
  * Identity is positional: a `move` reorders the *same* mapped references in the
1460
1854
  * mirror, so the mapped element is preserved across moves and never recreated.
1461
- * `create` runs on `insert` / `set` / `reset` / initial build; `destroy` on
1462
- * `remove` / the replaced half of `set` / every element on `reset` / `destroy()`.
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.
1463
1861
  *
1464
1862
  * Wiring to the source for a key is lazy (on first `subscribeCommands` or
1465
1863
  * `getItemsByKey`) and lives until `destroy()`; subscriber churn does not
1466
- * create or tear down mapped elements.
1864
+ * create mapped elements.
1467
1865
  *
1468
1866
  * The output is itself an {@link IOIMOrderedListCommandSource}, so maps chain:
1469
1867
  * `source.map(...)` → `.map(...)`.
@@ -1471,19 +1869,18 @@ type TOIMOrderedListMapOptions<TIn, TOut> = {
1471
1869
  declare class OIMOrderedListMappedCommandStream<TKey extends TOIMPk, TOut, TIn> implements IOIMOrderedListCommandSource<TKey, TOut> {
1472
1870
  private readonly source;
1473
1871
  private readonly create;
1474
- private readonly destroyItem?;
1475
1872
  /** Per-key positional mirror of the mapped elements. */
1476
1873
  private readonly mirror;
1477
1874
  /** Mapped commands produced for the current delivery, per key. */
1478
1875
  private readonly buffer;
1479
1876
  private readonly subscribers;
1480
1877
  private readonly sourceUnsubscribers;
1481
- constructor(source: IOIMOrderedListCommandSource<TKey, TIn>, opts: TOIMOrderedListMapOptions<TIn, TOut>);
1878
+ constructor(source: IOIMOrderedListCommandSource<TKey, TIn>, create: (item: TIn) => TOut);
1482
1879
  subscribeCommands(key: TKey, handler: () => void): () => void;
1483
1880
  consumeCommands(key: TKey): TOIMOrderedListCommand<TOut>[];
1484
1881
  getItemsByKey(key: TKey): readonly TOut[];
1485
1882
  /** Map this source again, chaining the projection. */
1486
- map<TNext>(opts: TOIMOrderedListMapOptions<TOut, TNext>): OIMOrderedListMappedCommandStream<TKey, TNext, TOut>;
1883
+ map<TNext>(create: (item: TOut) => TNext): OIMOrderedListMappedCommandStream<TKey, TNext, TOut>;
1487
1884
  destroy(): void;
1488
1885
  /** Build the initial mirror and subscribe to the source once per key. */
1489
1886
  private ensureWired;
@@ -1495,16 +1892,179 @@ declare class OIMOrderedListMappedCommandStream<TKey extends TOIMPk, TOut, TIn>
1495
1892
  * source, so it can be mapped again (or via its `.map()` method).
1496
1893
  *
1497
1894
  * ```ts
1498
- * const nodes = createOIMOrderedListMappedCommandStream(stream, {
1499
- * create: (slot) => engine.makeNode(slot.item),
1500
- * destroy: (node) => engine.dropNode(node),
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
+ * }
1501
1902
  * });
1502
- * nodes.subscribeCommands(key, () =>
1503
- * engine.apply(nodes.consumeCommands(key))
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
1504
2064
  * );
1505
2065
  * ```
1506
2066
  */
1507
- declare function createOIMOrderedListMappedCommandStream<TKey extends TOIMPk, TIn, TOut>(source: IOIMOrderedListCommandSource<TKey, TIn>, opts: TOIMOrderedListMapOptions<TIn, TOut>): OIMOrderedListMappedCommandStream<TKey, TOut, TIn>;
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>;
1508
2068
 
1509
2069
  /**
1510
2070
  * Animation frame-based scheduler that executes flushes synchronized with the browser's repaint cycle.
@@ -1522,7 +2082,7 @@ declare class OIMEventQueueSchedulerAnimationFrame extends OIMEventQueueSchedule
1522
2082
  /**
1523
2083
  * Available scheduler types for event queue configuration.
1524
2084
  */
1525
- type TOIMSchedulerType = 'microtask' | 'animationFrame' | 'timeout' | 'immediate';
2085
+ type TOIMSchedulerType = 'microtask' | 'animationFrame' | 'timeout' | 'immediate' | 'sync';
1526
2086
 
1527
2087
  /**
1528
2088
  * Configuration options for different scheduler types. */
@@ -1533,6 +2093,7 @@ type TOIMSchedulerOptions = {
1533
2093
  delay?: number;
1534
2094
  };
1535
2095
  immediate: never;
2096
+ sync: never;
1536
2097
  };
1537
2098
 
1538
2099
  /**
@@ -1577,6 +2138,28 @@ declare class OIMEventQueueSchedulerImmediate extends OIMEventQueueScheduler {
1577
2138
  cancel(): void;
1578
2139
  }
1579
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
+
1580
2163
  /**
1581
2164
  * Factory for creating event queue schedulers.
1582
2165
  * Provides a convenient way to create schedulers with type-safe configuration.
@@ -1599,9 +2182,14 @@ declare class OIMEventQueueSchedulerFactory {
1599
2182
  */
1600
2183
  static createTimeout(delay?: number): OIMEventQueueSchedulerTimeout;
1601
2184
  /**
1602
- * Create an immediate scheduler (fastest execution).
2185
+ * Create an immediate scheduler (setImmediate / MessageChannel / setTimeout(0)).
1603
2186
  */
1604
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;
1605
2193
  }
1606
2194
 
1607
2195
  declare enum EOIMCollectionEventType {
@@ -1858,4 +2446,20 @@ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TP
1858
2446
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1859
2447
  }
1860
2448
 
1861
- export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexStore, type IOIMKeyedUpdateEmitter, type IOIMOrderedListCommandSource, 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, OIMOrderedListMappedCommandStream, 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 TOIMOrderedListMapOptions, 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, createOIMOrderedListMappedCommandStream };
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 };