@oimdb/core 3.7.0 → 3.8.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
@@ -1,6 +1,33 @@
1
1
  type TOIMPk = string | number;
2
2
 
3
- type TOIMEntitySlot<TEntity extends object, TPk extends TOIMPk> = {
3
+ /**
4
+ * A composite index key: an ordered, arbitrary-length tuple of primitive
5
+ * segments. Unlike a stringified `"a|b|c"` key it keeps each segment's own
6
+ * type and identity (so `1` and `"1"` stay distinct and no separator can
7
+ * collide), and unlike a native object/array Map key it is matched by content,
8
+ * not reference — a freshly built `[a, b, c]` resolves to the same bucket as a
9
+ * previously stored `[a, b, c]`.
10
+ *
11
+ * Backed at runtime by a trie (`OIMTrieMap`): lookup walks one native-Map level
12
+ * per segment, so it is O(arity) — effectively O(1) for a fixed arity — and
13
+ * never allocates or hashes a string key.
14
+ */
15
+ type TOIMKeyPath = readonly TOIMPk[];
16
+
17
+ /**
18
+ * The key bound shared by every keyed node (index, keyed emitter, carrier
19
+ * resolver): either a single primitive PK (`TOIMPk`) or a composite key path
20
+ * (`TOIMKeyPath`).
21
+ *
22
+ * It exists purely to widen the generic bound from `TOIMPk` to also admit
23
+ * `TOIMKeyPath`, so the composite (trie-backed) index can reuse the exact same
24
+ * emitter / reactive-index machinery. It is a compile-time bound only — nothing
25
+ * branches on it at runtime, and primitive-keyed nodes keep their native-Map
26
+ * fast path untouched.
27
+ */
28
+ type TOIMKey = TOIMPk | TOIMKeyPath;
29
+
30
+ type TOIMEntitySlot<TEntity extends object, TPk extends TOIMKey> = {
4
31
  pk: TPk;
5
32
  item: TEntity | undefined;
6
33
  /**
@@ -11,10 +38,73 @@ type TOIMEntitySlot<TEntity extends object, TPk extends TOIMPk> = {
11
38
  */
12
39
  subscribers?: Set<() => void>;
13
40
  };
14
- type TOIMAnyEntitySlot<TPk extends TOIMPk> = TOIMEntitySlot<object, TPk>;
15
- type TOIMEntitySlotResolver<TPk extends TOIMPk> = (pk: TPk) => TOIMAnyEntitySlot<TPk> | undefined;
41
+ type TOIMAnyEntitySlot<TPk extends TOIMKey> = TOIMEntitySlot<object, TPk>;
42
+ type TOIMEntitySlotResolver<TPk extends TOIMKey> = (pk: TPk) => TOIMAnyEntitySlot<TPk> | undefined;
43
+
44
+ /**
45
+ * The Map surface the PK / index-key axis needs, abstracted so the concrete
46
+ * keying strategy is pluggable. A native `Map` satisfies this interface
47
+ * structurally (so the primitive default is a plain `Map`, zero wrapper), while
48
+ * a composite key uses a trie-backed implementation (`OIMTrieMap`) that matches
49
+ * array keys by content instead of by reference.
50
+ */
51
+ interface IOIMKeyedMap<TKey, TValue> {
52
+ get(key: TKey): TValue | undefined;
53
+ set(key: TKey, value: TValue): void;
54
+ has(key: TKey): boolean;
55
+ delete(key: TKey): boolean;
56
+ readonly size: number;
57
+ keys(): IterableIterator<TKey>;
58
+ entries(): IterableIterator<[TKey, TValue]>;
59
+ values(): IterableIterator<TValue>;
60
+ clear(): void;
61
+ }
62
+
63
+ /**
64
+ * The Set surface the PK / index-key axis needs, abstracted so the concrete
65
+ * keying strategy is pluggable. A native `Set` satisfies this interface
66
+ * structurally (primitive default is a plain `Set`, zero wrapper); a composite
67
+ * key uses a trie-backed implementation matching array keys by content.
68
+ */
69
+ interface IOIMKeyedSet<TKey> {
70
+ add(key: TKey): void;
71
+ has(key: TKey): boolean;
72
+ delete(key: TKey): boolean;
73
+ readonly size: number;
74
+ values(): IterableIterator<TKey>;
75
+ clear(): void;
76
+ }
77
+
78
+ /**
79
+ * Owns "how a key is stored, compared, and identified" for one keying axis
80
+ * (a collection's PK, or an index's key). It is the single seam every PK-keyed
81
+ * `Map`/`Set` on the hot path goes through, so the whole engine is agnostic to
82
+ * whether the key is a primitive or a composite path.
83
+ *
84
+ * - `OIMKeyDomainNative` (default): native `Map`/`Set`, `canonicalize` is
85
+ * identity — byte-for-byte the current behavior and cost for primitive keys.
86
+ * - `OIMKeyDomainTrie`: trie-backed `Map`/`Set` matching array keys by content,
87
+ * and `canonicalize` interns each logical key to one stable reference so that
88
+ * downstream native `Set<slot.pk>` keep working by reference.
89
+ */
90
+ interface IOIMKeyDomain<TKey extends TOIMKey> {
91
+ createMap<TValue>(): IOIMKeyedMap<TKey, TValue>;
92
+ createSet(): IOIMKeyedSet<TKey>;
93
+ /**
94
+ * Returns the canonical reference for a logical key. Native domain returns
95
+ * the key unchanged; a composite domain interns it so equal-content keys
96
+ * share one reference (making reference-keyed structures downstream correct).
97
+ */
98
+ canonicalize(key: TKey): TKey;
99
+ }
16
100
 
17
- declare abstract class OIMCollectionStore<TEntity extends object, TPk extends TOIMPk> {
101
+ declare abstract class OIMCollectionStore<TEntity extends object, TPk extends TOIMKey> {
102
+ /**
103
+ * The keying strategy for this store's PKs. Every PK-keyed structure built
104
+ * off a collection (indexes, wrappers) reads it so the whole engine keys PKs
105
+ * the same way — native `Map` for primitives, trie for composite paths.
106
+ */
107
+ abstract get keyDomain(): IOIMKeyDomain<TPk>;
18
108
  abstract setOneByPk(pk: TPk, entity: TEntity): TOIMEntitySlot<TEntity, TPk>;
19
109
  abstract getSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk> | undefined;
20
110
  /**
@@ -70,7 +160,7 @@ interface TOIMIndexUpdatePayload<TKey> {
70
160
  /**
71
161
  * Comparator function for index primary key arrays.
72
162
  * Returns true if the arrays are considered equal, false if they differ. */
73
- type TOIMIndexComparator<TPk extends TOIMPk> = (existingPks: readonly TPk[], newPks: readonly TPk[]) => boolean;
163
+ type TOIMIndexComparator<TPk extends TOIMKey> = (existingPks: readonly TPk[], newPks: readonly TPk[]) => boolean;
74
164
 
75
165
  interface IOIMIndexStore<TKey, TBucket> {
76
166
  setOneByKey(key: TKey, bucket: TBucket): void;
@@ -83,7 +173,7 @@ interface IOIMIndexStore<TKey, TBucket> {
83
173
  countAll(): number;
84
174
  clear(): void;
85
175
  }
86
- declare abstract class OIMIndex<TKey extends TOIMPk, TPk extends TOIMPk, TBucket extends Iterable<TOIMAnyEntitySlot<TPk>>> {
176
+ declare abstract class OIMIndex<TKey extends TOIMKey, TPk extends TOIMKey, TBucket extends Iterable<TOIMAnyEntitySlot<TPk>>> {
87
177
  protected readonly comparePks?: TOIMIndexComparator<TPk>;
88
178
  protected readonly store: IOIMIndexStore<TKey, TBucket>;
89
179
  readonly emitter: OIMEventEmitter<{
@@ -119,28 +209,112 @@ declare abstract class OIMIndex<TKey extends TOIMPk, TPk extends TOIMPk, TBucket
119
209
  protected slotsToEntities<TEntity extends object>(slots: Iterable<TOIMAnyEntitySlot<TPk>>): (TEntity | undefined)[];
120
210
  }
121
211
 
122
- declare abstract class OIMIndexStoreSetBased<TKey extends TOIMPk, TPk extends TOIMPk> {
212
+ /**
213
+ * A carrier that can hold per-key subscribers directly on itself, so the keyed
214
+ * emitter delivers without a per-key map lookup. Implemented by the entity slot
215
+ * (collection carrier) and the index bucket (index carrier).
216
+ */
217
+ interface IOIMSubscribable {
218
+ subscribers?: Set<() => void>;
219
+ /**
220
+ * Dirty-batch membership flag, owned by the keyed emitter. `true` while the
221
+ * carrier sits in the pending flush batch — lets the emitter dedup marks with
222
+ * an O(1) boolean check instead of a `Set` identity-hash lookup. Reset to
223
+ * `false` as the carrier is delivered (or on flush teardown). Do not read or
224
+ * write outside the emitter.
225
+ */
226
+ dirty?: boolean;
227
+ }
228
+
229
+ /**
230
+ * A set-based index bucket that is ALSO its own subscription carrier AND holds
231
+ * its own pk→slot membership.
232
+ *
233
+ * It extends `Set<slot>`, so every reader that treats a bucket as a `Set`
234
+ * (iteration, `size`, `has`, `add`, `delete`) is unchanged — a `Set` subclass is
235
+ * a `Set`. On top of that:
236
+ * - it carries `subscribers` + `dirty` (`IOIMSubscribable`) and its own `key`,
237
+ * so the keyed emitter delivers straight off the bucket the writer already
238
+ * holds — O(1), no key→carrier map/trie (bucket-as-carrier);
239
+ * - it carries an optional `membership` (pk → slot) so pk-oriented writes
240
+ * (`setPks`/`addPks`/`removePks`) dedup and remove by pk WITHOUT a second
241
+ * key-indexed structure. One `getOrReserveBucket` walk now serves both the
242
+ * slots and the membership — halving the trie walks for a composite key.
243
+ */
244
+ declare class OIMKeyedBucketSetBased<TKey extends TOIMKey, TPk extends TOIMKey> extends Set<TOIMAnyEntitySlot<TPk>> implements IOIMSubscribable {
245
+ readonly key: TKey;
246
+ subscribers?: Set<() => void>;
247
+ dirty?: boolean;
248
+ membership?: IOIMKeyedMap<TPk, TOIMAnyEntitySlot<TPk>>;
249
+ constructor(key: TKey);
250
+ hasSubscribers(): boolean;
251
+ /** Clearing the slot set also clears the pk membership — they stay in sync. */
252
+ clear(): void;
253
+ }
254
+
255
+ declare abstract class OIMIndexStoreSetBased<TKey extends TOIMKey, TPk extends TOIMKey> {
123
256
  abstract setOneByKey(key: TKey, slots: Set<TOIMAnyEntitySlot<TPk>>): void;
124
257
  abstract removeOneByKey(key: TKey): void;
125
258
  abstract removeManyByKeys(keys: readonly TKey[]): void;
259
+ /** The live bucket for `key` (undefined if none / empty-reserved). */
126
260
  abstract getOneByKey(key: TKey): Set<TOIMAnyEntitySlot<TPk>> | undefined;
127
261
  abstract getManyByKeys(keys: readonly TKey[]): Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
128
262
  abstract getAllKeys(): TKey[];
129
263
  abstract getAll(): Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
130
264
  abstract countAll(): number;
131
265
  abstract clear(): void;
266
+ /** Bucket for `key` (live or reserved), creating a reserved empty one if none. */
267
+ abstract getOrReserveBucket(key: TKey): OIMKeyedBucketSetBased<TKey, TPk>;
268
+ /** Existing bucket (live or reserved) without creating one — for delivery. */
269
+ abstract findBucket(key: TKey): OIMKeyedBucketSetBased<TKey, TPk> | undefined;
270
+ /** Promote a now-non-empty bucket into the live set. */
271
+ abstract retainBucket(bucket: OIMKeyedBucketSetBased<TKey, TPk>): void;
272
+ /** A now-empty bucket: keep it (reserved) if subscribed, else drop it. */
273
+ abstract releaseBucket(bucket: OIMKeyedBucketSetBased<TKey, TPk>): void;
274
+ /** Last subscriber left: drop the key's bucket if it is empty & unsubscribed. */
275
+ abstract dropIfReserved(key: TKey): void;
276
+ }
277
+
278
+ /**
279
+ * An array-based (ordered) index bucket that is ALSO its own subscription
280
+ * carrier — the array counterpart of `OIMKeyedBucketSetBased`.
281
+ *
282
+ * It extends `Array<slot>`, so every reader that treats a bucket as an ordered
283
+ * slot array (iteration, `length`, index access, `push`, `filter`) is unchanged.
284
+ * On top of that it carries `subscribers` + `dirty` (`IOIMSubscribable`) and its
285
+ * own `key`, so the keyed emitter delivers straight off the bucket the writer
286
+ * already holds (O(1), no key→carrier lookup).
287
+ *
288
+ * `Symbol.species` is `Array`, so derived arrays (`filter`/`slice`/`map`) are
289
+ * plain arrays — never stray carrier buckets.
290
+ */
291
+ declare class OIMKeyedBucketArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> extends Array<TOIMAnyEntitySlot<TPk>> implements IOIMSubscribable {
292
+ readonly key: TKey;
293
+ subscribers?: Set<() => void>;
294
+ dirty?: boolean;
295
+ static get [Symbol.species](): ArrayConstructor;
296
+ constructor(key: TKey);
297
+ hasSubscribers(): boolean;
298
+ /** Empty the bucket in place (Array has no `clear`). */
299
+ clear(): void;
132
300
  }
133
301
 
134
- declare abstract class OIMIndexStoreArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> {
302
+ declare abstract class OIMIndexStoreArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> {
135
303
  abstract setOneByKey(key: TKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
136
304
  abstract removeOneByKey(key: TKey): void;
137
305
  abstract removeManyByKeys(keys: readonly TKey[]): void;
306
+ /** The live bucket for `key` (undefined if none / empty-reserved). */
138
307
  abstract getOneByKey(key: TKey): TOIMAnyEntitySlot<TPk>[] | undefined;
139
308
  abstract getManyByKeys(keys: readonly TKey[]): Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
140
309
  abstract getAllKeys(): TKey[];
141
310
  abstract getAll(): Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
142
311
  abstract countAll(): number;
143
312
  abstract clear(): void;
313
+ abstract getOrReserveBucket(key: TKey): OIMKeyedBucketArrayBased<TKey, TPk>;
314
+ abstract findBucket(key: TKey): OIMKeyedBucketArrayBased<TKey, TPk> | undefined;
315
+ abstract retainBucket(bucket: OIMKeyedBucketArrayBased<TKey, TPk>): void;
316
+ abstract releaseBucket(bucket: OIMKeyedBucketArrayBased<TKey, TPk>): void;
317
+ abstract dropIfReserved(key: TKey): void;
144
318
  }
145
319
 
146
320
  declare enum EOIMEventQueueSchedulerEventType {
@@ -169,7 +343,12 @@ declare abstract class OIMEventQueueScheduler {
169
343
  protected flush(): void;
170
344
  }
171
345
 
172
- declare abstract class OIMIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndex<TKey, TPk, Set<TOIMAnyEntitySlot<TPk>>> {
346
+ declare abstract class OIMIndexSetBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndex<TKey, TPk, Set<TOIMAnyEntitySlot<TPk>>> {
347
+ /**
348
+ * The same store as the base `store`, narrowed to the set-based contract so
349
+ * the carrier-bucket lifecycle methods (`getOrReserveBucket`, …) are visible.
350
+ */
351
+ protected readonly setStore: OIMIndexStoreSetBased<TKey, TPk>;
173
352
  constructor(options?: {
174
353
  comparePks?: TOIMIndexComparator<TPk>;
175
354
  store?: OIMIndexStoreSetBased<TKey, TPk>;
@@ -180,10 +359,16 @@ declare abstract class OIMIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk>
180
359
  getSlotsByKey(key: TKey): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
181
360
  getSlotsByKeys(keys: readonly TKey[]): Map<TKey, ReadonlySet<TOIMAnyEntitySlot<TPk>>>;
182
361
  protected slotsToPks(slots: Iterable<TOIMAnyEntitySlot<TPk>>): Set<TPk>;
183
- protected setSlotsWithComparison(key: TKey, newSlots: Set<TOIMAnyEntitySlot<TPk>>): boolean;
362
+ /**
363
+ * True if a comparator is set and considers `bucket`'s current pks equal to
364
+ * `newSlots` — i.e. a `setSlots` would be a no-op and should not emit.
365
+ */
366
+ protected bucketMatchesComparator(bucket: ReadonlySet<TOIMAnyEntitySlot<TPk>>, newSlots: ReadonlySet<TOIMAnyEntitySlot<TPk>>): boolean;
184
367
  }
185
368
 
186
- declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndex<TKey, TPk, TOIMAnyEntitySlot<TPk>[]> {
369
+ declare abstract class OIMIndexArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndex<TKey, TPk, TOIMAnyEntitySlot<TPk>[]> {
370
+ /** The same store as `store`, narrowed to expose the carrier-bucket lifecycle. */
371
+ protected readonly arrayStore: OIMIndexStoreArrayBased<TKey, TPk>;
187
372
  constructor(options?: {
188
373
  comparePks?: TOIMIndexComparator<TPk>;
189
374
  store?: OIMIndexStoreArrayBased<TKey, TPk>;
@@ -194,7 +379,11 @@ declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMP
194
379
  getSlotsByKey(key: TKey): readonly TOIMAnyEntitySlot<TPk>[];
195
380
  getSlotsByKeys(keys: readonly TKey[]): Map<TKey, readonly TOIMAnyEntitySlot<TPk>[]>;
196
381
  protected slotsToPks(slots: readonly TOIMAnyEntitySlot<TPk>[]): TPk[];
197
- protected setSlotsWithComparison(key: TKey, newSlots: TOIMAnyEntitySlot<TPk>[]): boolean;
382
+ /**
383
+ * True if a comparator is set and considers `bucket`'s pks equal to
384
+ * `newSlots` — i.e. a `setSlots` would be a no-op and should not emit.
385
+ */
386
+ protected bucketMatchesComparator(bucket: readonly TOIMAnyEntitySlot<TPk>[], newSlots: readonly TOIMAnyEntitySlot<TPk>[]): boolean;
198
387
  }
199
388
 
200
389
  /**
@@ -206,13 +395,18 @@ declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMP
206
395
  * against this interface lets either back the node without leaking the carrier
207
396
  * generic into the node's signatures.
208
397
  */
209
- interface IOIMKeyedUpdateEmitter<TKey extends TOIMPk> {
398
+ interface IOIMKeyedUpdateEmitter<TKey extends TOIMKey> {
210
399
  subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
211
400
  subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
212
401
  unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
213
402
  unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
214
403
  markUpdatedKey(key: TKey): void;
215
404
  markUpdatedKeys(keys: readonly TKey[]): void;
405
+ /**
406
+ * Fast path: mark a carrier the writer already holds (an entity slot or an
407
+ * index bucket), skipping the key→carrier lookup entirely. O(1).
408
+ */
409
+ markUpdatedCarrier(carrier: IOIMSubscribable): void;
216
410
  hasSubscriptions(): boolean;
217
411
  getHandlerCount(key: TKey): number;
218
412
  getMetrics(): {
@@ -289,15 +483,97 @@ declare class OIMEventQueue {
289
483
  destroy(): void;
290
484
  }
291
485
 
292
- interface IOIMKeyedSubscription<TKey extends TOIMPk> {
486
+ /**
487
+ * Resolves a key to its carrier — the object that holds the key's subscribers.
488
+ * `getOrReserveCarrier` is used on subscribe (creates the carrier if absent so a
489
+ * subscription can exist before its data); `findCarrier` resolves an existing
490
+ * carrier for delivery/unsubscribe without creating one.
491
+ *
492
+ * Collection carrier = the entity slot (by pk); index carrier = the bucket
493
+ * (by index key).
494
+ */
495
+ interface IOIMCarrierResolver<TKey extends TOIMKey, TCarrier> {
496
+ getOrReserveCarrier(key: TKey): TCarrier;
497
+ findCarrier(key: TKey): TCarrier | undefined;
498
+ /**
499
+ * Optional: called when a carrier loses its last subscriber, so a resolver
500
+ * that owns standalone carriers (e.g. the index's key→carrier map) can prune
501
+ * it and not leak the key space. Resolvers whose carriers are owned
502
+ * elsewhere (e.g. the collection's slots) leave this unset.
503
+ */
504
+ onCarrierEmptied?(carrier: TCarrier): void;
505
+ }
506
+ /**
507
+ * Keyed (per-key) pub/sub that stores handlers ON the carrier object
508
+ * (`carrier.subscribers`) instead of a `Map<key, handlers>`. The hot path —
509
+ * marking a written carrier dirty and delivering — needs no per-key map lookup
510
+ * or hashing: the writer already holds the carrier.
511
+ *
512
+ * Same public surface as `OIMUpdateEventEmitter` (queue delivery) plus a fast
513
+ * `markUpdatedCarrier(carrier)`, so it is a drop-in for the collection's and
514
+ * index's keyed emitter. Reused with carrier = slot (collection) or carrier =
515
+ * bucket (index).
516
+ */
517
+ declare class OIMCarrierKeyedEmitter<TKey extends TOIMKey, TCarrier extends IOIMSubscribable> implements IOIMKeyedUpdateEmitter<TKey> {
518
+ private readonly queue;
519
+ private readonly resolver;
520
+ private readonly subscribedCarriers;
521
+ private dirtyCarriers;
522
+ private isFlushEnqueued;
523
+ constructor(queue: OIMEventQueue, resolver: IOIMCarrierResolver<TKey, TCarrier>);
524
+ subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
525
+ subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
526
+ unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
527
+ unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
528
+ private addHandler;
529
+ private removeHandler;
530
+ /** Fast path: the writer already holds the carrier. */
531
+ markUpdatedCarrier(carrier: TCarrier): void;
532
+ markUpdatedKey(key: TKey): void;
533
+ markUpdatedKeys(keys: readonly TKey[]): void;
534
+ markAllUpdated(): void;
535
+ hasSubscriptions(): boolean;
536
+ getHandlerCount(key: TKey): number;
537
+ getMetrics(): {
538
+ totalKeys: number;
539
+ totalHandlers: number;
540
+ averageHandlersPerKey: number;
541
+ queueLength: number;
542
+ };
543
+ destroy(): void;
544
+ private assertNotInFlush;
545
+ private scheduleFlush;
546
+ private readonly onFlush;
547
+ private notify;
548
+ }
549
+
550
+ /**
551
+ * Carrier for a single index key: holds that key's subscribers + dirty flag
552
+ * (via `IOIMSubscribable`) so the keyed emitter delivers straight off the
553
+ * carrier with no per-key map lookup. Carries its own `key` so the resolver can
554
+ * prune it from the key→carrier map when its last subscriber leaves.
555
+ */
556
+ interface IOIMKeyCarrier<TKey extends TOIMKey> extends IOIMSubscribable {
557
+ key: TKey;
558
+ }
559
+
560
+ interface IOIMKeyedSubscription<TKey extends TOIMKey> {
293
561
  subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
294
562
  subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
295
563
  }
296
564
 
297
- declare abstract class OIMReactiveIndex<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndex<TKey, TPk, Iterable<TOIMAnyEntitySlot<TPk>>>> implements IOIMKeyedSubscription<TKey> {
565
+ declare abstract class OIMReactiveIndex<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndex<TKey, TPk, Iterable<TOIMAnyEntitySlot<TPk>>>> implements IOIMKeyedSubscription<TKey> {
298
566
  readonly index: TIndex;
299
567
  protected readonly updateEmitter: IOIMKeyedUpdateEmitter<TKey>;
300
- constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex);
568
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex,
569
+ /**
570
+ * How to build the key→carrier resolver backing the keyed emitter.
571
+ * Defaults to the native-`Map` resolver used by every primitive-keyed
572
+ * index (its fast path is unchanged). A composite (trie-backed) index
573
+ * passes a resolver that keys carriers by key path instead. Called once
574
+ * at construction — no per-operation cost.
575
+ */
576
+ createResolver?: () => IOIMCarrierResolver<TKey, IOIMKeyCarrier<TKey>>);
301
577
  getEntitiesByKey<TEntity extends object = object>(key: TKey): (TEntity | undefined)[];
302
578
  getEntitiesByKeys<TEntity extends object = object>(keys: readonly TKey[]): Map<TKey, (TEntity | undefined)[]>;
303
579
  hasKey(key: TKey): boolean;
@@ -327,16 +603,16 @@ declare abstract class OIMReactiveIndex<TKey extends TOIMPk, TPk extends TOIMPk,
327
603
  destroy(): void;
328
604
  }
329
605
 
330
- declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
331
- constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex);
606
+ declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
607
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex, createResolver?: () => IOIMCarrierResolver<TKey, IOIMKeyCarrier<TKey>>);
332
608
  getPksByKey(key: TKey): Set<TPk>;
333
609
  getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
334
610
  getSlotsByKey(key: TKey): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
335
611
  getSlotsByKeys(keys: readonly TKey[]): Map<TKey, ReadonlySet<TOIMAnyEntitySlot<TPk>>>;
336
612
  }
337
613
 
338
- declare abstract class OIMReactiveIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
339
- constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex);
614
+ declare abstract class OIMReactiveIndexArrayBased<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
615
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex, createResolver?: () => IOIMCarrierResolver<TKey, IOIMKeyCarrier<TKey>>);
340
616
  getPksByKey(key: TKey): TPk[];
341
617
  getPksByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
342
618
  getSlotsByKey(key: TKey): readonly TOIMAnyEntitySlot<TPk>[];
@@ -364,7 +640,7 @@ declare abstract class OIMObjectStore<TKey extends string | number | symbol, TVa
364
640
  * anywhere on its surface. Concrete shape (ordered array vs unordered set) is
365
641
  * added by {@link OIMGlobalIndexArrayBased} / {@link OIMGlobalIndexSetBased}.
366
642
  */
367
- declare abstract class OIMGlobalIndex<TPk extends TOIMPk> {
643
+ declare abstract class OIMGlobalIndex<TPk extends TOIMKey> {
368
644
  protected readonly comparePks?: TOIMIndexComparator<TPk>;
369
645
  readonly emitter: OIMEventEmitter<{
370
646
  0: void;
@@ -392,7 +668,7 @@ declare abstract class OIMGlobalIndex<TPk extends TOIMPk> {
392
668
  * bucket over the whole collection. Mirrors {@link OIMIndexSetBased} minus the
393
669
  * key.
394
670
  */
395
- declare abstract class OIMGlobalIndexSetBased<TPk extends TOIMPk> extends OIMGlobalIndex<TPk> {
671
+ declare abstract class OIMGlobalIndexSetBased<TPk extends TOIMKey> extends OIMGlobalIndex<TPk> {
396
672
  protected slots: Set<TOIMAnyEntitySlot<TPk>>;
397
673
  constructor(options?: {
398
674
  comparePks?: TOIMIndexComparator<TPk>;
@@ -410,7 +686,7 @@ declare abstract class OIMGlobalIndexSetBased<TPk extends TOIMPk> extends OIMGlo
410
686
  * Array-based (ordered) keyless index. Holds a single `slot[]` bucket over the
411
687
  * whole collection. Mirrors {@link OIMIndexArrayBased} minus the key.
412
688
  */
413
- declare abstract class OIMGlobalIndexArrayBased<TPk extends TOIMPk> extends OIMGlobalIndex<TPk> {
689
+ declare abstract class OIMGlobalIndexArrayBased<TPk extends TOIMKey> extends OIMGlobalIndex<TPk> {
414
690
  protected slots: TOIMAnyEntitySlot<TPk>[];
415
691
  constructor(options?: {
416
692
  comparePks?: TOIMIndexComparator<TPk>;
@@ -451,7 +727,7 @@ interface IOIMSingleUpdateEmitter extends IOIMSubscription {
451
727
  * and directly satisfies `IOIMSelectorSourceDependency`. Mirrors
452
728
  * {@link OIMReactiveIndex} minus the key.
453
729
  */
454
- declare abstract class OIMReactiveGlobalIndex<TPk extends TOIMPk, TIndex extends OIMGlobalIndex<TPk>> implements IOIMSubscription {
730
+ declare abstract class OIMReactiveGlobalIndex<TPk extends TOIMKey, TIndex extends OIMGlobalIndex<TPk>> implements IOIMSubscription {
455
731
  readonly index: TIndex;
456
732
  protected readonly updateEmitter: IOIMSingleUpdateEmitter;
457
733
  constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMSingleUpdateEmitter) => TIndex);
@@ -466,40 +742,47 @@ declare abstract class OIMReactiveGlobalIndex<TPk extends TOIMPk, TIndex extends
466
742
  destroy(): void;
467
743
  }
468
744
 
469
- declare abstract class OIMReactiveGlobalIndexSetBased<TPk extends TOIMPk, TIndex extends OIMGlobalIndexSetBased<TPk>> extends OIMReactiveGlobalIndex<TPk, TIndex> {
745
+ declare abstract class OIMReactiveGlobalIndexSetBased<TPk extends TOIMKey, TIndex extends OIMGlobalIndexSetBased<TPk>> extends OIMReactiveGlobalIndex<TPk, TIndex> {
470
746
  constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMSingleUpdateEmitter) => TIndex);
471
747
  getPks(): Set<TPk>;
472
748
  getSlots(): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
473
749
  }
474
750
 
475
- declare abstract class OIMReactiveGlobalIndexArrayBased<TPk extends TOIMPk, TIndex extends OIMGlobalIndexArrayBased<TPk>> extends OIMReactiveGlobalIndex<TPk, TIndex> {
751
+ declare abstract class OIMReactiveGlobalIndexArrayBased<TPk extends TOIMKey, TIndex extends OIMGlobalIndexArrayBased<TPk>> extends OIMReactiveGlobalIndex<TPk, TIndex> {
476
752
  constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMSingleUpdateEmitter) => TIndex);
477
753
  getPks(): TPk[];
478
754
  getSlots(): readonly TOIMAnyEntitySlot<TPk>[];
479
755
  }
480
756
 
481
- type TOIMPkSelector<TEntity extends object, TPk extends TOIMPk> = (entity: TEntity) => TPk;
757
+ type TOIMPkSelector<TEntity extends object, TPk extends TOIMKey> = (entity: TEntity) => TPk;
482
758
 
483
759
  type TOIMEntityUpdater<TEntity extends object> = (draft: Partial<TEntity>, prevEntity: TEntity) => TEntity;
484
760
 
485
- type TOIMCollectionOptions<TEntity extends object, TPk extends TOIMPk> = {
761
+ type TOIMCollectionOptions<TEntity extends object, TPk extends TOIMKey> = {
486
762
  selectPk?: TOIMPkSelector<TEntity, TPk>;
763
+ /**
764
+ * Backing store. Defaults to `OIMCollectionStoreMapDriven` (native-`Map`,
765
+ * primitive PKs). For a composite PK path, pass
766
+ * `new OIMCollectionStoreTrieDriven()`.
767
+ */
487
768
  store?: OIMCollectionStore<TEntity, TPk>;
488
769
  updateEntity?: TOIMEntityUpdater<TEntity>;
489
770
  };
490
771
 
491
- type TOIMCollectionUpdatePayload<TPk extends TOIMPk> = {
772
+ type TOIMCollectionUpdatePayload<TPk extends TOIMKey> = {
492
773
  pks: readonly TPk[];
493
774
  };
494
775
 
495
776
  /** It's like a store - but with event emitter */
496
- declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
777
+ declare class OIMCollection<TEntity extends object, TPk extends TOIMKey> {
497
778
  readonly emitter: OIMEventEmitter<{
498
779
  0: TOIMCollectionUpdatePayload<TPk>;
499
780
  }>;
500
781
  readonly selectPk: TOIMPkSelector<TEntity, TPk>;
501
782
  protected readonly store: OIMCollectionStore<TEntity, TPk>;
502
783
  protected readonly updateEntity: TOIMEntityUpdater<TEntity>;
784
+ /** The collection's PK keying strategy — read by indexes and wrappers. */
785
+ get keyDomain(): IOIMKeyDomain<TPk>;
503
786
  constructor(opts?: TOIMCollectionOptions<TEntity, TPk>);
504
787
  getOneByPk(pk: TPk): TEntity | undefined;
505
788
  getManyByPks(pks: readonly TPk[]): TEntity[];
@@ -523,92 +806,11 @@ declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
523
806
  destroy(): void;
524
807
  }
525
808
 
526
- /**
527
- * A carrier that can hold per-key subscribers directly on itself, so the keyed
528
- * emitter delivers without a per-key map lookup. Implemented by the entity slot
529
- * (collection carrier) and the index bucket (index carrier).
530
- */
531
- interface IOIMSubscribable {
532
- subscribers?: Set<() => void>;
533
- /**
534
- * Dirty-batch membership flag, owned by the keyed emitter. `true` while the
535
- * carrier sits in the pending flush batch — lets the emitter dedup marks with
536
- * an O(1) boolean check instead of a `Set` identity-hash lookup. Reset to
537
- * `false` as the carrier is delivered (or on flush teardown). Do not read or
538
- * write outside the emitter.
539
- */
540
- dirty?: boolean;
541
- }
542
-
543
- /**
544
- * Resolves a key to its carrier — the object that holds the key's subscribers.
545
- * `getOrReserveCarrier` is used on subscribe (creates the carrier if absent so a
546
- * subscription can exist before its data); `findCarrier` resolves an existing
547
- * carrier for delivery/unsubscribe without creating one.
548
- *
549
- * Collection carrier = the entity slot (by pk); index carrier = the bucket
550
- * (by index key).
551
- */
552
- interface IOIMCarrierResolver<TKey extends TOIMPk, TCarrier> {
553
- getOrReserveCarrier(key: TKey): TCarrier;
554
- findCarrier(key: TKey): TCarrier | undefined;
555
- /**
556
- * Optional: called when a carrier loses its last subscriber, so a resolver
557
- * that owns standalone carriers (e.g. the index's key→carrier map) can prune
558
- * it and not leak the key space. Resolvers whose carriers are owned
559
- * elsewhere (e.g. the collection's slots) leave this unset.
560
- */
561
- onCarrierEmptied?(carrier: TCarrier): void;
562
- }
563
- /**
564
- * Keyed (per-key) pub/sub that stores handlers ON the carrier object
565
- * (`carrier.subscribers`) instead of a `Map<key, handlers>`. The hot path —
566
- * marking a written carrier dirty and delivering — needs no per-key map lookup
567
- * or hashing: the writer already holds the carrier.
568
- *
569
- * Same public surface as `OIMUpdateEventEmitter` (queue delivery) plus a fast
570
- * `markUpdatedCarrier(carrier)`, so it is a drop-in for the collection's and
571
- * index's keyed emitter. Reused with carrier = slot (collection) or carrier =
572
- * bucket (index).
573
- */
574
- declare class OIMCarrierKeyedEmitter<TKey extends TOIMPk, TCarrier extends IOIMSubscribable> implements IOIMKeyedUpdateEmitter<TKey> {
575
- private readonly queue;
576
- private readonly resolver;
577
- private readonly subscribedCarriers;
578
- private dirtyCarriers;
579
- private isFlushEnqueued;
580
- constructor(queue: OIMEventQueue, resolver: IOIMCarrierResolver<TKey, TCarrier>);
581
- subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
582
- subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
583
- unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
584
- unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
585
- private addHandler;
586
- private removeHandler;
587
- /** Fast path: the writer already holds the carrier. */
588
- markUpdatedCarrier(carrier: TCarrier): void;
589
- markUpdatedKey(key: TKey): void;
590
- markUpdatedKeys(keys: readonly TKey[]): void;
591
- markAllUpdated(): void;
592
- hasSubscriptions(): boolean;
593
- getHandlerCount(key: TKey): number;
594
- getMetrics(): {
595
- totalKeys: number;
596
- totalHandlers: number;
597
- averageHandlersPerKey: number;
598
- queueLength: number;
599
- };
600
- destroy(): void;
601
- private assertNotInFlush;
602
- private scheduleFlush;
603
- private readonly onFlush;
604
- private notify;
605
- }
606
-
607
- declare class OIMReactiveCollection<TEntity extends object, TPk extends TOIMPk> extends OIMCollection<TEntity, TPk> implements IOIMKeyedSubscription<TPk> {
809
+ declare class OIMReactiveCollection<TEntity extends object, TPk extends TOIMKey> extends OIMCollection<TEntity, TPk> implements IOIMKeyedSubscription<TPk> {
608
810
  private readonly queue;
609
811
  protected readonly updateEmitter: OIMCarrierKeyedEmitter<TPk, TOIMEntitySlot<TEntity, TPk>>;
610
812
  private readonly anyUpdateHandlers;
611
- private pendingAnyUpdatePks;
813
+ private readonly pendingAnyUpdatePks;
612
814
  private isAnyUpdateClearPending;
613
815
  private isAnyUpdateScheduled;
614
816
  constructor(queue: OIMEventQueue, opts?: TOIMCollectionOptions<TEntity, TPk>);
@@ -644,7 +846,7 @@ declare class OIMReactiveCollection<TEntity extends object, TPk extends TOIMPk>
644
846
  destroy(): void;
645
847
  }
646
848
 
647
- type TOIMCollectionIndexSetBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
849
+ type TOIMCollectionIndexSetBasedOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = {
648
850
  indexOptions?: {
649
851
  comparePks?: TOIMIndexComparator<TPk>;
650
852
  store?: OIMIndexStoreSetBased<TKey, TPk>;
@@ -656,7 +858,7 @@ type TOIMCollectionIndexSetBasedOptions<TEntity extends object, TKey extends TOI
656
858
  collection?: never;
657
859
  resolveSlot: TOIMEntitySlotResolver<TPk>;
658
860
  });
659
- type TOIMCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
861
+ type TOIMCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = {
660
862
  indexOptions?: {
661
863
  comparePks?: TOIMIndexComparator<TPk>;
662
864
  store?: OIMIndexStoreArrayBased<TKey, TPk>;
@@ -668,14 +870,14 @@ type TOIMCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends T
668
870
  collection?: never;
669
871
  resolveSlot: TOIMEntitySlotResolver<TPk>;
670
872
  });
671
- type TOIMCollectionOrderedIndexOptions<TEntity extends object, TPk extends TOIMPk> = {
873
+ type TOIMCollectionOrderedIndexOptions<TEntity extends object, TPk extends TOIMKey> = {
672
874
  collection: OIMReactiveCollection<TEntity, TPk>;
673
875
  resolveSlot?: never;
674
876
  } | {
675
877
  collection?: never;
676
878
  resolveSlot: TOIMEntitySlotResolver<TPk>;
677
879
  };
678
- type TOIMCollectionOrderedListCommandStreamOptions<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object> = {
880
+ type TOIMCollectionOrderedListCommandStreamOptions<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object> = {
679
881
  index?: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
680
882
  } & ({
681
883
  collection: OIMReactiveCollection<TEntity, TPk>;
@@ -684,23 +886,69 @@ type TOIMCollectionOrderedListCommandStreamOptions<TKey extends TOIMPk, TPk exte
684
886
  collection?: never;
685
887
  resolveSlot: TOIMEntitySlotResolver<TPk>;
686
888
  });
687
- type TOIMRelationsSetIndexOptions<TKey extends TOIMPk, TPk extends TOIMPk> = {
889
+ type TOIMRelationsSetIndexOptions<TKey extends TOIMKey, TPk extends TOIMKey> = {
688
890
  indexOptions?: {
689
891
  comparePks?: TOIMIndexComparator<TPk>;
690
892
  store?: OIMIndexStoreSetBased<TKey, TPk>;
691
893
  };
692
894
  };
693
- type TOIMRelationsArrayIndexOptions<TKey extends TOIMPk, TPk extends TOIMPk> = {
895
+ type TOIMRelationsArrayIndexOptions<TKey extends TOIMKey, TPk extends TOIMKey> = {
694
896
  indexOptions?: {
695
897
  comparePks?: TOIMIndexComparator<TPk>;
696
898
  store?: OIMIndexStoreArrayBased<TKey, TPk>;
697
899
  };
698
900
  };
699
- type TOIMRelationsOrderedListOptions<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object> = {
901
+ /**
902
+ * Options for a composite (trie-backed) Set-based index. Its key is a
903
+ * `TOIMKeyPath` — an arbitrary-length tuple of primitive segments — looked up by
904
+ * content in O(arity). The store defaults to `OIMIndexStoreTrieDrivenSetBased`.
905
+ */
906
+ type TOIMCollectionIndexCompositeSetBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
907
+ indexOptions?: {
908
+ comparePks?: TOIMIndexComparator<TPk>;
909
+ store?: OIMIndexStoreSetBased<TOIMKeyPath, TPk>;
910
+ };
911
+ } & ({
912
+ collection: OIMReactiveCollection<TEntity, TPk>;
913
+ resolveSlot?: never;
914
+ } | {
915
+ collection?: never;
916
+ resolveSlot: TOIMEntitySlotResolver<TPk>;
917
+ });
918
+ type TOIMRelationsCompositeSetIndexOptions<TPk extends TOIMKey> = {
919
+ indexOptions?: {
920
+ comparePks?: TOIMIndexComparator<TPk>;
921
+ store?: OIMIndexStoreSetBased<TOIMKeyPath, TPk>;
922
+ };
923
+ };
924
+ /**
925
+ * Options for a composite (trie-backed) Array-based (ordered) index. Its key is
926
+ * a `TOIMKeyPath`, looked up by content in O(arity). The store defaults to
927
+ * `OIMIndexStoreTrieDrivenArrayBased`.
928
+ */
929
+ type TOIMCollectionIndexCompositeArrayBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
930
+ indexOptions?: {
931
+ comparePks?: TOIMIndexComparator<TPk>;
932
+ store?: OIMIndexStoreArrayBased<TOIMKeyPath, TPk>;
933
+ };
934
+ } & ({
935
+ collection: OIMReactiveCollection<TEntity, TPk>;
936
+ resolveSlot?: never;
937
+ } | {
938
+ collection?: never;
939
+ resolveSlot: TOIMEntitySlotResolver<TPk>;
940
+ });
941
+ type TOIMRelationsCompositeArrayIndexOptions<TPk extends TOIMKey> = {
942
+ indexOptions?: {
943
+ comparePks?: TOIMIndexComparator<TPk>;
944
+ store?: OIMIndexStoreArrayBased<TOIMKeyPath, TPk>;
945
+ };
946
+ };
947
+ type TOIMRelationsOrderedListOptions<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object> = {
700
948
  index?: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
701
949
  };
702
- type TOIMDerivedIndexKeySelector<TEntity extends object, TKey extends TOIMPk> = (entity: TEntity) => TKey | readonly TKey[] | undefined | null;
703
- type TOIMDerivedCollectionIndexSetBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
950
+ type TOIMDerivedIndexKeySelector<TEntity extends object, TKey extends TOIMKey> = (entity: TEntity) => TKey | readonly TKey[] | undefined | null;
951
+ type TOIMDerivedCollectionIndexSetBasedOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = {
704
952
  selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>;
705
953
  /**
706
954
  * Build initial index state from existing collection slots.
@@ -709,11 +957,11 @@ type TOIMDerivedCollectionIndexSetBasedOptions<TEntity extends object, TKey exte
709
957
  buildInitial?: boolean;
710
958
  indexOptions?: TOIMCollectionIndexSetBasedOptions<TEntity, TKey, TPk>['indexOptions'];
711
959
  };
712
- type TOIMRelationsDerivedSetIndexOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = Omit<TOIMDerivedCollectionIndexSetBasedOptions<TEntity, TKey, TPk>, 'selectIndexKeys'>;
960
+ type TOIMRelationsDerivedSetIndexOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = Omit<TOIMDerivedCollectionIndexSetBasedOptions<TEntity, TKey, TPk>, 'selectIndexKeys'>;
713
961
  type TOIMDerivedEntityOrderValue = string | number | bigint | boolean;
714
962
  type TOIMDerivedEntityOrderSelector<TEntity extends object> = (entity: TEntity) => TOIMDerivedEntityOrderValue;
715
963
  type TOIMDerivedEntityComparator<TEntity extends object> = (a: TEntity, b: TEntity) => number;
716
- type TOIMDerivedCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
964
+ type TOIMDerivedCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = {
717
965
  selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>;
718
966
  /**
719
967
  * Build initial index state from existing collection slots.
@@ -730,7 +978,7 @@ type TOIMDerivedCollectionIndexArrayBasedOptions<TEntity extends object, TKey ex
730
978
  orderBy?: TOIMDerivedEntityOrderSelector<TEntity>;
731
979
  indexOptions?: TOIMCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>['indexOptions'];
732
980
  };
733
- type TOIMRelationsDerivedArrayIndexOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = Omit<TOIMDerivedCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>, 'selectIndexKeys'>;
981
+ type TOIMRelationsDerivedArrayIndexOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = Omit<TOIMDerivedCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>, 'selectIndexKeys'>;
734
982
 
735
983
  /**
736
984
  * Manual ordered Array-based index.
@@ -743,9 +991,10 @@ type TOIMRelationsDerivedArrayIndexOptions<TEntity extends object, TKey extends
743
991
  *
744
992
  * It emits UPDATE events per key on every successful mutation. It is a plain
745
993
  * data structure: it knows nothing about "commands" — turning its mutations
746
- * into position-addressed commands is the command stream's job.
994
+ * into position-addressed commands is the command stream's job. Mutations happen
995
+ * on the store's stable carrier bucket in place (via `arrayStore`).
747
996
  */
748
- declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexArrayBased<TKey, TPk> {
997
+ declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndexArrayBased<TKey, TPk> {
749
998
  clear(key?: TKey): void;
750
999
  pushSlot(key: TKey, slot: TOIMAnyEntitySlot<TPk>): number;
751
1000
  insertSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TPk>): number;
@@ -765,7 +1014,6 @@ declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk extends T
765
1014
  */
766
1015
  moveRange(key: TKey, from: number, to: number, count: number): number;
767
1016
  resetSlots(key: TKey, slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
768
- private getOrCreateList;
769
1017
  }
770
1018
 
771
1019
  /**
@@ -774,7 +1022,7 @@ declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk extends T
774
1022
  * Raw ordered indexes store slots. This variant provides PK writes and resolves
775
1023
  * them to canonical collection slots at construction-bound write time.
776
1024
  */
777
- declare class OIMCollectionIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMIndexManualOrderedArrayBased<TKey, TPk> {
1025
+ declare class OIMCollectionIndexManualOrderedArrayBased<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMIndexManualOrderedArrayBased<TKey, TPk> {
778
1026
  private readonly resolveSlot;
779
1027
  constructor(opts: TOIMCollectionOrderedIndexOptions<TEntity, TPk>);
780
1028
  push(key: TKey, pk: TPk): number;
@@ -792,7 +1040,7 @@ type TOIMUpdateEventEmitterDeliveryMode = 'queue' | 'after_flush' | 'immediate';
792
1040
  * Universal event emitter that handles subscriptions and notifications for any key type.
793
1041
  * Optimized for performance with adaptive algorithms and memory management.
794
1042
  */
795
- declare class OIMUpdateEventEmitter<TKey extends TOIMPk> {
1043
+ declare class OIMUpdateEventEmitter<TKey extends TOIMKey> {
796
1044
  protected keyHandlers: Map<TKey, Set<TOIMEventHandler<void>>>;
797
1045
  protected queue: OIMEventQueue;
798
1046
  private readonly deliveryMode;
@@ -895,7 +1143,7 @@ type TOIMOrderedListCommand<TItem> = {
895
1143
  * payload, so `consumeCommands(key)` must be called inside the `handler`, before
896
1144
  * the buffer for that key is cleared.
897
1145
  */
898
- interface IOIMOrderedListCommandSource<TKey extends TOIMPk, TItem> {
1146
+ interface IOIMOrderedListCommandSource<TKey extends TOIMKey, TItem> {
899
1147
  /**
900
1148
  * Subscribe to per-key command notifications. The handler receives no
901
1149
  * payload — pull the commands with {@link consumeCommands} synchronously.
@@ -924,7 +1172,7 @@ interface IOIMOrderedListCommandSource<TKey extends TOIMPk, TItem> {
924
1172
  * consulted only on the cold reset-coalescing path, so it stays off the hot
925
1173
  * append path.
926
1174
  */
927
- declare abstract class OIMOrderedListCommandBuffer<TKey extends TOIMPk, TItem> implements IOIMOrderedListCommandSource<TKey, TItem> {
1175
+ declare abstract class OIMOrderedListCommandBuffer<TKey extends TOIMKey, TItem> implements IOIMOrderedListCommandSource<TKey, TItem> {
928
1176
  readonly commandsEventEmitter: OIMUpdateEventEmitter<TKey>;
929
1177
  private readonly unsubscribeAfterFlush;
930
1178
  protected readonly commandsByKey: Map<TKey, TOIMOrderedListCommand<TItem>[]>;
@@ -955,7 +1203,7 @@ declare abstract class OIMOrderedListCommandBuffer<TKey extends TOIMPk, TItem> i
955
1203
  * Command buffering, `after_flush` delivery and the consume/subscribe surface
956
1204
  * come from {@link OIMOrderedListCommandBuffer}.
957
1205
  */
958
- declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMOrderedListCommandBuffer<TKey, TOIMEntitySlot<TEntity, TPk>> {
1206
+ declare class OIMOrderedListCommandStream<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMOrderedListCommandBuffer<TKey, TOIMEntitySlot<TEntity, TPk>> {
959
1207
  /** Underlying slot-first ordered index. */
960
1208
  readonly index: OIMIndexManualOrderedArrayBased<TKey, TPk>;
961
1209
  constructor(queue: OIMEventQueue, index?: OIMIndexManualOrderedArrayBased<TKey, TPk>);
@@ -990,7 +1238,7 @@ declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMP
990
1238
  * Public writes use PKs; they resolve to canonical collection slots (throwing on
991
1239
  * an unresolvable pk) before mutating the index and recording the command.
992
1240
  */
993
- declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMOrderedListCommandStream<TKey, TPk, TEntity> {
1241
+ declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMOrderedListCommandStream<TKey, TPk, TEntity> {
994
1242
  readonly index: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
995
1243
  constructor(queue: OIMEventQueue, opts: TOIMCollectionOrderedListCommandStreamOptions<TKey, TPk, TEntity>);
996
1244
  push(key: TKey, pk: TPk): void;
@@ -1004,28 +1252,37 @@ declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMPk, TPk ext
1004
1252
  }
1005
1253
 
1006
1254
  /**
1007
- * Manual Array-based index that allows direct manipulation of key-to-primary-keys mappings.
1008
- * Extends the abstract OIMIndexArrayBased with manual control methods and optional comparison.
1255
+ * Manual Array-based (ordered) index with direct key→slots control.
1256
+ *
1257
+ * Buckets are stable carrier buckets owned by the store (`getOrReserveBucket`):
1258
+ * a write mutates the SAME bucket in place and then calls `emitBucketChanged`,
1259
+ * so the reactive subclass delivers straight off that bucket in O(1). Emptied
1260
+ * buckets are released (kept only while subscribed).
1009
1261
  */
1010
- declare class OIMIndexManualArrayBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexArrayBased<TIndexKey, TPk> {
1262
+ declare class OIMIndexManualArrayBased<TIndexKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndexArrayBased<TIndexKey, TPk> {
1011
1263
  constructor(options?: {
1012
1264
  comparePks?: TOIMIndexComparator<TPk>;
1013
1265
  store?: OIMIndexStoreArrayBased<TIndexKey, TPk>;
1014
1266
  });
1015
1267
  setSlots(key: TIndexKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
1016
1268
  /**
1017
- * Appends pre-deduplicated slots to a key's bucket IN PLACE (no copy of the
1018
- * existing bucket) and emits once. Callers own dedup (so this stays O(added),
1019
- * not O(bucket)); used by collection-bound indexes for fast `addPks`.
1269
+ * Appends pre-deduplicated slots to a key's bucket IN PLACE and emits once.
1270
+ * O(added); callers own dedup.
1020
1271
  */
1021
1272
  appendSlots(key: TIndexKey, slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1022
1273
  /**
1023
- * Clear all primary keys for a specific index key, or all keys if no key specified
1274
+ * Clear all primary keys for a specific index key, or all keys if none given.
1024
1275
  */
1025
1276
  clear(key?: TIndexKey): void;
1277
+ /**
1278
+ * Emit that a bucket changed. Base (non-reactive) path emits by key on the
1279
+ * plain event emitter; the reactive subclass overrides this to mark the
1280
+ * bucket carrier directly (O(1), no key→carrier lookup).
1281
+ */
1282
+ protected emitBucketChanged(bucket: OIMKeyedBucketArrayBased<TIndexKey, TPk>): void;
1026
1283
  }
1027
1284
 
1028
- declare class OIMReactiveIndexManualArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMReactiveIndexArrayBased<TKey, TPk, OIMIndexManualArrayBased<TKey, TPk>> {
1285
+ declare class OIMReactiveIndexManualArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMReactiveIndexArrayBased<TKey, TPk, OIMIndexManualArrayBased<TKey, TPk>> {
1029
1286
  constructor(queue: OIMEventQueue, opts?: {
1030
1287
  indexOptions?: {
1031
1288
  comparePks?: TOIMIndexComparator<TPk>;
@@ -1043,8 +1300,9 @@ declare class OIMReactiveIndexManualArrayBased<TKey extends TOIMPk, TPk extends
1043
1300
  * PK writes (`setPks`/`addPks`/`removePks`) resolve canonical entity slots
1044
1301
  * through the collection binding supplied at construction time.
1045
1302
  */
1046
- declare class OIMReactiveCollectionIndexManualArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveIndexManualArrayBased<TKey, TPk> {
1303
+ declare class OIMReactiveCollectionIndexManualArrayBased<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveIndexManualArrayBased<TKey, TPk> {
1047
1304
  private readonly resolveSlot;
1305
+ private readonly pkDomain;
1048
1306
  private readonly pksByKey;
1049
1307
  constructor(queue: OIMEventQueue, opts: TOIMCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>);
1050
1308
  setPks(key: TKey, pks: readonly TPk[]): void;
@@ -1063,18 +1321,35 @@ declare class OIMReactiveCollectionIndexManualArrayBased<TKey extends TOIMPk, TP
1063
1321
  }
1064
1322
 
1065
1323
  /**
1066
- * Manual Set-based index that allows direct manipulation of key-to-primary-keys mappings.
1067
- * Extends the abstract OIMIndexSetBased with manual control methods and optional comparison.
1068
- */
1069
- declare class OIMIndexManualSetBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexSetBased<TIndexKey, TPk> {
1324
+ * Manual Set-based index with direct key→slots control.
1325
+ *
1326
+ * Buckets are stable carrier buckets owned by the store (`getOrReserveBucket`):
1327
+ * a write mutates the SAME bucket in place and then calls `emitBucketChanged`,
1328
+ * so the reactive subclass delivers straight off that bucket in O(1). Emptied
1329
+ * buckets are released (kept only while subscribed); the store keeps a
1330
+ * subscribed-but-empty bucket alive so a subscription survives a key going empty
1331
+ * and re-filling.
1332
+ */
1333
+ declare class OIMIndexManualSetBased<TIndexKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndexSetBased<TIndexKey, TPk> {
1334
+ protected readonly pkDomain: IOIMKeyDomain<TPk>;
1070
1335
  constructor(options?: {
1071
1336
  comparePks?: TOIMIndexComparator<TPk>;
1072
1337
  store?: OIMIndexStoreSetBased<TIndexKey, TPk>;
1338
+ pkDomain?: IOIMKeyDomain<TPk>;
1073
1339
  });
1074
1340
  setSlots(key: TIndexKey, slots: Iterable<TOIMAnyEntitySlot<TPk>>): void;
1341
+ setPks(key: TIndexKey, pks: readonly TPk[], resolveSlot: (pk: TPk) => TOIMAnyEntitySlot<TPk>): void;
1342
+ addPks(key: TIndexKey, pks: readonly TPk[], resolveSlot: (pk: TPk) => TOIMAnyEntitySlot<TPk>): void;
1343
+ removePks(key: TIndexKey, pks: readonly TPk[]): void;
1075
1344
  /**
1076
- * Adds slots to a key's bucket IN PLACE (no copy of the existing Set) and
1077
- * emits once. O(added). Used by collection-bound indexes for fast `addPks`.
1345
+ * The bucket's pk → slot membership, lazily created and seeded from the
1346
+ * bucket's current slots (so it stays correct even if slots were written
1347
+ * through the lower-level `setSlots` path).
1348
+ */
1349
+ private membershipOf;
1350
+ private replaceBucketContents;
1351
+ /**
1352
+ * Adds slots to a key's bucket IN PLACE and emits once. O(added).
1078
1353
  */
1079
1354
  addSlots(key: TIndexKey, slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1080
1355
  /**
@@ -1082,17 +1357,29 @@ declare class OIMIndexManualSetBased<TIndexKey extends TOIMPk, TPk extends TOIMP
1082
1357
  */
1083
1358
  removeSlots(key: TIndexKey, slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1084
1359
  /**
1085
- * Clear all primary keys for a specific index key, or all keys if no key specified
1360
+ * Clear all primary keys for a specific index key, or all keys if none given.
1086
1361
  */
1087
1362
  clear(key?: TIndexKey): void;
1363
+ /**
1364
+ * Emit that a bucket changed. Base (non-reactive) path emits by key on the
1365
+ * plain event emitter; the reactive subclass overrides this to mark the
1366
+ * bucket carrier directly (O(1), no key→carrier lookup).
1367
+ */
1368
+ protected emitBucketChanged(bucket: OIMKeyedBucketSetBased<TIndexKey, TPk>): void;
1088
1369
  }
1089
1370
 
1090
- declare class OIMReactiveIndexManualSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMReactiveIndexSetBased<TKey, TPk, OIMIndexManualSetBased<TKey, TPk>> {
1371
+ declare class OIMReactiveIndexManualSetBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMReactiveIndexSetBased<TKey, TPk, OIMIndexManualSetBased<TKey, TPk>> {
1091
1372
  constructor(queue: OIMEventQueue, opts?: {
1092
1373
  indexOptions?: {
1093
1374
  comparePks?: TOIMIndexComparator<TPk>;
1094
1375
  store?: OIMIndexStoreSetBased<TKey, TPk>;
1095
1376
  };
1377
+ /**
1378
+ * PK key domain for the per-bucket membership — native for primitive
1379
+ * PKs, trie for a composite-PK collection. Threaded from the bound
1380
+ * collection's `keyDomain`.
1381
+ */
1382
+ pkDomain?: IOIMKeyDomain<TPk>;
1096
1383
  });
1097
1384
  setSlots(key: TKey, slots: Iterable<TOIMAnyEntitySlot<TPk>>): void;
1098
1385
  addSlots(key: TKey, slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
@@ -1104,23 +1391,74 @@ declare class OIMReactiveIndexManualSetBased<TKey extends TOIMPk, TPk extends TO
1104
1391
  * Collection-bound reactive Set-based index.
1105
1392
  *
1106
1393
  * PK writes (`setPks`/`addPks`/`removePks`) resolve canonical entity slots
1107
- * through the collection binding supplied at construction time.
1394
+ * through the collection binding and delegate to the underlying index, which
1395
+ * keeps each key's pk→slot membership ON the bucket itself — so a write touches
1396
+ * the key's store bucket exactly once (no separate membership map/trie).
1108
1397
  */
1109
- declare class OIMReactiveCollectionIndexManualSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveIndexManualSetBased<TKey, TPk> {
1398
+ declare class OIMReactiveCollectionIndexManualSetBased<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveIndexManualSetBased<TKey, TPk> {
1110
1399
  private readonly resolveSlot;
1111
- private readonly slotByPk;
1400
+ private readonly resolveRequiredSlot;
1112
1401
  constructor(queue: OIMEventQueue, opts: TOIMCollectionIndexSetBasedOptions<TEntity, TKey, TPk>);
1113
1402
  setPks(key: TKey, pks: readonly TPk[]): void;
1114
1403
  addPks(key: TKey, pks: readonly TPk[]): void;
1115
1404
  removePks(key: TKey, pks: readonly TPk[]): void;
1116
- clear(key?: TKey): void;
1405
+ getEntitiesByKey<TItem extends object = TEntity>(key: TKey): (TItem | undefined)[];
1406
+ getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TKey[]): Map<TKey, (TItem | undefined)[]>;
1407
+ }
1408
+
1409
+ /**
1410
+ * Collection-bound reactive Set-based index keyed by a composite key path
1411
+ * (`TOIMKeyPath`) — an arbitrary-length tuple of primitive segments, e.g.
1412
+ * `[userId, projectId, role]`.
1413
+ *
1414
+ * Composite counterpart of `OIMReactiveCollectionIndexManualSetBased`: same
1415
+ * manual `setPks`/`addPks`/`removePks` surface and collection slot resolution,
1416
+ * but every key is a path matched by content in O(arity). Because the pk→slot
1417
+ * membership lives ON the store bucket (not a separate key-indexed structure), a
1418
+ * pk-write walks the key-path trie exactly once — for both the bucket and its
1419
+ * membership. The full path is the lookup unit (no partial/prefix queries);
1420
+ * subscriptions deliver per full path off the bucket carrier.
1421
+ *
1422
+ * The primitive-keyed indexes are untouched and keep their native-`Map` fast
1423
+ * path — the trie cost is paid only by this opt-in index.
1424
+ */
1425
+ declare class OIMReactiveCollectionIndexCompositeTrieSetBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveIndexManualSetBased<TOIMKeyPath, TPk> {
1426
+ private readonly resolveSlot;
1427
+ private readonly resolveRequiredSlot;
1428
+ constructor(queue: OIMEventQueue, opts: TOIMCollectionIndexCompositeSetBasedOptions<TEntity, TPk>);
1429
+ setPks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1430
+ addPks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1431
+ removePks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1432
+ getEntitiesByKey<TItem extends object = TEntity>(key: TOIMKeyPath): (TItem | undefined)[];
1433
+ getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TOIMKeyPath[]): Map<TOIMKeyPath, (TItem | undefined)[]>;
1434
+ }
1435
+
1436
+ /**
1437
+ * Collection-bound reactive Array-based (ordered) index keyed by a composite key
1438
+ * path (`TOIMKeyPath`). The array counterpart of
1439
+ * `OIMReactiveCollectionIndexCompositeTrieSetBased`: same manual
1440
+ * `setPks`/`addPks`/`removePks` surface and collection slot resolution, but keys
1441
+ * are ordered slot arrays and each key is a path matched by content in O(arity).
1442
+ *
1443
+ * Primitive-keyed indexes keep their native-`Map` fast path — the trie cost is
1444
+ * paid only by this opt-in index.
1445
+ */
1446
+ declare class OIMReactiveCollectionIndexCompositeTrieArrayBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveIndexManualArrayBased<TOIMKeyPath, TPk> {
1447
+ private readonly resolveSlot;
1448
+ private readonly pksByKey;
1449
+ constructor(queue: OIMEventQueue, opts: TOIMCollectionIndexCompositeArrayBasedOptions<TEntity, TPk>);
1450
+ setPks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1451
+ addPks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1452
+ removePks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1453
+ clear(key?: TOIMKeyPath): void;
1117
1454
  /**
1118
- * The pk→slot map for a key, lazily seeded from the current bucket so it
1119
- * stays correct even if slots were set through a lower-level path.
1455
+ * The membership set for a key path, lazily seeded from the current bucket so
1456
+ * it stays correct even if slots were set through a lower-level path.
1120
1457
  */
1121
1458
  private membershipOf;
1122
- getEntitiesByKey<TItem extends object = TEntity>(key: TKey): (TItem | undefined)[];
1123
- getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TKey[]): Map<TKey, (TItem | undefined)[]>;
1459
+ getEntitiesByKey<TItem extends object = TEntity>(key: TOIMKeyPath): (TItem | undefined)[];
1460
+ getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TOIMKeyPath[]): Map<TOIMKeyPath, (TItem | undefined)[]>;
1461
+ private resolveSlots;
1124
1462
  private resolveRequiredSlot;
1125
1463
  }
1126
1464
 
@@ -1130,7 +1468,7 @@ declare class OIMReactiveCollectionIndexManualSetBased<TKey extends TOIMPk, TPk
1130
1468
  * The collection remains the source of truth. This index listens to collection
1131
1469
  * updates and maintains key membership automatically.
1132
1470
  */
1133
- declare class OIMDerivedCollectionIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionIndexManualSetBased<TKey, TPk, TEntity> {
1471
+ declare class OIMDerivedCollectionIndexSetBased<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveCollectionIndexManualSetBased<TKey, TPk, TEntity> {
1134
1472
  private readonly collection;
1135
1473
  private readonly selectIndexKeys;
1136
1474
  private readonly unsubscribeFromCollection;
@@ -1150,7 +1488,7 @@ declare class OIMDerivedCollectionIndexSetBased<TKey extends TOIMPk, TPk extends
1150
1488
  * It maintains ordered per-key arrays automatically from collection updates.
1151
1489
  * Use `orderBy` or `compareEntities` when list order matters.
1152
1490
  */
1153
- declare class OIMDerivedCollectionIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity> {
1491
+ declare class OIMDerivedCollectionIndexArrayBased<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity> {
1154
1492
  private readonly collection;
1155
1493
  private readonly selectIndexKeys;
1156
1494
  private readonly compareEntities?;
@@ -1171,7 +1509,7 @@ declare class OIMDerivedCollectionIndexArrayBased<TKey extends TOIMPk, TPk exten
1171
1509
  * Manual array-based keyless index — direct raw-slot control of the single
1172
1510
  * ordered bucket. Mirrors {@link OIMIndexManualArrayBased} minus the key.
1173
1511
  */
1174
- declare class OIMGlobalIndexManualArrayBased<TPk extends TOIMPk> extends OIMGlobalIndexArrayBased<TPk> {
1512
+ declare class OIMGlobalIndexManualArrayBased<TPk extends TOIMKey> extends OIMGlobalIndexArrayBased<TPk> {
1175
1513
  constructor(options?: {
1176
1514
  comparePks?: TOIMIndexComparator<TPk>;
1177
1515
  });
@@ -1188,7 +1526,7 @@ declare class OIMGlobalIndexManualArrayBased<TPk extends TOIMPk> extends OIMGlob
1188
1526
  * Reactive manual array-based keyless index — raw-slot writes bridged to a
1189
1527
  * single-carrier emitter. Mirrors {@link OIMReactiveIndexManualArrayBased}.
1190
1528
  */
1191
- declare class OIMReactiveGlobalIndexManualArrayBased<TPk extends TOIMPk> extends OIMReactiveGlobalIndexArrayBased<TPk, OIMGlobalIndexManualArrayBased<TPk>> {
1529
+ declare class OIMReactiveGlobalIndexManualArrayBased<TPk extends TOIMKey> extends OIMReactiveGlobalIndexArrayBased<TPk, OIMGlobalIndexManualArrayBased<TPk>> {
1192
1530
  constructor(queue: OIMEventQueue, opts?: {
1193
1531
  indexOptions?: {
1194
1532
  comparePks?: TOIMIndexComparator<TPk>;
@@ -1204,7 +1542,7 @@ declare class OIMReactiveGlobalIndexManualArrayBased<TPk extends TOIMPk> extends
1204
1542
  * Defaults to "the entity exists" (`item !== undefined`) when omitted.
1205
1543
  */
1206
1544
  type TOIMGlobalIndexFilter<TEntity extends object> = (entity: TEntity) => boolean;
1207
- type TOIMCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1545
+ type TOIMCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
1208
1546
  indexOptions?: {
1209
1547
  comparePks?: TOIMIndexComparator<TPk>;
1210
1548
  };
@@ -1215,7 +1553,7 @@ type TOIMCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk exte
1215
1553
  collection?: never;
1216
1554
  resolveSlot: TOIMEntitySlotResolver<TPk>;
1217
1555
  });
1218
- type TOIMCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1556
+ type TOIMCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
1219
1557
  indexOptions?: {
1220
1558
  comparePks?: TOIMIndexComparator<TPk>;
1221
1559
  };
@@ -1226,7 +1564,7 @@ type TOIMCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extend
1226
1564
  collection?: never;
1227
1565
  resolveSlot: TOIMEntitySlotResolver<TPk>;
1228
1566
  });
1229
- type TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1567
+ type TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
1230
1568
  /** Build initial state from existing collection slots. Defaults to true. */
1231
1569
  buildInitial?: boolean;
1232
1570
  /** Sort the list. Takes priority over `orderBy`. */
@@ -1239,7 +1577,7 @@ type TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity extends object, T
1239
1577
  comparePks?: TOIMIndexComparator<TPk>;
1240
1578
  };
1241
1579
  };
1242
- type TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1580
+ type TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
1243
1581
  /** Build initial state from existing collection slots. Defaults to true. */
1244
1582
  buildInitial?: boolean;
1245
1583
  /** Include predicate. Defaults to "entity exists". */
@@ -1248,18 +1586,18 @@ type TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk
1248
1586
  comparePks?: TOIMIndexComparator<TPk>;
1249
1587
  };
1250
1588
  };
1251
- type TOIMRelationsGlobalArrayIndexOptions<TPk extends TOIMPk> = {
1589
+ type TOIMRelationsGlobalArrayIndexOptions<TPk extends TOIMKey> = {
1252
1590
  indexOptions?: {
1253
1591
  comparePks?: TOIMIndexComparator<TPk>;
1254
1592
  };
1255
1593
  };
1256
- type TOIMRelationsGlobalSetIndexOptions<TPk extends TOIMPk> = {
1594
+ type TOIMRelationsGlobalSetIndexOptions<TPk extends TOIMKey> = {
1257
1595
  indexOptions?: {
1258
1596
  comparePks?: TOIMIndexComparator<TPk>;
1259
1597
  };
1260
1598
  };
1261
- type TOIMRelationsDerivedGlobalArrayIndexOptions<TEntity extends object, TPk extends TOIMPk> = TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity, TPk>;
1262
- type TOIMRelationsDerivedGlobalSetIndexOptions<TEntity extends object, TPk extends TOIMPk> = TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity, TPk>;
1599
+ type TOIMRelationsDerivedGlobalArrayIndexOptions<TEntity extends object, TPk extends TOIMKey> = TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity, TPk>;
1600
+ type TOIMRelationsDerivedGlobalSetIndexOptions<TEntity extends object, TPk extends TOIMKey> = TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity, TPk>;
1263
1601
 
1264
1602
  /**
1265
1603
  * Collection-bound reactive array-based keyless index.
@@ -1269,7 +1607,7 @@ type TOIMRelationsDerivedGlobalSetIndexOptions<TEntity extends object, TPk exten
1269
1607
  * dedup. Mirrors {@link OIMReactiveCollectionIndexManualArrayBased} minus the
1270
1608
  * key (one bucket instead of a per-key map).
1271
1609
  */
1272
- declare class OIMReactiveCollectionGlobalIndexManualArrayBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveGlobalIndexManualArrayBased<TPk> {
1610
+ declare class OIMReactiveCollectionGlobalIndexManualArrayBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveGlobalIndexManualArrayBased<TPk> {
1273
1611
  private readonly resolveSlot;
1274
1612
  private readonly membership;
1275
1613
  private membershipSeeded;
@@ -1288,7 +1626,7 @@ declare class OIMReactiveCollectionGlobalIndexManualArrayBased<TPk extends TOIMP
1288
1626
  * Manual set-based keyless index — direct raw-slot control of the single
1289
1627
  * unordered bucket. Mirrors {@link OIMIndexManualSetBased} minus the key.
1290
1628
  */
1291
- declare class OIMGlobalIndexManualSetBased<TPk extends TOIMPk> extends OIMGlobalIndexSetBased<TPk> {
1629
+ declare class OIMGlobalIndexManualSetBased<TPk extends TOIMKey> extends OIMGlobalIndexSetBased<TPk> {
1292
1630
  constructor(options?: {
1293
1631
  comparePks?: TOIMIndexComparator<TPk>;
1294
1632
  });
@@ -1304,7 +1642,7 @@ declare class OIMGlobalIndexManualSetBased<TPk extends TOIMPk> extends OIMGlobal
1304
1642
  * Reactive manual set-based keyless index — raw-slot writes bridged to a
1305
1643
  * single-carrier emitter. Mirrors {@link OIMReactiveIndexManualSetBased}.
1306
1644
  */
1307
- declare class OIMReactiveGlobalIndexManualSetBased<TPk extends TOIMPk> extends OIMReactiveGlobalIndexSetBased<TPk, OIMGlobalIndexManualSetBased<TPk>> {
1645
+ declare class OIMReactiveGlobalIndexManualSetBased<TPk extends TOIMKey> extends OIMReactiveGlobalIndexSetBased<TPk, OIMGlobalIndexManualSetBased<TPk>> {
1308
1646
  constructor(queue: OIMEventQueue, opts?: {
1309
1647
  indexOptions?: {
1310
1648
  comparePks?: TOIMIndexComparator<TPk>;
@@ -1324,7 +1662,7 @@ declare class OIMReactiveGlobalIndexManualSetBased<TPk extends TOIMPk> extends O
1324
1662
  * add (dedup) and O(1) remove. Mirrors
1325
1663
  * {@link OIMReactiveCollectionIndexManualSetBased} minus the key.
1326
1664
  */
1327
- declare class OIMReactiveCollectionGlobalIndexManualSetBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveGlobalIndexManualSetBased<TPk> {
1665
+ declare class OIMReactiveCollectionGlobalIndexManualSetBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveGlobalIndexManualSetBased<TPk> {
1328
1666
  private readonly resolveSlot;
1329
1667
  private readonly membership;
1330
1668
  private membershipSeeded;
@@ -1346,7 +1684,7 @@ declare class OIMReactiveCollectionGlobalIndexManualSetBased<TPk extends TOIMPk,
1346
1684
  * {@link OIMDerivedCollectionIndexArrayBased}, but membership is a single
1347
1685
  * boolean set (`presentPks`) instead of a per-pk key-set.
1348
1686
  */
1349
- declare class OIMDerivedCollectionGlobalIndexArrayBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionGlobalIndexManualArrayBased<TPk, TEntity> {
1687
+ declare class OIMDerivedCollectionGlobalIndexArrayBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveCollectionGlobalIndexManualArrayBased<TPk, TEntity> {
1350
1688
  private readonly collection;
1351
1689
  private readonly compareEntities?;
1352
1690
  private readonly orderBy?;
@@ -1369,7 +1707,7 @@ declare class OIMDerivedCollectionGlobalIndexArrayBased<TPk extends TOIMPk, TEnt
1369
1707
  * (default: "entity exists"). Mirrors {@link OIMDerivedCollectionIndexSetBased}
1370
1708
  * minus the key.
1371
1709
  */
1372
- declare class OIMDerivedCollectionGlobalIndexSetBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionGlobalIndexManualSetBased<TPk, TEntity> {
1710
+ declare class OIMDerivedCollectionGlobalIndexSetBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveCollectionGlobalIndexManualSetBased<TPk, TEntity> {
1373
1711
  private readonly collection;
1374
1712
  private readonly filter?;
1375
1713
  private readonly unsubscribeFromCollection;
@@ -1388,14 +1726,28 @@ declare class OIMDerivedCollectionGlobalIndexSetBased<TPk extends TOIMPk, TEntit
1388
1726
  * `queue + collection` binding in one place, so related structures can be
1389
1727
  * created next to the collection with less generic noise.
1390
1728
  */
1391
- declare class OIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMPk> {
1729
+ declare class OIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMKey> {
1392
1730
  readonly queue: OIMEventQueue;
1393
1731
  readonly collection: OIMReactiveCollection<TEntity, TPk>;
1394
1732
  constructor(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>);
1395
- setBasedIndex<TKey extends TOIMPk = string>(opts?: TOIMRelationsSetIndexOptions<TKey, TPk>): OIMReactiveCollectionIndexManualSetBased<TKey, TPk, TEntity>;
1396
- derivedSetIndex<TKey extends TOIMPk = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedSetIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexSetBased<TKey, TPk, TEntity>;
1397
- arrayBasedIndex<TKey extends TOIMPk = string>(opts?: TOIMRelationsArrayIndexOptions<TKey, TPk>): OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity>;
1398
- derivedArrayIndex<TKey extends TOIMPk = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedArrayIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexArrayBased<TKey, TPk, TEntity>;
1733
+ setBasedIndex<TKey extends TOIMKey = string>(opts?: TOIMRelationsSetIndexOptions<TKey, TPk>): OIMReactiveCollectionIndexManualSetBased<TKey, TPk, TEntity>;
1734
+ /**
1735
+ * Composite (trie-backed) manual Set-based index keyed by an
1736
+ * arbitrary-length key path, e.g. `setPks([userId, projectId, role], pks)`.
1737
+ * Key paths are matched by content in O(arity) — no string concatenation,
1738
+ * no separator collisions, each segment keeps its type. Primitive-keyed
1739
+ * indexes are unaffected and keep their native-`Map` fast path.
1740
+ */
1741
+ compositeSetIndex(opts?: TOIMRelationsCompositeSetIndexOptions<TPk>): OIMReactiveCollectionIndexCompositeTrieSetBased<TPk, TEntity>;
1742
+ /**
1743
+ * Composite (trie-backed) manual Array-based (ordered) index keyed by an
1744
+ * arbitrary-length key path, e.g. `setPks([channelId, threadId], pks)`.
1745
+ * Ordered counterpart of `compositeSetIndex`.
1746
+ */
1747
+ compositeArrayIndex(opts?: TOIMRelationsCompositeArrayIndexOptions<TPk>): OIMReactiveCollectionIndexCompositeTrieArrayBased<TPk, TEntity>;
1748
+ derivedSetIndex<TKey extends TOIMKey = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedSetIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexSetBased<TKey, TPk, TEntity>;
1749
+ arrayBasedIndex<TKey extends TOIMKey = string>(opts?: TOIMRelationsArrayIndexOptions<TKey, TPk>): OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity>;
1750
+ derivedArrayIndex<TKey extends TOIMKey = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedArrayIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexArrayBased<TKey, TPk, TEntity>;
1399
1751
  /**
1400
1752
  * Keyless (whole-collection / "all") manual array-based index. No key —
1401
1753
  * write pks directly with `setPks`/`addPks`/`removePks`.
@@ -1410,10 +1762,10 @@ declare class OIMCollectionIndexFactory<TEntity extends object, TPk extends TOIM
1410
1762
  derivedArrayGlobalIndex(opts?: TOIMRelationsDerivedGlobalArrayIndexOptions<TEntity, TPk>): OIMDerivedCollectionGlobalIndexArrayBased<TPk, TEntity>;
1411
1763
  /** Keyless set auto-derived from the whole collection. */
1412
1764
  derivedSetGlobalIndex(opts?: TOIMRelationsDerivedGlobalSetIndexOptions<TEntity, TPk>): OIMDerivedCollectionGlobalIndexSetBased<TPk, TEntity>;
1413
- orderedIndex<TKey extends TOIMPk = string>(): OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
1414
- orderedList<TKey extends TOIMPk = string>(opts?: TOIMRelationsOrderedListOptions<TKey, TPk, TEntity>): OIMCollectionOrderedListCommandStream<TKey, TPk, TEntity>;
1765
+ orderedIndex<TKey extends TOIMKey = string>(): OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
1766
+ orderedList<TKey extends TOIMKey = string>(opts?: TOIMRelationsOrderedListOptions<TKey, TPk, TEntity>): OIMCollectionOrderedListCommandStream<TKey, TPk, TEntity>;
1415
1767
  }
1416
- declare function createOIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMPk>(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>): OIMCollectionIndexFactory<TEntity, TPk>;
1768
+ declare function createOIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMKey>(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>): OIMCollectionIndexFactory<TEntity, TPk>;
1417
1769
 
1418
1770
  /**
1419
1771
  * Payload type for update events that contain keys */
@@ -1479,7 +1831,15 @@ declare class OIMReactiveObject<TKey extends string, TValue> extends OIMObject<T
1479
1831
  destroy(): void;
1480
1832
  }
1481
1833
 
1482
- declare class OIMCollectionStoreMapDriven<TEntity extends object, TPk extends TOIMPk> extends OIMCollectionStore<TEntity, TPk> {
1834
+ /**
1835
+ * Native-`Map` collection store for primitive PKs. The hot path is a plain
1836
+ * `Map` — this class NEVER holds a trie, so its `.get`/`.set` call sites stay
1837
+ * monomorphic even in a process that also runs composite-PK collections (those
1838
+ * use `OIMCollectionStoreTrieDriven`). Byte-for-byte the pre-seam behavior; the
1839
+ * only addition is a shared native `keyDomain` object the indexes read.
1840
+ */
1841
+ declare class OIMCollectionStoreMapDriven<TEntity extends object, TPk extends TOIMKey> extends OIMCollectionStore<TEntity, TPk> {
1842
+ readonly keyDomain: IOIMKeyDomain<TPk>;
1483
1843
  protected readonly slots: Map<TPk, TOIMEntitySlot<TEntity, TPk>>;
1484
1844
  protected readonly reservedSlots: Map<TPk, TOIMEntitySlot<TEntity, TPk>>;
1485
1845
  setOneByPk(pk: TPk, entity: TEntity): TOIMEntitySlot<TEntity, TPk>;
@@ -1501,6 +1861,76 @@ declare class OIMCollectionStoreMapDriven<TEntity extends object, TPk extends TO
1501
1861
  destroy(): void;
1502
1862
  }
1503
1863
 
1864
+ /**
1865
+ * Key domain for composite key paths (`TOIMKeyPath`) — the trie counterpart of
1866
+ * `OIMKeyDomainNative`. Maps/Sets are trie-backed (match array keys by content),
1867
+ * and `canonicalize` interns each logical key into one stable reference via a
1868
+ * shared pool, so a collection's `slot.pk` is a single reference per logical key
1869
+ * and every downstream native `Set<slot.pk>`/`Map<slot.pk>` stays correct.
1870
+ *
1871
+ * Object-key support later: swap in a `keyToSegments` that sorts object entries;
1872
+ * nothing else here or at the call sites changes.
1873
+ */
1874
+ declare class OIMKeyDomainTrie implements IOIMKeyDomain<TOIMKeyPath> {
1875
+ private readonly pool;
1876
+ createMap<TValue>(): IOIMKeyedMap<TOIMKeyPath, TValue>;
1877
+ createSet(): IOIMKeyedSet<TOIMKeyPath>;
1878
+ canonicalize(key: TOIMKeyPath): TOIMKeyPath;
1879
+ }
1880
+
1881
+ declare class OIMTrieMap<TSegment, TValue> {
1882
+ private readonly root;
1883
+ private _size;
1884
+ /** Number of stored paths (terminal nodes), not the number of trie nodes. */
1885
+ get size(): number;
1886
+ set(path: readonly TSegment[], value: TValue): void;
1887
+ get(path: readonly TSegment[]): TValue | undefined;
1888
+ has(path: readonly TSegment[]): boolean;
1889
+ delete(path: readonly TSegment[]): boolean;
1890
+ clear(): void;
1891
+ /** Depth-first iteration over `[path, value]` for every stored path. */
1892
+ entries(): IterableIterator<[TSegment[], TValue]>;
1893
+ keys(): IterableIterator<TSegment[]>;
1894
+ values(): IterableIterator<TValue>;
1895
+ private findNode;
1896
+ }
1897
+
1898
+ /**
1899
+ * Composite-PK collection store: keys slots by a `TOIMKeyPath` via a trie, so a
1900
+ * freshly built `[a, b]` resolves to the same slot as one stored earlier, and
1901
+ * `slot.pk` is interned to one canonical reference per logical key (downstream
1902
+ * native `Set<slot.pk>` stay correct).
1903
+ *
1904
+ * It is a SEPARATE class from `OIMCollectionStoreMapDriven` on purpose: each
1905
+ * store's `.get`/`.set` call sites see exactly one container shape (all-`Map`
1906
+ * there, all-trie here), so a process running both primitive and composite
1907
+ * collections keeps both hot paths monomorphic — no shared-class inline-cache
1908
+ * pollution. Method bodies mirror the Map store.
1909
+ */
1910
+ declare class OIMCollectionStoreTrieDriven<TEntity extends object> extends OIMCollectionStore<TEntity, TOIMKeyPath> {
1911
+ readonly keyDomain: IOIMKeyDomain<TOIMKeyPath>;
1912
+ protected readonly slots: OIMTrieMap<TOIMPk, TOIMEntitySlot<TEntity, TOIMKeyPath>>;
1913
+ protected readonly reservedSlots: OIMTrieMap<TOIMPk, TOIMEntitySlot<TEntity, TOIMKeyPath>>;
1914
+ constructor(keyDomain?: OIMKeyDomainTrie);
1915
+ setOneByPk(pk: TOIMKeyPath, entity: TEntity): TOIMEntitySlot<TEntity, TOIMKeyPath>;
1916
+ getOrReserveSlotByPk(pk: TOIMKeyPath): TOIMEntitySlot<TEntity, TOIMKeyPath>;
1917
+ setManyByPks(pks: readonly TOIMKeyPath[], entities: TEntity[]): TOIMEntitySlot<TEntity, TOIMKeyPath>[];
1918
+ getSlotByPk(pk: TOIMKeyPath): TOIMEntitySlot<TEntity, TOIMKeyPath> | undefined;
1919
+ findSlotByPk(pk: TOIMKeyPath): TOIMEntitySlot<TEntity, TOIMKeyPath> | undefined;
1920
+ private hasSubscribers;
1921
+ getSlotsByPks(pks: readonly TOIMKeyPath[]): TOIMEntitySlot<TEntity, TOIMKeyPath>[];
1922
+ getAllSlots(): TOIMEntitySlot<TEntity, TOIMKeyPath>[];
1923
+ removeOneByPk(pk: TOIMKeyPath): void;
1924
+ removeManyByPks(pks: readonly TOIMKeyPath[]): void;
1925
+ getOneByPk(pk: TOIMKeyPath): TEntity | undefined;
1926
+ getManyByPks(pks: readonly TOIMKeyPath[]): TEntity[];
1927
+ getAll(): TEntity[];
1928
+ countAll(): number;
1929
+ clear(): void;
1930
+ getAllPks(): TOIMKeyPath[];
1931
+ destroy(): void;
1932
+ }
1933
+
1504
1934
  declare class OIMObjectStoreMapDriven<TKey extends TOIMPk, TValue> extends OIMObjectStore<TKey, TValue> {
1505
1935
  protected readonly properties: Map<TKey, TValue>;
1506
1936
  setProperty(key: TKey, value: TValue): void;
@@ -1538,8 +1968,14 @@ declare class OIMObjectStoreRecordDriven<TKey extends string, TValue> extends OI
1538
1968
  destroy(): void;
1539
1969
  }
1540
1970
 
1541
- declare class OIMIndexStoreMapDrivenSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexStoreSetBased<TKey, TPk> {
1542
- protected readonly slots: Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
1971
+ declare class OIMIndexStoreMapDrivenSetBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndexStoreSetBased<TKey, TPk> {
1972
+ protected readonly slots: Map<TKey, OIMKeyedBucketSetBased<TKey, TPk>>;
1973
+ protected readonly reservedBuckets: Map<TKey, OIMKeyedBucketSetBased<TKey, TPk>>;
1974
+ getOrReserveBucket(key: TKey): OIMKeyedBucketSetBased<TKey, TPk>;
1975
+ findBucket(key: TKey): OIMKeyedBucketSetBased<TKey, TPk> | undefined;
1976
+ retainBucket(bucket: OIMKeyedBucketSetBased<TKey, TPk>): void;
1977
+ releaseBucket(bucket: OIMKeyedBucketSetBased<TKey, TPk>): void;
1978
+ dropIfReserved(key: TKey): void;
1543
1979
  setOneByKey(key: TKey, slots: Set<TOIMAnyEntitySlot<TPk>>): void;
1544
1980
  removeOneByKey(key: TKey): void;
1545
1981
  removeManyByKeys(keys: readonly TKey[]): void;
@@ -1551,8 +1987,14 @@ declare class OIMIndexStoreMapDrivenSetBased<TKey extends TOIMPk, TPk extends TO
1551
1987
  clear(): void;
1552
1988
  }
1553
1989
 
1554
- declare class OIMIndexStoreMapDrivenArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexStoreArrayBased<TKey, TPk> {
1555
- protected readonly slots: Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
1990
+ declare class OIMIndexStoreMapDrivenArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndexStoreArrayBased<TKey, TPk> {
1991
+ protected readonly slots: Map<TKey, OIMKeyedBucketArrayBased<TKey, TPk>>;
1992
+ protected readonly reservedBuckets: Map<TKey, OIMKeyedBucketArrayBased<TKey, TPk>>;
1993
+ getOrReserveBucket(key: TKey): OIMKeyedBucketArrayBased<TKey, TPk>;
1994
+ findBucket(key: TKey): OIMKeyedBucketArrayBased<TKey, TPk> | undefined;
1995
+ retainBucket(bucket: OIMKeyedBucketArrayBased<TKey, TPk>): void;
1996
+ releaseBucket(bucket: OIMKeyedBucketArrayBased<TKey, TPk>): void;
1997
+ dropIfReserved(key: TKey): void;
1556
1998
  setOneByKey(key: TKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
1557
1999
  removeOneByKey(key: TKey): void;
1558
2000
  removeManyByKeys(keys: readonly TKey[]): void;
@@ -1564,6 +2006,106 @@ declare class OIMIndexStoreMapDrivenArrayBased<TKey extends TOIMPk, TPk extends
1564
2006
  clear(): void;
1565
2007
  }
1566
2008
 
2009
+ /**
2010
+ * Set-based index store keyed by a composite key path (`TOIMKeyPath`), backed by
2011
+ * a trie (`OIMTrieMap`) instead of a native `Map`. Key paths are matched by
2012
+ * content in O(arity) without building a string key. Buckets are carrier buckets
2013
+ * with the same live/reserved lifecycle as the Map-driven store.
2014
+ */
2015
+ declare class OIMIndexStoreTrieDrivenSetBased<TPk extends TOIMKey> extends OIMIndexStoreSetBased<TOIMKeyPath, TPk> {
2016
+ protected readonly slots: OIMTrieMap<TOIMPk, OIMKeyedBucketSetBased<TOIMKeyPath, TPk>>;
2017
+ protected readonly reservedBuckets: OIMTrieMap<TOIMPk, OIMKeyedBucketSetBased<TOIMKeyPath, TPk>>;
2018
+ getOrReserveBucket(key: TOIMKeyPath): OIMKeyedBucketSetBased<TOIMKeyPath, TPk>;
2019
+ findBucket(key: TOIMKeyPath): OIMKeyedBucketSetBased<TOIMKeyPath, TPk> | undefined;
2020
+ retainBucket(bucket: OIMKeyedBucketSetBased<TOIMKeyPath, TPk>): void;
2021
+ releaseBucket(bucket: OIMKeyedBucketSetBased<TOIMKeyPath, TPk>): void;
2022
+ dropIfReserved(key: TOIMKeyPath): void;
2023
+ setOneByKey(key: TOIMKeyPath, slots: Set<TOIMAnyEntitySlot<TPk>>): void;
2024
+ removeOneByKey(key: TOIMKeyPath): void;
2025
+ removeManyByKeys(keys: readonly TOIMKeyPath[]): void;
2026
+ getOneByKey(key: TOIMKeyPath): Set<TOIMAnyEntitySlot<TPk>> | undefined;
2027
+ getManyByKeys(keys: readonly TOIMKeyPath[]): Map<TOIMKeyPath, Set<TOIMAnyEntitySlot<TPk>>>;
2028
+ getAllKeys(): TOIMKeyPath[];
2029
+ getAll(): Map<TOIMKeyPath, Set<TOIMAnyEntitySlot<TPk>>>;
2030
+ countAll(): number;
2031
+ clear(): void;
2032
+ }
2033
+
2034
+ /**
2035
+ * Array-based (ordered) index store keyed by a composite key path
2036
+ * (`TOIMKeyPath`), backed by a trie (`OIMTrieMap`). The array counterpart of
2037
+ * `OIMIndexStoreTrieDrivenSetBased`: each key path maps to an ordered carrier
2038
+ * bucket (`OIMKeyedBucketArrayBased`) with the same live/reserved lifecycle,
2039
+ * matched by content in O(arity) without building a string key.
2040
+ */
2041
+ declare class OIMIndexStoreTrieDrivenArrayBased<TPk extends TOIMKey> extends OIMIndexStoreArrayBased<TOIMKeyPath, TPk> {
2042
+ protected readonly slots: OIMTrieMap<TOIMPk, OIMKeyedBucketArrayBased<TOIMKeyPath, TPk>>;
2043
+ protected readonly reservedBuckets: OIMTrieMap<TOIMPk, OIMKeyedBucketArrayBased<TOIMKeyPath, TPk>>;
2044
+ getOrReserveBucket(key: TOIMKeyPath): OIMKeyedBucketArrayBased<TOIMKeyPath, TPk>;
2045
+ findBucket(key: TOIMKeyPath): OIMKeyedBucketArrayBased<TOIMKeyPath, TPk> | undefined;
2046
+ retainBucket(bucket: OIMKeyedBucketArrayBased<TOIMKeyPath, TPk>): void;
2047
+ releaseBucket(bucket: OIMKeyedBucketArrayBased<TOIMKeyPath, TPk>): void;
2048
+ dropIfReserved(key: TOIMKeyPath): void;
2049
+ setOneByKey(key: TOIMKeyPath, slots: TOIMAnyEntitySlot<TPk>[]): void;
2050
+ removeOneByKey(key: TOIMKeyPath): void;
2051
+ removeManyByKeys(keys: readonly TOIMKeyPath[]): void;
2052
+ getOneByKey(key: TOIMKeyPath): TOIMAnyEntitySlot<TPk>[] | undefined;
2053
+ getManyByKeys(keys: readonly TOIMKeyPath[]): Map<TOIMKeyPath, TOIMAnyEntitySlot<TPk>[]>;
2054
+ getAllKeys(): TOIMKeyPath[];
2055
+ getAll(): Map<TOIMKeyPath, TOIMAnyEntitySlot<TPk>[]>;
2056
+ countAll(): number;
2057
+ clear(): void;
2058
+ }
2059
+
2060
+ /**
2061
+ * Composite-key counterpart of `OIMKeyedCarrierResolver`: backs the index keyed
2062
+ * emitter for key paths. Maps each key path to a carrier holding that path's
2063
+ * subscribers + dirty flag, via a trie (`OIMTrieMap`) so a freshly built
2064
+ * `[a, b, c]` resolves to the same carrier as the one subscribed earlier.
2065
+ *
2066
+ * Carriers are created on first subscribe (`getOrReserveCarrier`) and pruned
2067
+ * when their last subscriber leaves (`onCarrierEmptied`) — the trie drops the
2068
+ * empty branch, so a churning key-path space does not leak carriers.
2069
+ */
2070
+ declare class OIMKeyPathCarrierResolver implements IOIMCarrierResolver<TOIMKeyPath, IOIMKeyCarrier<TOIMKeyPath>> {
2071
+ private readonly carriers;
2072
+ getOrReserveCarrier(key: TOIMKeyPath): IOIMKeyCarrier<TOIMKeyPath>;
2073
+ findCarrier(key: TOIMKeyPath): IOIMKeyCarrier<TOIMKeyPath> | undefined;
2074
+ onCarrierEmptied(carrier: IOIMKeyCarrier<TOIMKeyPath>): void;
2075
+ }
2076
+
2077
+ /**
2078
+ * The bucket-lifecycle surface a carrier resolver needs from an index store —
2079
+ * implemented by both the set-based and array-based stores. `getOrReserveBucket`
2080
+ * creates a reserved (empty) bucket so a subscription can exist before its data;
2081
+ * `dropIfReserved` prunes such a bucket once its last subscriber leaves.
2082
+ */
2083
+ interface IOIMCarrierBucketStore<TKey extends TOIMKey, TBucket extends IOIMSubscribable> {
2084
+ getOrReserveBucket(key: TKey): TBucket;
2085
+ findBucket(key: TKey): TBucket | undefined;
2086
+ dropIfReserved(key: TKey): void;
2087
+ }
2088
+ /**
2089
+ * Resolves an index key to its carrier — where the carrier IS the index bucket,
2090
+ * owned by the store. Mirrors the collection's slot-based resolver: subscribers
2091
+ * live on the bucket, so on a write the reactive index marks the bucket it just
2092
+ * touched in O(1) with no key→carrier map/trie. Works uniformly for primitive
2093
+ * (Map) and composite (trie) stores, and for set- and array-based buckets.
2094
+ *
2095
+ * `getOrReserveCarrier` creates a reserved (empty) bucket so a subscription can
2096
+ * exist before its data; `onCarrierEmptied` drops such a bucket once its last
2097
+ * subscriber leaves and it holds no slots.
2098
+ */
2099
+ declare class OIMBucketCarrierResolver<TKey extends TOIMKey, TBucket extends IOIMSubscribable & {
2100
+ readonly key: TKey;
2101
+ }> implements IOIMCarrierResolver<TKey, TBucket> {
2102
+ private readonly store;
2103
+ constructor(store: IOIMCarrierBucketStore<TKey, TBucket>);
2104
+ getOrReserveCarrier(key: TKey): TBucket;
2105
+ findCarrier(key: TKey): TBucket | undefined;
2106
+ onCarrierEmptied(carrier: TBucket): void;
2107
+ }
2108
+
1567
2109
  type TOIMComparator<TEntity extends object> = (a: TEntity, b: TEntity) => boolean;
1568
2110
 
1569
2111
  declare class OIMComparatorFactory<TEntity extends object> {
@@ -1642,22 +2184,22 @@ declare class OIMIndexComparatorFactory {
1642
2184
  * Create an element-wise comparator that checks arrays for strict equality.
1643
2185
  * Compares array lengths and each element using strict equality (===).
1644
2186
  */
1645
- static createElementWiseComparator<TPk extends TOIMPk>(): TOIMIndexComparator<TPk>;
2187
+ static createElementWiseComparator<TPk extends TOIMKey>(): TOIMIndexComparator<TPk>;
1646
2188
  /**
1647
2189
  * Create a set-based comparator that checks if arrays contain the same elements.
1648
2190
  * Order doesn't matter, only the presence of elements.
1649
2191
  */
1650
- static createSetBasedComparator<TPk extends TOIMPk>(): TOIMIndexComparator<TPk>;
2192
+ static createSetBasedComparator<TPk extends TOIMKey>(): TOIMIndexComparator<TPk>;
1651
2193
  /**
1652
2194
  * Create a shallow comparator that only checks array references.
1653
2195
  * Fastest but only works if you're reusing the same array instances.
1654
2196
  */
1655
- static createShallowComparator<TPk extends TOIMPk>(): TOIMIndexComparator<TPk>;
2197
+ static createShallowComparator<TPk extends TOIMKey>(): TOIMIndexComparator<TPk>;
1656
2198
  /**
1657
2199
  * Create a no-comparison comparator that always returns false (always updates).
1658
2200
  * Useful for disabling comparison while keeping the same interface.
1659
2201
  */
1660
- static createAlwaysUpdateComparator<TPk extends TOIMPk>(): TOIMIndexComparator<TPk>;
2202
+ static createAlwaysUpdateComparator<TPk extends TOIMKey>(): TOIMIndexComparator<TPk>;
1661
2203
  }
1662
2204
 
1663
2205
  declare class OIMMap2Keys<K1, K2, V> {
@@ -1671,7 +2213,133 @@ declare class OIMMap2Keys<K1, K2, V> {
1671
2213
  clear(): void;
1672
2214
  }
1673
2215
 
1674
- declare class OIMPkSelectorFactory<TEntity extends object, TPk extends TOIMPk> {
2216
+ /**
2217
+ * Anything with a `destroy()` teardown. `destroy(): void` is the de-facto
2218
+ * convention across oimdb (collections, indexes, objects, emitters, effects,
2219
+ * computed, streams); this interface just names it so a dispose scope can hold
2220
+ * them uniformly.
2221
+ */
2222
+ interface IOIMDisposable {
2223
+ destroy(): void;
2224
+ }
2225
+
2226
+ /**
2227
+ * A unit of teardown a dispose scope can hold: either an object with `destroy()`
2228
+ * (collection, index, object, stream, effect, computed…) or a bare unsubscribe
2229
+ * function — the `() => void` returned by `subscribeOnKey`, `emitter.on`,
2230
+ * `selector.watch`, `runtime.schedule`, etc. Many resources (selectors, per-key
2231
+ * subscriptions, scheduler tasks) expose ONLY the function form.
2232
+ */
2233
+ type TOIMDisposable = IOIMDisposable | (() => void);
2234
+
2235
+ /**
2236
+ * Collects disposables and tears them ALL down at once, in reverse registration
2237
+ * (LIFO) order — so dependents are disposed before the things they depend on
2238
+ * (indexes/streams/selectors before the collection, the collection before the
2239
+ * queue). This is the correct teardown order in oimdb, and doing it by hand is
2240
+ * the classic source of leaks and use-after-destroy bugs.
2241
+ *
2242
+ * Register as you build, capturing the value inline:
2243
+ *
2244
+ * ```ts
2245
+ * const scope = new OIMDisposeScope();
2246
+ * const queue = scope.add(new OIMEventQueue());
2247
+ * const users = scope.add(new OIMReactiveCollection(queue, { selectPk: u => u.id }));
2248
+ * const byTeam = scope.add(users.indexFactory.setBasedIndex());
2249
+ * scope.add(selector.watch(v => render(v))); // bare unsubscribe fn also works
2250
+ * // …later, one call tears everything down, LIFO:
2251
+ * scope.destroy();
2252
+ * ```
2253
+ *
2254
+ * Accepts both `{ destroy(): void }` objects and bare `() => void` unsubscribe
2255
+ * functions (selectors, per-key subscriptions and scheduler tasks only expose
2256
+ * the latter). Idempotent; every registered item is disposed even if one throws
2257
+ * (the first error is rethrown afterwards). Nestable via `child()`.
2258
+ */
2259
+ declare class OIMDisposeScope implements IOIMDisposable {
2260
+ private readonly disposables;
2261
+ private disposed;
2262
+ /** Number of not-yet-disposed items currently held. */
2263
+ get size(): number;
2264
+ get isDisposed(): boolean;
2265
+ /**
2266
+ * Register a disposable (object with `destroy()` or an unsubscribe function)
2267
+ * and return it unchanged, so it can be captured inline. If the scope is
2268
+ * already disposed the item is disposed immediately, so nothing leaks.
2269
+ */
2270
+ add<T extends TOIMDisposable>(disposable: T): T;
2271
+ /** A nested scope, itself registered here — dispose it early or with the parent. */
2272
+ child(): OIMDisposeScope;
2273
+ /**
2274
+ * Dispose everything in reverse registration order, then clear. Idempotent.
2275
+ * If any `destroy()`/unsubscribe throws, the rest are still disposed and the
2276
+ * first error is rethrown once teardown completes.
2277
+ */
2278
+ destroy(): void;
2279
+ private disposeOne;
2280
+ }
2281
+ declare function createOIMDisposeScope(): OIMDisposeScope;
2282
+
2283
+ /**
2284
+ * Trie-backed Set of composite key paths — the `Set` counterpart of
2285
+ * `OIMTrieMap`. Membership is by content, so a freshly built `[a, b]` is the
2286
+ * same member as one added earlier. Implemented over an `OIMTrieMap<TOIMPk,
2287
+ * true>` to reuse its terminal-flagged nodes and empty-branch pruning.
2288
+ */
2289
+ declare class OIMTrieSet implements IOIMKeyedSet<TOIMKeyPath> {
2290
+ private readonly map;
2291
+ get size(): number;
2292
+ add(key: TOIMKeyPath): void;
2293
+ has(key: TOIMKeyPath): boolean;
2294
+ delete(key: TOIMKeyPath): boolean;
2295
+ values(): IterableIterator<TOIMKeyPath>;
2296
+ clear(): void;
2297
+ }
2298
+
2299
+ /**
2300
+ * Default key domain for primitive keys (`string | number`): plain native
2301
+ * `Map`/`Set` and identity `canonicalize`. A native `Map`/`Set` structurally
2302
+ * satisfies `IOIMKeyedMap`/`IOIMKeyedSet`, so there is no wrapper and no
2303
+ * indirection — the hot path is byte-for-byte what it was before the seam.
2304
+ */
2305
+ declare class OIMKeyDomainNative<TKey extends TOIMKey> implements IOIMKeyDomain<TKey> {
2306
+ createMap<TValue>(): IOIMKeyedMap<TKey, TValue>;
2307
+ createSet(): IOIMKeyedSet<TKey>;
2308
+ canonicalize(key: TKey): TKey;
2309
+ }
2310
+
2311
+ /**
2312
+ * Projects a PK to/from a string, for the serialization boundaries that can only
2313
+ * key state by a string: the Redux adapter (state object keyed by id), persist
2314
+ * storage, JSON snapshots. In-memory core never needs this — it keys PKs by
2315
+ * content via `IOIMKeyDomain` — but a composite PK path cannot be a string key,
2316
+ * so those boundaries require a codec.
2317
+ *
2318
+ * There is intentionally NO default codec for composite keys: a hidden
2319
+ * `JSON.stringify` would silently couple correctness to key order / escaping.
2320
+ * Callers pass one explicitly (`OIMPkCodecKeyPath` is a ready opt-in for paths).
2321
+ */
2322
+ interface IOIMPkCodec<TPk extends TOIMKey> {
2323
+ encode(pk: TPk): string;
2324
+ decode(encoded: string): TPk;
2325
+ }
2326
+
2327
+ /**
2328
+ * Opt-in `IOIMPkCodec` for composite key paths at serialization boundaries. Uses
2329
+ * a JSON array encoding, which is collision-safe (a segment containing the
2330
+ * delimiter cannot forge a boundary the way `"a|b"` concatenation can) and
2331
+ * preserves each segment's JSON type, so `decode(encode(pk))` round-trips
2332
+ * `string`/`number` segments exactly.
2333
+ *
2334
+ * It is NOT a default — pass it explicitly where a boundary needs to key a
2335
+ * composite PK by string (Redux state, persist storage, snapshots).
2336
+ */
2337
+ declare class OIMPkCodecKeyPath implements IOIMPkCodec<TOIMKeyPath> {
2338
+ encode(pk: TOIMKeyPath): string;
2339
+ decode(encoded: string): TOIMKeyPath;
2340
+ }
2341
+
2342
+ declare class OIMPkSelectorFactory<TEntity extends object, TPk extends TOIMKey> {
1675
2343
  createIdSelector(): TOIMPkSelector<TEntity & {
1676
2344
  id: TPk;
1677
2345
  }, TPk>;
@@ -1748,29 +2416,45 @@ declare abstract class OIMSelector<TValue> {
1748
2416
  type TOIMCollectionEntitySelector<TEntity extends object> = OIMSelector<TEntity | undefined>;
1749
2417
  type TOIMCollectionEntitiesSelector<TEntity extends object> = OIMSelector<readonly (TEntity | undefined)[]>;
1750
2418
 
1751
- declare class OIMCollectionSelectors<TEntity extends object, TPk extends TOIMPk> {
2419
+ declare class OIMCollectionSelectors<TEntity extends object, TPk extends TOIMKey> {
1752
2420
  private readonly collection;
1753
2421
  readonly runtime: OIMComputeRuntime;
1754
2422
  constructor(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>);
1755
2423
  byPk(pk: TPk): TOIMCollectionEntitySelector<TEntity>;
1756
2424
  byPks(pks: readonly TPk[]): TOIMCollectionEntitiesSelector<TEntity>;
1757
- entitiesBySetIndexKey<TKey extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>>(index: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
1758
- entitiesByArrayIndexKey<TKey extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>>(index: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
2425
+ entitiesBySetIndexKey<TKey extends TOIMKey, TIndex extends OIMIndexSetBased<TKey, TPk>>(index: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
2426
+ entitiesByArrayIndexKey<TKey extends TOIMKey, TIndex extends OIMIndexArrayBased<TKey, TPk>>(index: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
2427
+ /**
2428
+ * Entities of a composite (key-path) set-based index for one key path, e.g.
2429
+ * `entitiesByCompositeSetIndexKey(index, [projectId, role])`.
2430
+ */
2431
+ entitiesByCompositeSetIndexKey<TIndex extends OIMIndexSetBased<TOIMKeyPath, TPk>>(index: OIMReactiveIndexSetBased<TOIMKeyPath, TPk, TIndex>, key: TOIMKeyPath): TOIMCollectionEntitiesSelector<TEntity>;
2432
+ /** Entities of a composite (key-path) array-based index for one key path. */
2433
+ entitiesByCompositeArrayIndexKey<TIndex extends OIMIndexArrayBased<TOIMKeyPath, TPk>>(index: OIMReactiveIndexArrayBased<TOIMKeyPath, TPk, TIndex>, key: TOIMKeyPath): TOIMCollectionEntitiesSelector<TEntity>;
1759
2434
  /** Entities of a keyless (whole-collection) array-based index, ordered. */
1760
2435
  entitiesByArrayGlobalIndex<TIndex extends OIMGlobalIndexArrayBased<TPk>>(index: OIMReactiveGlobalIndexArrayBased<TPk, TIndex>): TOIMCollectionEntitiesSelector<TEntity>;
1761
2436
  /** Entities of a keyless (whole-collection) set-based index. */
1762
2437
  entitiesBySetGlobalIndex<TIndex extends OIMGlobalIndexSetBased<TPk>>(index: OIMReactiveGlobalIndexSetBased<TPk, TIndex>): TOIMCollectionEntitiesSelector<TEntity>;
1763
2438
  }
1764
2439
 
1765
- type TOIMReactiveCollectionFactoryOptions<TEntity extends object, TPk extends TOIMPk> = TOIMCollectionOptions<TEntity, TPk>;
1766
- type TOIMCollectionKit<TEntity extends object, TPk extends TOIMPk> = {
2440
+ type TOIMReactiveCollectionFactoryOptions<TEntity extends object, TPk extends TOIMKey> = TOIMCollectionOptions<TEntity, TPk>;
2441
+ type TOIMCollectionKit<TEntity extends object, TPk extends TOIMKey> = {
1767
2442
  queue: OIMEventQueue;
1768
2443
  collection: OIMReactiveCollection<TEntity, TPk>;
1769
2444
  indexFactory: OIMCollectionIndexFactory<TEntity, TPk>;
1770
2445
  select: OIMCollectionSelectors<TEntity, TPk>;
2446
+ /**
2447
+ * Dispose scope owning the kit's collection. `add()` indexes/streams/
2448
+ * subscriptions you create off the kit, then `destroy()` tears them all down
2449
+ * in reverse order. Does NOT own the `queue` (it is passed in and may be
2450
+ * shared) — destroy the queue yourself when nothing else uses it.
2451
+ */
2452
+ scope: OIMDisposeScope;
2453
+ /** Tear down the kit's scope (collection + everything added to it). */
2454
+ destroy: () => void;
1771
2455
  };
1772
2456
 
1773
- declare function createOIMCollectionKit<TEntity extends object, TPk extends TOIMPk>(queue: OIMEventQueue, opts?: TOIMReactiveCollectionFactoryOptions<TEntity, TPk>): TOIMCollectionKit<TEntity, TPk>;
2457
+ declare function createOIMCollectionKit<TEntity extends object, TPk extends TOIMKey>(queue: OIMEventQueue, opts?: TOIMReactiveCollectionFactoryOptions<TEntity, TPk>): TOIMCollectionKit<TEntity, TPk>;
1774
2458
 
1775
2459
  type TOIMFieldKey<TEntity extends object> = keyof TEntity & string;
1776
2460
  /**
@@ -1781,7 +2465,7 @@ type TOIMFieldKey<TEntity extends object> = keyof TEntity & string;
1781
2465
  * DX: if the underlying collection is mutated directly, we detect it via collection
1782
2466
  * update events and infer changed fields by diffing the last observed entity snapshot.
1783
2467
  */
1784
- declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOIMPk> {
2468
+ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOIMKey> {
1785
2469
  readonly collection: OIMCollection<TEntity, TPk>;
1786
2470
  private readonly selectPk;
1787
2471
  private readonly unsubscribeAfterFlush;
@@ -1866,7 +2550,7 @@ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOI
1866
2550
  * The output is itself an {@link IOIMOrderedListCommandSource}, so maps chain:
1867
2551
  * `source.map(...)` → `.map(...)`.
1868
2552
  */
1869
- declare class OIMOrderedListMappedCommandStream<TKey extends TOIMPk, TOut, TIn> implements IOIMOrderedListCommandSource<TKey, TOut> {
2553
+ declare class OIMOrderedListMappedCommandStream<TKey extends TOIMKey, TOut, TIn> implements IOIMOrderedListCommandSource<TKey, TOut> {
1870
2554
  private readonly source;
1871
2555
  private readonly create;
1872
2556
  /** Per-key positional mirror of the mapped elements. */
@@ -1902,7 +2586,7 @@ declare class OIMOrderedListMappedCommandStream<TKey extends TOIMPk, TOut, TIn>
1902
2586
  * });
1903
2587
  * ```
1904
2588
  */
1905
- declare function createOIMOrderedListMappedCommandStream<TKey extends TOIMPk, TIn, TOut>(source: IOIMOrderedListCommandSource<TKey, TIn>, create: (item: TIn) => TOut): OIMOrderedListMappedCommandStream<TKey, TOut, TIn>;
2589
+ declare function createOIMOrderedListMappedCommandStream<TKey extends TOIMKey, TIn, TOut>(source: IOIMOrderedListCommandSource<TKey, TIn>, create: (item: TIn) => TOut): OIMOrderedListMappedCommandStream<TKey, TOut, TIn>;
1906
2590
 
1907
2591
  /**
1908
2592
  * Minimal read/subscribe surface a keyed index exposes for slot mapping:
@@ -1912,7 +2596,7 @@ declare function createOIMOrderedListMappedCommandStream<TKey extends TOIMPk, TI
1912
2596
  * `OIMReactiveIndexArrayBased` (slots as a `readonly` array) satisfy it
1913
2597
  * structurally — a `Set` and an array are both `Iterable`.
1914
2598
  */
1915
- interface IOIMIndexSlotSource<TKey extends TOIMPk, TPk extends TOIMPk> extends IOIMKeyedSubscription<TKey> {
2599
+ interface IOIMIndexSlotSource<TKey extends TOIMKey, TPk extends TOIMKey> extends IOIMKeyedSubscription<TKey> {
1916
2600
  getSlotsByKey(key: TKey): Iterable<TOIMAnyEntitySlot<TPk>>;
1917
2601
  }
1918
2602
 
@@ -1935,7 +2619,7 @@ interface IOIMIndexSlotSource<TKey extends TOIMPk, TPk extends TOIMPk> extends I
1935
2619
  * This is a thin wrapper: it holds no queue and no standing subscription of its
1936
2620
  * own — `subscribeOnKey` is a passthrough to the index.
1937
2621
  */
1938
- declare class OIMIndexSlotMap<TKey extends TOIMPk, TPk extends TOIMPk, TMapped> {
2622
+ declare class OIMIndexSlotMap<TKey extends TOIMKey, TPk extends TOIMKey, TMapped> {
1939
2623
  private readonly index;
1940
2624
  private readonly create;
1941
2625
  private readonly cache;
@@ -1974,7 +2658,7 @@ declare class OIMIndexSlotMap<TKey extends TOIMPk, TPk extends TOIMPk, TMapped>
1974
2658
  * }
1975
2659
  * ```
1976
2660
  */
1977
- declare function createOIMIndexSlotMap<TKey extends TOIMPk, TPk extends TOIMPk, TMapped>(index: IOIMIndexSlotSource<TKey, TPk>, create: (slot: TOIMAnyEntitySlot<TPk>) => TMapped): OIMIndexSlotMap<TKey, TPk, TMapped>;
2661
+ declare function createOIMIndexSlotMap<TKey extends TOIMKey, TPk extends TOIMKey, TMapped>(index: IOIMIndexSlotSource<TKey, TPk>, create: (slot: TOIMAnyEntitySlot<TPk>) => TMapped): OIMIndexSlotMap<TKey, TPk, TMapped>;
1978
2662
 
1979
2663
  /**
1980
2664
  * Minimal read/subscribe surface a keyless (whole-collection) index exposes for
@@ -1985,7 +2669,7 @@ declare function createOIMIndexSlotMap<TKey extends TOIMPk, TPk extends TOIMPk,
1985
2669
  * `OIMReactiveGlobalIndexArrayBased` (slots as a `readonly` array) satisfy it
1986
2670
  * structurally — a `Set` and an array are both `Iterable`.
1987
2671
  */
1988
- interface IOIMGlobalIndexSlotSource<TPk extends TOIMPk> extends IOIMSubscription {
2672
+ interface IOIMGlobalIndexSlotSource<TPk extends TOIMKey> extends IOIMSubscription {
1989
2673
  getSlots(): Iterable<TOIMAnyEntitySlot<TPk>>;
1990
2674
  }
1991
2675
 
@@ -2007,7 +2691,7 @@ interface IOIMGlobalIndexSlotSource<TPk extends TOIMPk> extends IOIMSubscription
2007
2691
  * Thin wrapper: no queue, no standing subscription of its own — `subscribe` is a
2008
2692
  * passthrough to the index.
2009
2693
  */
2010
- declare class OIMGlobalIndexSlotMap<TPk extends TOIMPk, TMapped> {
2694
+ declare class OIMGlobalIndexSlotMap<TPk extends TOIMKey, TMapped> {
2011
2695
  private readonly index;
2012
2696
  private readonly create;
2013
2697
  private readonly cache;
@@ -2044,7 +2728,7 @@ declare class OIMGlobalIndexSlotMap<TPk extends TOIMPk, TMapped> {
2044
2728
  * }
2045
2729
  * ```
2046
2730
  */
2047
- declare function createOIMGlobalIndexSlotMap<TPk extends TOIMPk, TMapped>(index: IOIMGlobalIndexSlotSource<TPk>, create: (slot: TOIMAnyEntitySlot<TPk>) => TMapped): OIMGlobalIndexSlotMap<TPk, TMapped>;
2731
+ declare function createOIMGlobalIndexSlotMap<TPk extends TOIMKey, TMapped>(index: IOIMGlobalIndexSlotSource<TPk>, create: (slot: TOIMAnyEntitySlot<TPk>) => TMapped): OIMGlobalIndexSlotMap<TPk, TMapped>;
2048
2732
 
2049
2733
  /**
2050
2734
  * Options for {@link OIMOrderedListCommandStreamDiffDriven}.
@@ -2082,7 +2766,7 @@ type TOIMOrderedListDiffOptions = {
2082
2766
  * worst case (an index scan per placed item), acceptable for the moderate bucket
2083
2767
  * sizes indexes produce, where it runs only on an actual change.
2084
2768
  */
2085
- declare function diffOrderedListByPk<TPk extends TOIMPk, TItem extends {
2769
+ declare function diffOrderedListByPk<TPk extends TOIMKey, TItem extends {
2086
2770
  pk: TPk;
2087
2771
  }>(prev: readonly TItem[], next: readonly TItem[]): TOIMOrderedListCommand<TItem>[];
2088
2772
 
@@ -2104,7 +2788,7 @@ declare function diffOrderedListByPk<TPk extends TOIMPk, TItem extends {
2104
2788
  * `IOIMOrderedListCommandSource`, so it consumes exactly like the writer stream
2105
2789
  * and composes with `createOIMOrderedListMappedCommandStream`.
2106
2790
  */
2107
- 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>> {
2791
+ declare class OIMOrderedListCommandStreamDiffDriven<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object, TIndex extends OIMIndexArrayBased<TKey, TPk> = OIMIndexArrayBased<TKey, TPk>> extends OIMOrderedListCommandBuffer<TKey, TOIMEntitySlot<TEntity, TPk>> {
2108
2792
  private readonly index;
2109
2793
  private readonly resetThreshold;
2110
2794
  private readonly prevByKey;
@@ -2134,7 +2818,7 @@ declare class OIMOrderedListCommandStreamDiffDriven<TKey extends TOIMPk, TPk ext
2134
2818
  * );
2135
2819
  * ```
2136
2820
  */
2137
- 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>;
2821
+ declare function createOIMOrderedListCommandStreamDiffDriven<TKey extends TOIMKey, TPk extends TOIMKey, 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>;
2138
2822
 
2139
2823
  /**
2140
2824
  * Animation frame-based scheduler that executes flushes synchronized with the browser's repaint cycle.
@@ -2278,18 +2962,18 @@ type TOIMIndexKey = string | number | bigint;
2278
2962
 
2279
2963
  /**
2280
2964
  * Configuration options for Set-based index instances */
2281
- type TOIMIndexOptionsSetBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> = {
2965
+ type TOIMIndexOptionsSetBased<TIndexKey extends TOIMKey, TPk extends TOIMKey> = {
2282
2966
  comparePks?: TOIMIndexComparator<TPk>;
2283
2967
  store?: OIMIndexStoreSetBased<TIndexKey, TPk>;
2284
2968
  };
2285
2969
  /**
2286
2970
  * Configuration options for Array-based index instances */
2287
- type TOIMIndexOptionsArrayBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> = {
2971
+ type TOIMIndexOptionsArrayBased<TIndexKey extends TOIMKey, TPk extends TOIMKey> = {
2288
2972
  comparePks?: TOIMIndexComparator<TPk>;
2289
2973
  store?: OIMIndexStoreArrayBased<TIndexKey, TPk>;
2290
2974
  };
2291
2975
 
2292
- type TOIMIndexPksUpdatePayload<TKey extends TOIMPk, TPk extends TOIMPk> = {
2976
+ type TOIMIndexPksUpdatePayload<TKey extends TOIMKey, TPk extends TOIMKey> = {
2293
2977
  key: TKey;
2294
2978
  pks: readonly TPk[];
2295
2979
  };
@@ -2317,7 +3001,7 @@ type TOIMComputedOptions<TValue> = {
2317
3001
  compare?: (a: TValue, b: TValue) => boolean;
2318
3002
  };
2319
3003
 
2320
- type TOIMComputedUpdatePayload<TKey extends TOIMPk> = {
3004
+ type TOIMComputedUpdatePayload<TKey extends TOIMKey> = {
2321
3005
  keys: readonly TKey[];
2322
3006
  };
2323
3007
 
@@ -2389,7 +3073,7 @@ declare class OIMEffect {
2389
3073
  private readonly onAfterFlush;
2390
3074
  }
2391
3075
 
2392
- declare class OIMEffectDependencyKeyed<TKey extends TOIMPk> implements IOIMEffectDependency {
3076
+ declare class OIMEffectDependencyKeyed<TKey extends TOIMKey> implements IOIMEffectDependency {
2393
3077
  readonly source: IOIMKeyedSubscription<TKey>;
2394
3078
  private readonly key;
2395
3079
  private readonly keys;
@@ -2405,7 +3089,7 @@ declare class OIMEffectDependencyKeyedObject<TKey extends string, TValue> implem
2405
3089
  subscribe(onUpdate: () => void): () => void;
2406
3090
  }
2407
3091
 
2408
- declare class OIMEffectDependencyKeyedCollection<TEntity extends object, TPk extends TOIMPk> implements IOIMEffectDependency {
3092
+ declare class OIMEffectDependencyKeyedCollection<TEntity extends object, TPk extends TOIMKey> implements IOIMEffectDependency {
2409
3093
  private readonly dep;
2410
3094
  constructor(collection: OIMReactiveCollection<TEntity, TPk>, pk: TPk);
2411
3095
  constructor(collection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]);
@@ -2413,7 +3097,7 @@ declare class OIMEffectDependencyKeyedCollection<TEntity extends object, TPk ext
2413
3097
  subscribe(onUpdate: () => void): () => void;
2414
3098
  }
2415
3099
 
2416
- declare class OIMEffectDependencyKeyedIndex<TKey extends TOIMPk> implements IOIMEffectDependency {
3100
+ declare class OIMEffectDependencyKeyedIndex<TKey extends TOIMKey> implements IOIMEffectDependency {
2417
3101
  private readonly dep;
2418
3102
  constructor(index: IOIMKeyedSubscription<TKey>, key: TKey);
2419
3103
  constructor(index: IOIMKeyedSubscription<TKey>, keys: readonly TKey[]);
@@ -2437,14 +3121,14 @@ declare class OIMEffectDependencyComputed implements IOIMEffectDependency {
2437
3121
  subscribe(onUpdate: () => void): () => void;
2438
3122
  }
2439
3123
 
2440
- declare class OIMCollectionByPkSelector<TEntity extends object, TPk extends TOIMPk> extends OIMSelector<TEntity | undefined> {
3124
+ declare class OIMCollectionByPkSelector<TEntity extends object, TPk extends TOIMKey> extends OIMSelector<TEntity | undefined> {
2441
3125
  private readonly collection;
2442
3126
  private readonly pk;
2443
3127
  constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pk: TPk);
2444
3128
  getValue(): TEntity | undefined;
2445
3129
  }
2446
3130
 
2447
- declare class OIMCollectionByPksSelector<TEntity extends object, TPk extends TOIMPk> extends OIMSelector<readonly (TEntity | undefined)[]> {
3131
+ declare class OIMCollectionByPksSelector<TEntity extends object, TPk extends TOIMKey> extends OIMSelector<readonly (TEntity | undefined)[]> {
2448
3132
  private readonly collection;
2449
3133
  private readonly pks;
2450
3134
  constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]);
@@ -2467,14 +3151,14 @@ declare class OIMObjectValuesByKeysSelector<TKey extends string, TValue> extends
2467
3151
  protected areEqual(prev: readonly (TValue | undefined)[], next: readonly (TValue | undefined)[]): boolean;
2468
3152
  }
2469
3153
 
2470
- declare class OIMIndexPksByKeySetBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<Set<TPk>> {
3154
+ declare class OIMIndexPksByKeySetBasedSelector<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<Set<TPk>> {
2471
3155
  private readonly reactiveIndex;
2472
3156
  private readonly key;
2473
3157
  constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey);
2474
3158
  getValue(): Set<TPk>;
2475
3159
  }
2476
3160
 
2477
- declare class OIMIndexPksByKeyArrayBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
3161
+ declare class OIMIndexPksByKeyArrayBasedSelector<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
2478
3162
  private readonly reactiveIndex;
2479
3163
  private readonly key;
2480
3164
  constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey);
@@ -2482,7 +3166,7 @@ declare class OIMIndexPksByKeyArrayBasedSelector<TKey extends TOIMPk, TPk extend
2482
3166
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
2483
3167
  }
2484
3168
 
2485
- declare class OIMIndexPksByKeysSetBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
3169
+ declare class OIMIndexPksByKeysSetBasedSelector<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
2486
3170
  private readonly reactiveIndex;
2487
3171
  private readonly keys;
2488
3172
  constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
@@ -2490,7 +3174,7 @@ declare class OIMIndexPksByKeysSetBasedSelector<TKey extends TOIMPk, TPk extends
2490
3174
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
2491
3175
  }
2492
3176
 
2493
- declare class OIMIndexPksByKeysArrayBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
3177
+ declare class OIMIndexPksByKeysArrayBasedSelector<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
2494
3178
  private readonly reactiveIndex;
2495
3179
  private readonly keys;
2496
3180
  constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
@@ -2498,7 +3182,7 @@ declare class OIMIndexPksByKeysArrayBasedSelector<TKey extends TOIMPk, TPk exten
2498
3182
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
2499
3183
  }
2500
3184
 
2501
- declare class OIMEntitiesByIndexKeySetBasedSelector<TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
3185
+ declare class OIMEntitiesByIndexKeySetBasedSelector<TEntity extends object, TPk extends TOIMKey, TKey extends TOIMKey, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
2502
3186
  private readonly collection;
2503
3187
  private readonly reactiveIndex;
2504
3188
  private readonly key;
@@ -2507,7 +3191,7 @@ declare class OIMEntitiesByIndexKeySetBasedSelector<TEntity extends object, TPk
2507
3191
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
2508
3192
  }
2509
3193
 
2510
- declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
3194
+ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TPk extends TOIMKey, TKey extends TOIMKey, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
2511
3195
  private readonly collection;
2512
3196
  private readonly reactiveIndex;
2513
3197
  private readonly key;
@@ -2516,7 +3200,7 @@ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TP
2516
3200
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
2517
3201
  }
2518
3202
 
2519
- declare class OIMEntitiesByGlobalIndexSetBasedSelector<TEntity extends object, TPk extends TOIMPk, TIndex extends OIMGlobalIndexSetBased<TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
3203
+ declare class OIMEntitiesByGlobalIndexSetBasedSelector<TEntity extends object, TPk extends TOIMKey, TIndex extends OIMGlobalIndexSetBased<TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
2520
3204
  private readonly collection;
2521
3205
  private readonly reactiveIndex;
2522
3206
  constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveGlobalIndexSetBased<TPk, TIndex>);
@@ -2524,7 +3208,7 @@ declare class OIMEntitiesByGlobalIndexSetBasedSelector<TEntity extends object, T
2524
3208
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
2525
3209
  }
2526
3210
 
2527
- declare class OIMEntitiesByGlobalIndexArrayBasedSelector<TEntity extends object, TPk extends TOIMPk, TIndex extends OIMGlobalIndexArrayBased<TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
3211
+ declare class OIMEntitiesByGlobalIndexArrayBasedSelector<TEntity extends object, TPk extends TOIMKey, TIndex extends OIMGlobalIndexArrayBased<TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
2528
3212
  private readonly collection;
2529
3213
  private readonly reactiveIndex;
2530
3214
  constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveGlobalIndexArrayBased<TPk, TIndex>);
@@ -2532,4 +3216,4 @@ declare class OIMEntitiesByGlobalIndexArrayBasedSelector<TEntity extends object,
2532
3216
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
2533
3217
  }
2534
3218
 
2535
- export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMGlobalIndexSlotSource, 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, OIMGlobalIndexSlotMap, 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, createOIMGlobalIndexSlotMap, createOIMIndexSlotMap, createOIMOrderedListCommandStreamDiffDriven, createOIMOrderedListMappedCommandStream, diffOrderedListByPk };
3219
+ export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierBucketStore, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMDisposable, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMGlobalIndexSlotSource, type IOIMIndexSlotSource, type IOIMIndexStore, type IOIMKeyDomain, type IOIMKeyedMap, type IOIMKeyedSet, type IOIMKeyedUpdateEmitter, type IOIMOrderedListCommandSource, type IOIMPkCodec, type IOIMSingleUpdateEmitter, type IOIMSubscribable, type IOIMSubscription, OIMBucketCarrierResolver, OIMCarrierKeyedEmitter, OIMCarrierSingleEmitter, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMCollectionStoreTrieDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionGlobalIndexArrayBased, OIMDerivedCollectionGlobalIndexSetBased, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMDisposeScope, 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, OIMGlobalIndexSlotMap, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexSlotMap, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMIndexStoreTrieDrivenArrayBased, OIMIndexStoreTrieDrivenSetBased, OIMKeyDomainNative, OIMKeyDomainTrie, OIMKeyPathCarrierResolver, OIMKeyedBucketArrayBased, OIMKeyedBucketSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandBuffer, OIMOrderedListCommandStream, OIMOrderedListCommandStreamDiffDriven, OIMOrderedListMappedCommandStream, OIMPkCodecKeyPath, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionGlobalIndexManualArrayBased, OIMReactiveCollectionGlobalIndexManualSetBased, OIMReactiveCollectionIndexCompositeTrieArrayBased, OIMReactiveCollectionIndexCompositeTrieSetBased, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveGlobalIndex, OIMReactiveGlobalIndexArrayBased, OIMReactiveGlobalIndexManualArrayBased, OIMReactiveGlobalIndexManualSetBased, OIMReactiveGlobalIndexSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, OIMTrieMap, OIMTrieSet, type TOIMAnyEntitySlot, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionGlobalIndexArrayBasedOptions, type TOIMCollectionGlobalIndexSetBasedOptions, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexCompositeArrayBasedOptions, type TOIMCollectionIndexCompositeSetBasedOptions, 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 TOIMDisposable, 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 TOIMKey, type TOIMKeyPath, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMOrderedListDiffOptions, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsCompositeArrayIndexOptions, type TOIMRelationsCompositeSetIndexOptions, 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, createOIMDisposeScope, createOIMGlobalIndexSlotMap, createOIMIndexSlotMap, createOIMOrderedListCommandStreamDiffDriven, createOIMOrderedListMappedCommandStream, diffOrderedListByPk };