@oimdb/core 3.7.0 → 3.9.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
+ * provider): 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,10 @@ 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 TOIMEntitySlotGetter<TPk extends TOIMKey> = (pk: TPk) => TOIMAnyEntitySlot<TPk> | undefined;
16
43
 
17
- declare abstract class OIMCollectionStore<TEntity extends object, TPk extends TOIMPk> {
44
+ declare abstract class OIMCollectionStore<TEntity extends object, TPk extends TOIMKey> {
18
45
  abstract setOneByPk(pk: TPk, entity: TEntity): TOIMEntitySlot<TEntity, TPk>;
19
46
  abstract getSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk> | undefined;
20
47
  /**
@@ -70,7 +97,7 @@ interface TOIMIndexUpdatePayload<TKey> {
70
97
  /**
71
98
  * Comparator function for index primary key arrays.
72
99
  * 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;
100
+ type TOIMIndexComparator<TPk extends TOIMKey> = (existingPks: readonly TPk[], newPks: readonly TPk[]) => boolean;
74
101
 
75
102
  interface IOIMIndexStore<TKey, TBucket> {
76
103
  setOneByKey(key: TKey, bucket: TBucket): void;
@@ -83,7 +110,7 @@ interface IOIMIndexStore<TKey, TBucket> {
83
110
  countAll(): number;
84
111
  clear(): void;
85
112
  }
86
- declare abstract class OIMIndex<TKey extends TOIMPk, TPk extends TOIMPk, TBucket extends Iterable<TOIMAnyEntitySlot<TPk>>> {
113
+ declare abstract class OIMIndex<TKey extends TOIMKey, TPk extends TOIMKey, TBucket extends Iterable<TOIMAnyEntitySlot<TPk>>> {
87
114
  protected readonly comparePks?: TOIMIndexComparator<TPk>;
88
115
  protected readonly store: IOIMIndexStore<TKey, TBucket>;
89
116
  readonly emitter: OIMEventEmitter<{
@@ -119,28 +146,131 @@ declare abstract class OIMIndex<TKey extends TOIMPk, TPk extends TOIMPk, TBucket
119
146
  protected slotsToEntities<TEntity extends object>(slots: Iterable<TOIMAnyEntitySlot<TPk>>): (TEntity | undefined)[];
120
147
  }
121
148
 
122
- declare abstract class OIMIndexStoreSetBased<TKey extends TOIMPk, TPk extends TOIMPk> {
149
+ /**
150
+ * A carrier that can hold per-key subscribers directly on itself, so the keyed
151
+ * emitter delivers without a per-key map lookup. Implemented by the entity slot
152
+ * (collection carrier) and the index bucket (index carrier).
153
+ */
154
+ interface IOIMSubscribable {
155
+ subscribers?: Set<() => void>;
156
+ /**
157
+ * Dirty-batch membership flag, owned by the keyed emitter. `true` while the
158
+ * carrier sits in the pending flush batch — lets the emitter dedup marks with
159
+ * an O(1) boolean check instead of a `Set` identity-hash lookup. Reset to
160
+ * `false` as the carrier is delivered (or on flush teardown). Do not read or
161
+ * write outside the emitter.
162
+ */
163
+ dirty?: boolean;
164
+ }
165
+
166
+ /**
167
+ * The Map surface the PK / index-key axis needs, abstracted so the concrete
168
+ * keying strategy is pluggable. A native `Map` satisfies this interface
169
+ * structurally (so the primitive default is a plain `Map`, zero wrapper), while
170
+ * a composite key uses a trie-backed implementation (`OIMTrieMap`) that matches
171
+ * array keys by content instead of by reference.
172
+ */
173
+ interface IOIMKeyedMap<TKey, TValue> {
174
+ get(key: TKey): TValue | undefined;
175
+ set(key: TKey, value: TValue): void;
176
+ has(key: TKey): boolean;
177
+ delete(key: TKey): boolean;
178
+ readonly size: number;
179
+ keys(): IterableIterator<TKey>;
180
+ entries(): IterableIterator<[TKey, TValue]>;
181
+ values(): IterableIterator<TValue>;
182
+ clear(): void;
183
+ }
184
+
185
+ /**
186
+ * A set-based index bucket that is ALSO its own subscription carrier AND holds
187
+ * its own pk→slot membership.
188
+ *
189
+ * It extends `Set<slot>`, so every reader that treats a bucket as a `Set`
190
+ * (iteration, `size`, `has`, `add`, `delete`) is unchanged — a `Set` subclass is
191
+ * a `Set`. On top of that:
192
+ * - it carries `subscribers` + `dirty` (`IOIMSubscribable`) and its own `key`,
193
+ * so the keyed emitter delivers straight off the bucket the writer already
194
+ * holds — O(1), no key→carrier map/trie (bucket-as-carrier);
195
+ * - it carries an optional `membership` (pk → slot) so pk-oriented writes
196
+ * (`setPks`/`addPks`/`removePks`) dedup and remove by pk WITHOUT a second
197
+ * key-indexed structure. One `getOrReserveBucket` walk now serves both the
198
+ * slots and the membership — halving the trie walks for a composite key.
199
+ */
200
+ declare class OIMKeyedBucketSetBased<TKey extends TOIMKey, TPk extends TOIMKey> extends Set<TOIMAnyEntitySlot<TPk>> implements IOIMSubscribable {
201
+ readonly key: TKey;
202
+ subscribers?: Set<() => void>;
203
+ dirty?: boolean;
204
+ membership?: IOIMKeyedMap<TPk, TOIMAnyEntitySlot<TPk>>;
205
+ constructor(key: TKey);
206
+ hasSubscribers(): boolean;
207
+ /** Clearing the slot set also clears the pk membership — they stay in sync. */
208
+ clear(): void;
209
+ }
210
+
211
+ declare abstract class OIMIndexStoreSetBased<TKey extends TOIMKey, TPk extends TOIMKey> {
123
212
  abstract setOneByKey(key: TKey, slots: Set<TOIMAnyEntitySlot<TPk>>): void;
124
213
  abstract removeOneByKey(key: TKey): void;
125
214
  abstract removeManyByKeys(keys: readonly TKey[]): void;
215
+ /** The live bucket for `key` (undefined if none / empty-reserved). */
126
216
  abstract getOneByKey(key: TKey): Set<TOIMAnyEntitySlot<TPk>> | undefined;
127
217
  abstract getManyByKeys(keys: readonly TKey[]): Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
128
218
  abstract getAllKeys(): TKey[];
129
219
  abstract getAll(): Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
130
220
  abstract countAll(): number;
131
221
  abstract clear(): void;
222
+ /** Bucket for `key` (live or reserved), creating a reserved empty one if none. */
223
+ abstract getOrReserveBucket(key: TKey): OIMKeyedBucketSetBased<TKey, TPk>;
224
+ /** Existing bucket (live or reserved) without creating one — for delivery. */
225
+ abstract findBucket(key: TKey): OIMKeyedBucketSetBased<TKey, TPk> | undefined;
226
+ /** Promote a now-non-empty bucket into the live set. */
227
+ abstract retainBucket(bucket: OIMKeyedBucketSetBased<TKey, TPk>): void;
228
+ /** A now-empty bucket: keep it (reserved) if subscribed, else drop it. */
229
+ abstract releaseBucket(bucket: OIMKeyedBucketSetBased<TKey, TPk>): void;
230
+ /** Last subscriber left: drop the key's bucket if it is empty & unsubscribed. */
231
+ abstract dropIfReserved(key: TKey): void;
232
+ }
233
+
234
+ /**
235
+ * An array-based (ordered) index bucket that is ALSO its own subscription
236
+ * carrier — the array counterpart of `OIMKeyedBucketSetBased`.
237
+ *
238
+ * It extends `Array<slot>`, so every reader that treats a bucket as an ordered
239
+ * slot array (iteration, `length`, index access, `push`, `filter`) is unchanged.
240
+ * On top of that it carries `subscribers` + `dirty` (`IOIMSubscribable`) and its
241
+ * own `key`, so the keyed emitter delivers straight off the bucket the writer
242
+ * already holds (O(1), no key→carrier lookup).
243
+ *
244
+ * `Symbol.species` is `Array`, so derived arrays (`filter`/`slice`/`map`) are
245
+ * plain arrays — never stray carrier buckets.
246
+ */
247
+ declare class OIMKeyedBucketArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> extends Array<TOIMAnyEntitySlot<TPk>> implements IOIMSubscribable {
248
+ readonly key: TKey;
249
+ subscribers?: Set<() => void>;
250
+ dirty?: boolean;
251
+ static get [Symbol.species](): ArrayConstructor;
252
+ constructor(key: TKey);
253
+ hasSubscribers(): boolean;
254
+ /** Empty the bucket in place (Array has no `clear`). */
255
+ clear(): void;
132
256
  }
133
257
 
134
- declare abstract class OIMIndexStoreArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> {
258
+ declare abstract class OIMIndexStoreArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> {
135
259
  abstract setOneByKey(key: TKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
136
260
  abstract removeOneByKey(key: TKey): void;
137
261
  abstract removeManyByKeys(keys: readonly TKey[]): void;
262
+ /** The live bucket for `key` (undefined if none / empty-reserved). */
138
263
  abstract getOneByKey(key: TKey): TOIMAnyEntitySlot<TPk>[] | undefined;
139
264
  abstract getManyByKeys(keys: readonly TKey[]): Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
140
265
  abstract getAllKeys(): TKey[];
141
266
  abstract getAll(): Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
142
267
  abstract countAll(): number;
143
268
  abstract clear(): void;
269
+ abstract getOrReserveBucket(key: TKey): OIMKeyedBucketArrayBased<TKey, TPk>;
270
+ abstract findBucket(key: TKey): OIMKeyedBucketArrayBased<TKey, TPk> | undefined;
271
+ abstract retainBucket(bucket: OIMKeyedBucketArrayBased<TKey, TPk>): void;
272
+ abstract releaseBucket(bucket: OIMKeyedBucketArrayBased<TKey, TPk>): void;
273
+ abstract dropIfReserved(key: TKey): void;
144
274
  }
145
275
 
146
276
  declare enum EOIMEventQueueSchedulerEventType {
@@ -169,7 +299,12 @@ declare abstract class OIMEventQueueScheduler {
169
299
  protected flush(): void;
170
300
  }
171
301
 
172
- declare abstract class OIMIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndex<TKey, TPk, Set<TOIMAnyEntitySlot<TPk>>> {
302
+ declare abstract class OIMIndexSetBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndex<TKey, TPk, Set<TOIMAnyEntitySlot<TPk>>> {
303
+ /**
304
+ * The same store as the base `store`, narrowed to the set-based contract so
305
+ * the carrier-bucket lifecycle methods (`getOrReserveBucket`, …) are visible.
306
+ */
307
+ protected readonly setStore: OIMIndexStoreSetBased<TKey, TPk>;
173
308
  constructor(options?: {
174
309
  comparePks?: TOIMIndexComparator<TPk>;
175
310
  store?: OIMIndexStoreSetBased<TKey, TPk>;
@@ -180,10 +315,16 @@ declare abstract class OIMIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk>
180
315
  getSlotsByKey(key: TKey): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
181
316
  getSlotsByKeys(keys: readonly TKey[]): Map<TKey, ReadonlySet<TOIMAnyEntitySlot<TPk>>>;
182
317
  protected slotsToPks(slots: Iterable<TOIMAnyEntitySlot<TPk>>): Set<TPk>;
183
- protected setSlotsWithComparison(key: TKey, newSlots: Set<TOIMAnyEntitySlot<TPk>>): boolean;
318
+ /**
319
+ * True if a comparator is set and considers `bucket`'s current pks equal to
320
+ * `newSlots` — i.e. a `setSlots` would be a no-op and should not emit.
321
+ */
322
+ protected bucketMatchesComparator(bucket: ReadonlySet<TOIMAnyEntitySlot<TPk>>, newSlots: ReadonlySet<TOIMAnyEntitySlot<TPk>>): boolean;
184
323
  }
185
324
 
186
- declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndex<TKey, TPk, TOIMAnyEntitySlot<TPk>[]> {
325
+ declare abstract class OIMIndexArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndex<TKey, TPk, TOIMAnyEntitySlot<TPk>[]> {
326
+ /** The same store as `store`, narrowed to expose the carrier-bucket lifecycle. */
327
+ protected readonly arrayStore: OIMIndexStoreArrayBased<TKey, TPk>;
187
328
  constructor(options?: {
188
329
  comparePks?: TOIMIndexComparator<TPk>;
189
330
  store?: OIMIndexStoreArrayBased<TKey, TPk>;
@@ -194,7 +335,11 @@ declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMP
194
335
  getSlotsByKey(key: TKey): readonly TOIMAnyEntitySlot<TPk>[];
195
336
  getSlotsByKeys(keys: readonly TKey[]): Map<TKey, readonly TOIMAnyEntitySlot<TPk>[]>;
196
337
  protected slotsToPks(slots: readonly TOIMAnyEntitySlot<TPk>[]): TPk[];
197
- protected setSlotsWithComparison(key: TKey, newSlots: TOIMAnyEntitySlot<TPk>[]): boolean;
338
+ /**
339
+ * True if a comparator is set and considers `bucket`'s pks equal to
340
+ * `newSlots` — i.e. a `setSlots` would be a no-op and should not emit.
341
+ */
342
+ protected bucketMatchesComparator(bucket: readonly TOIMAnyEntitySlot<TPk>[], newSlots: readonly TOIMAnyEntitySlot<TPk>[]): boolean;
198
343
  }
199
344
 
200
345
  /**
@@ -206,13 +351,18 @@ declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMP
206
351
  * against this interface lets either back the node without leaking the carrier
207
352
  * generic into the node's signatures.
208
353
  */
209
- interface IOIMKeyedUpdateEmitter<TKey extends TOIMPk> {
354
+ interface IOIMKeyedUpdateEmitter<TKey extends TOIMKey> {
210
355
  subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
211
356
  subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
212
357
  unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
213
358
  unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
214
359
  markUpdatedKey(key: TKey): void;
215
360
  markUpdatedKeys(keys: readonly TKey[]): void;
361
+ /**
362
+ * Fast path: mark a carrier the writer already holds (an entity slot or an
363
+ * index bucket), skipping the key→carrier lookup entirely. O(1).
364
+ */
365
+ markUpdatedCarrier(carrier: IOIMSubscribable): void;
216
366
  hasSubscriptions(): boolean;
217
367
  getHandlerCount(key: TKey): number;
218
368
  getMetrics(): {
@@ -289,15 +439,97 @@ declare class OIMEventQueue {
289
439
  destroy(): void;
290
440
  }
291
441
 
292
- interface IOIMKeyedSubscription<TKey extends TOIMPk> {
442
+ /**
443
+ * Resolves a key to its carrier — the object that holds the key's subscribers.
444
+ * `getOrReserveCarrier` is used on subscribe (creates the carrier if absent so a
445
+ * subscription can exist before its data); `findCarrier` resolves an existing
446
+ * carrier for delivery/unsubscribe without creating one.
447
+ *
448
+ * Collection carrier = the entity slot (by pk); index carrier = the bucket
449
+ * (by index key).
450
+ */
451
+ interface IOIMCarrierProvider<TKey extends TOIMKey, TCarrier> {
452
+ getOrReserveCarrier(key: TKey): TCarrier;
453
+ findCarrier(key: TKey): TCarrier | undefined;
454
+ /**
455
+ * Optional: called when a carrier loses its last subscriber, so a carrierProvider
456
+ * that owns standalone carriers (e.g. the index's key→carrier map) can prune
457
+ * it and not leak the key space. Providers whose carriers are owned
458
+ * elsewhere (e.g. the collection's slots) leave this unset.
459
+ */
460
+ onCarrierEmptied?(carrier: TCarrier): void;
461
+ }
462
+ /**
463
+ * Keyed (per-key) pub/sub that stores handlers ON the carrier object
464
+ * (`carrier.subscribers`) instead of a `Map<key, handlers>`. The hot path —
465
+ * marking a written carrier dirty and delivering — needs no per-key map lookup
466
+ * or hashing: the writer already holds the carrier.
467
+ *
468
+ * Same public surface as `OIMUpdateEventEmitter` (queue delivery) plus a fast
469
+ * `markUpdatedCarrier(carrier)`, so it is a drop-in for the collection's and
470
+ * index's keyed emitter. Reused with carrier = slot (collection) or carrier =
471
+ * bucket (index).
472
+ */
473
+ declare class OIMCarrierKeyedEmitter<TKey extends TOIMKey, TCarrier extends IOIMSubscribable> implements IOIMKeyedUpdateEmitter<TKey> {
474
+ private readonly queue;
475
+ private readonly carrierProvider;
476
+ private readonly subscribedCarriers;
477
+ private dirtyCarriers;
478
+ private isFlushEnqueued;
479
+ constructor(queue: OIMEventQueue, carrierProvider: IOIMCarrierProvider<TKey, TCarrier>);
293
480
  subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
294
481
  subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
482
+ unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
483
+ unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
484
+ private addHandler;
485
+ private removeHandler;
486
+ /** Fast path: the writer already holds the carrier. */
487
+ markUpdatedCarrier(carrier: TCarrier): void;
488
+ markUpdatedKey(key: TKey): void;
489
+ markUpdatedKeys(keys: readonly TKey[]): void;
490
+ markAllUpdated(): void;
491
+ hasSubscriptions(): boolean;
492
+ getHandlerCount(key: TKey): number;
493
+ getMetrics(): {
494
+ totalKeys: number;
495
+ totalHandlers: number;
496
+ averageHandlersPerKey: number;
497
+ queueLength: number;
498
+ };
499
+ destroy(): void;
500
+ private assertNotInFlush;
501
+ private scheduleFlush;
502
+ private readonly onFlush;
503
+ private notify;
504
+ }
505
+
506
+ /**
507
+ * Carrier for a single index key: holds that key's subscribers + dirty flag
508
+ * (via `IOIMSubscribable`) so the keyed emitter delivers straight off the
509
+ * carrier with no per-key map lookup. Carries its own `key` so the provider can
510
+ * prune it from the key→carrier map when its last subscriber leaves.
511
+ */
512
+ interface IOIMKeyCarrier<TKey extends TOIMKey> extends IOIMSubscribable {
513
+ key: TKey;
295
514
  }
296
515
 
297
- declare abstract class OIMReactiveIndex<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndex<TKey, TPk, Iterable<TOIMAnyEntitySlot<TPk>>>> implements IOIMKeyedSubscription<TKey> {
516
+ interface IOIMKeyedSubscription<TKey extends TOIMKey> {
517
+ subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
518
+ subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
519
+ }
520
+
521
+ declare abstract class OIMReactiveIndex<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndex<TKey, TPk, Iterable<TOIMAnyEntitySlot<TPk>>>> implements IOIMKeyedSubscription<TKey> {
298
522
  readonly index: TIndex;
299
523
  protected readonly updateEmitter: IOIMKeyedUpdateEmitter<TKey>;
300
- constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex);
524
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex,
525
+ /**
526
+ * How to build the key→carrier carrierProvider backing the keyed emitter.
527
+ * Defaults to the native-`Map` carrierProvider used by every primitive-keyed
528
+ * index (its fast path is unchanged). A composite (trie-backed) index
529
+ * passes a carrierProvider that keys carriers by key path instead. Called once
530
+ * at construction — no per-operation cost.
531
+ */
532
+ createCarrierProvider?: () => IOIMCarrierProvider<TKey, IOIMKeyCarrier<TKey>>);
301
533
  getEntitiesByKey<TEntity extends object = object>(key: TKey): (TEntity | undefined)[];
302
534
  getEntitiesByKeys<TEntity extends object = object>(keys: readonly TKey[]): Map<TKey, (TEntity | undefined)[]>;
303
535
  hasKey(key: TKey): boolean;
@@ -327,16 +559,16 @@ declare abstract class OIMReactiveIndex<TKey extends TOIMPk, TPk extends TOIMPk,
327
559
  destroy(): void;
328
560
  }
329
561
 
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);
562
+ declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
563
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex, createCarrierProvider?: () => IOIMCarrierProvider<TKey, IOIMKeyCarrier<TKey>>);
332
564
  getPksByKey(key: TKey): Set<TPk>;
333
565
  getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
334
566
  getSlotsByKey(key: TKey): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
335
567
  getSlotsByKeys(keys: readonly TKey[]): Map<TKey, ReadonlySet<TOIMAnyEntitySlot<TPk>>>;
336
568
  }
337
569
 
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);
570
+ declare abstract class OIMReactiveIndexArrayBased<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
571
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex, createCarrierProvider?: () => IOIMCarrierProvider<TKey, IOIMKeyCarrier<TKey>>);
340
572
  getPksByKey(key: TKey): TPk[];
341
573
  getPksByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
342
574
  getSlotsByKey(key: TKey): readonly TOIMAnyEntitySlot<TPk>[];
@@ -364,7 +596,7 @@ declare abstract class OIMObjectStore<TKey extends string | number | symbol, TVa
364
596
  * anywhere on its surface. Concrete shape (ordered array vs unordered set) is
365
597
  * added by {@link OIMGlobalIndexArrayBased} / {@link OIMGlobalIndexSetBased}.
366
598
  */
367
- declare abstract class OIMGlobalIndex<TPk extends TOIMPk> {
599
+ declare abstract class OIMGlobalIndex<TPk extends TOIMKey> {
368
600
  protected readonly comparePks?: TOIMIndexComparator<TPk>;
369
601
  readonly emitter: OIMEventEmitter<{
370
602
  0: void;
@@ -392,7 +624,7 @@ declare abstract class OIMGlobalIndex<TPk extends TOIMPk> {
392
624
  * bucket over the whole collection. Mirrors {@link OIMIndexSetBased} minus the
393
625
  * key.
394
626
  */
395
- declare abstract class OIMGlobalIndexSetBased<TPk extends TOIMPk> extends OIMGlobalIndex<TPk> {
627
+ declare abstract class OIMGlobalIndexSetBased<TPk extends TOIMKey> extends OIMGlobalIndex<TPk> {
396
628
  protected slots: Set<TOIMAnyEntitySlot<TPk>>;
397
629
  constructor(options?: {
398
630
  comparePks?: TOIMIndexComparator<TPk>;
@@ -410,7 +642,7 @@ declare abstract class OIMGlobalIndexSetBased<TPk extends TOIMPk> extends OIMGlo
410
642
  * Array-based (ordered) keyless index. Holds a single `slot[]` bucket over the
411
643
  * whole collection. Mirrors {@link OIMIndexArrayBased} minus the key.
412
644
  */
413
- declare abstract class OIMGlobalIndexArrayBased<TPk extends TOIMPk> extends OIMGlobalIndex<TPk> {
645
+ declare abstract class OIMGlobalIndexArrayBased<TPk extends TOIMKey> extends OIMGlobalIndex<TPk> {
414
646
  protected slots: TOIMAnyEntitySlot<TPk>[];
415
647
  constructor(options?: {
416
648
  comparePks?: TOIMIndexComparator<TPk>;
@@ -437,7 +669,7 @@ interface IOIMSubscription {
437
669
  * The keyless pub/sub surface a reactive Global node needs from its update
438
670
  * emitter: subscribe + a batched "mark updated" delivery. The counterpart of
439
671
  * {@link IOIMKeyedUpdateEmitter}, but for exactly one carrier — so there is no
440
- * key parameter, no resolver, and no per-key map.
672
+ * key parameter, no provider, and no per-key map.
441
673
  */
442
674
  interface IOIMSingleUpdateEmitter extends IOIMSubscription {
443
675
  markUpdated(): void;
@@ -447,11 +679,11 @@ interface IOIMSingleUpdateEmitter extends IOIMSubscription {
447
679
 
448
680
  /**
449
681
  * Reactive wrapper around a keyless {@link OIMGlobalIndex}. Owns a single-carrier
450
- * emitter (no resolver, no key→carrier map), so `subscribe(handler)` is keyless
682
+ * emitter (no provider, no key→carrier map), so `subscribe(handler)` is keyless
451
683
  * and directly satisfies `IOIMSelectorSourceDependency`. Mirrors
452
684
  * {@link OIMReactiveIndex} minus the key.
453
685
  */
454
- declare abstract class OIMReactiveGlobalIndex<TPk extends TOIMPk, TIndex extends OIMGlobalIndex<TPk>> implements IOIMSubscription {
686
+ declare abstract class OIMReactiveGlobalIndex<TPk extends TOIMKey, TIndex extends OIMGlobalIndex<TPk>> implements IOIMSubscription {
455
687
  readonly index: TIndex;
456
688
  protected readonly updateEmitter: IOIMSingleUpdateEmitter;
457
689
  constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMSingleUpdateEmitter) => TIndex);
@@ -466,34 +698,39 @@ declare abstract class OIMReactiveGlobalIndex<TPk extends TOIMPk, TIndex extends
466
698
  destroy(): void;
467
699
  }
468
700
 
469
- declare abstract class OIMReactiveGlobalIndexSetBased<TPk extends TOIMPk, TIndex extends OIMGlobalIndexSetBased<TPk>> extends OIMReactiveGlobalIndex<TPk, TIndex> {
701
+ declare abstract class OIMReactiveGlobalIndexSetBased<TPk extends TOIMKey, TIndex extends OIMGlobalIndexSetBased<TPk>> extends OIMReactiveGlobalIndex<TPk, TIndex> {
470
702
  constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMSingleUpdateEmitter) => TIndex);
471
703
  getPks(): Set<TPk>;
472
704
  getSlots(): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
473
705
  }
474
706
 
475
- declare abstract class OIMReactiveGlobalIndexArrayBased<TPk extends TOIMPk, TIndex extends OIMGlobalIndexArrayBased<TPk>> extends OIMReactiveGlobalIndex<TPk, TIndex> {
707
+ declare abstract class OIMReactiveGlobalIndexArrayBased<TPk extends TOIMKey, TIndex extends OIMGlobalIndexArrayBased<TPk>> extends OIMReactiveGlobalIndex<TPk, TIndex> {
476
708
  constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMSingleUpdateEmitter) => TIndex);
477
709
  getPks(): TPk[];
478
710
  getSlots(): readonly TOIMAnyEntitySlot<TPk>[];
479
711
  }
480
712
 
481
- type TOIMPkSelector<TEntity extends object, TPk extends TOIMPk> = (entity: TEntity) => TPk;
713
+ type TOIMPkSelector<TEntity extends object, TPk extends TOIMKey> = (entity: TEntity) => TPk;
482
714
 
483
715
  type TOIMEntityUpdater<TEntity extends object> = (draft: Partial<TEntity>, prevEntity: TEntity) => TEntity;
484
716
 
485
- type TOIMCollectionOptions<TEntity extends object, TPk extends TOIMPk> = {
717
+ type TOIMCollectionOptions<TEntity extends object, TPk extends TOIMKey> = {
486
718
  selectPk?: TOIMPkSelector<TEntity, TPk>;
719
+ /**
720
+ * Backing store. Defaults to `OIMCollectionStoreMapDriven` (native-`Map`,
721
+ * primitive PKs). For a composite PK path, pass
722
+ * `new OIMCollectionStoreTrieDriven()`.
723
+ */
487
724
  store?: OIMCollectionStore<TEntity, TPk>;
488
725
  updateEntity?: TOIMEntityUpdater<TEntity>;
489
726
  };
490
727
 
491
- type TOIMCollectionUpdatePayload<TPk extends TOIMPk> = {
728
+ type TOIMCollectionUpdatePayload<TPk extends TOIMKey> = {
492
729
  pks: readonly TPk[];
493
730
  };
494
731
 
495
732
  /** It's like a store - but with event emitter */
496
- declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
733
+ declare class OIMCollection<TEntity extends object, TPk extends TOIMKey> {
497
734
  readonly emitter: OIMEventEmitter<{
498
735
  0: TOIMCollectionUpdatePayload<TPk>;
499
736
  }>;
@@ -505,6 +742,12 @@ declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
505
742
  getManyByPks(pks: readonly TPk[]): TEntity[];
506
743
  getSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk> | undefined;
507
744
  getOrReserveSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk>;
745
+ /**
746
+ * The existing slot for `pk` (live or reserved) WITHOUT creating one — used
747
+ * by indexes to resolve a pk to its canonical slot for removal (delete by
748
+ * reference), with no side effect for a pk that is not present.
749
+ */
750
+ findSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk> | undefined;
508
751
  getSlotsByPks(pks: readonly TPk[]): TOIMEntitySlot<TEntity, TPk>[];
509
752
  getAllSlots(): TOIMEntitySlot<TEntity, TPk>[];
510
753
  upsertOneByPk(pk: TPk, entity: Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
@@ -523,92 +766,11 @@ declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
523
766
  destroy(): void;
524
767
  }
525
768
 
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> {
769
+ declare class OIMReactiveCollection<TEntity extends object, TPk extends TOIMKey> extends OIMCollection<TEntity, TPk> implements IOIMKeyedSubscription<TPk> {
608
770
  private readonly queue;
609
771
  protected readonly updateEmitter: OIMCarrierKeyedEmitter<TPk, TOIMEntitySlot<TEntity, TPk>>;
610
772
  private readonly anyUpdateHandlers;
611
- private pendingAnyUpdatePks;
773
+ private readonly pendingAnyUpdatePks;
612
774
  private isAnyUpdateClearPending;
613
775
  private isAnyUpdateScheduled;
614
776
  constructor(queue: OIMEventQueue, opts?: TOIMCollectionOptions<TEntity, TPk>);
@@ -644,63 +806,109 @@ declare class OIMReactiveCollection<TEntity extends object, TPk extends TOIMPk>
644
806
  destroy(): void;
645
807
  }
646
808
 
647
- type TOIMCollectionIndexSetBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
809
+ type TOIMCollectionIndexSetBasedOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = {
648
810
  indexOptions?: {
649
811
  comparePks?: TOIMIndexComparator<TPk>;
650
812
  store?: OIMIndexStoreSetBased<TKey, TPk>;
651
813
  };
652
814
  } & ({
653
815
  collection: OIMReactiveCollection<TEntity, TPk>;
654
- resolveSlot?: never;
816
+ getSlot?: never;
655
817
  } | {
656
818
  collection?: never;
657
- resolveSlot: TOIMEntitySlotResolver<TPk>;
819
+ getSlot: TOIMEntitySlotGetter<TPk>;
658
820
  });
659
- type TOIMCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
821
+ type TOIMCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = {
660
822
  indexOptions?: {
661
823
  comparePks?: TOIMIndexComparator<TPk>;
662
824
  store?: OIMIndexStoreArrayBased<TKey, TPk>;
663
825
  };
664
826
  } & ({
665
827
  collection: OIMReactiveCollection<TEntity, TPk>;
666
- resolveSlot?: never;
828
+ getSlot?: never;
667
829
  } | {
668
830
  collection?: never;
669
- resolveSlot: TOIMEntitySlotResolver<TPk>;
831
+ getSlot: TOIMEntitySlotGetter<TPk>;
670
832
  });
671
- type TOIMCollectionOrderedIndexOptions<TEntity extends object, TPk extends TOIMPk> = {
833
+ type TOIMCollectionOrderedIndexOptions<TEntity extends object, TPk extends TOIMKey> = {
672
834
  collection: OIMReactiveCollection<TEntity, TPk>;
673
- resolveSlot?: never;
835
+ getSlot?: never;
674
836
  } | {
675
837
  collection?: never;
676
- resolveSlot: TOIMEntitySlotResolver<TPk>;
838
+ getSlot: TOIMEntitySlotGetter<TPk>;
677
839
  };
678
- type TOIMCollectionOrderedListCommandStreamOptions<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object> = {
840
+ type TOIMCollectionOrderedListCommandStreamOptions<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object> = {
679
841
  index?: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
680
842
  } & ({
681
843
  collection: OIMReactiveCollection<TEntity, TPk>;
682
- resolveSlot?: never;
844
+ getSlot?: never;
683
845
  } | {
684
846
  collection?: never;
685
- resolveSlot: TOIMEntitySlotResolver<TPk>;
847
+ getSlot: TOIMEntitySlotGetter<TPk>;
686
848
  });
687
- type TOIMRelationsSetIndexOptions<TKey extends TOIMPk, TPk extends TOIMPk> = {
849
+ type TOIMRelationsSetIndexOptions<TKey extends TOIMKey, TPk extends TOIMKey> = {
688
850
  indexOptions?: {
689
851
  comparePks?: TOIMIndexComparator<TPk>;
690
852
  store?: OIMIndexStoreSetBased<TKey, TPk>;
691
853
  };
692
854
  };
693
- type TOIMRelationsArrayIndexOptions<TKey extends TOIMPk, TPk extends TOIMPk> = {
855
+ type TOIMRelationsArrayIndexOptions<TKey extends TOIMKey, TPk extends TOIMKey> = {
694
856
  indexOptions?: {
695
857
  comparePks?: TOIMIndexComparator<TPk>;
696
858
  store?: OIMIndexStoreArrayBased<TKey, TPk>;
697
859
  };
698
860
  };
699
- type TOIMRelationsOrderedListOptions<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object> = {
861
+ /**
862
+ * Options for a composite (trie-backed) Set-based index. Its key is a
863
+ * `TOIMKeyPath` — an arbitrary-length tuple of primitive segments — looked up by
864
+ * content in O(arity). The store defaults to `OIMIndexStoreTrieDrivenSetBased`.
865
+ */
866
+ type TOIMCollectionIndexCompositeSetBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
867
+ indexOptions?: {
868
+ comparePks?: TOIMIndexComparator<TPk>;
869
+ store?: OIMIndexStoreSetBased<TOIMKeyPath, TPk>;
870
+ };
871
+ } & ({
872
+ collection: OIMReactiveCollection<TEntity, TPk>;
873
+ getSlot?: never;
874
+ } | {
875
+ collection?: never;
876
+ getSlot: TOIMEntitySlotGetter<TPk>;
877
+ });
878
+ type TOIMRelationsCompositeSetIndexOptions<TPk extends TOIMKey> = {
879
+ indexOptions?: {
880
+ comparePks?: TOIMIndexComparator<TPk>;
881
+ store?: OIMIndexStoreSetBased<TOIMKeyPath, TPk>;
882
+ };
883
+ };
884
+ /**
885
+ * Options for a composite (trie-backed) Array-based (ordered) index. Its key is
886
+ * a `TOIMKeyPath`, looked up by content in O(arity). The store defaults to
887
+ * `OIMIndexStoreTrieDrivenArrayBased`.
888
+ */
889
+ type TOIMCollectionIndexCompositeArrayBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
890
+ indexOptions?: {
891
+ comparePks?: TOIMIndexComparator<TPk>;
892
+ store?: OIMIndexStoreArrayBased<TOIMKeyPath, TPk>;
893
+ };
894
+ } & ({
895
+ collection: OIMReactiveCollection<TEntity, TPk>;
896
+ getSlot?: never;
897
+ } | {
898
+ collection?: never;
899
+ getSlot: TOIMEntitySlotGetter<TPk>;
900
+ });
901
+ type TOIMRelationsCompositeArrayIndexOptions<TPk extends TOIMKey> = {
902
+ indexOptions?: {
903
+ comparePks?: TOIMIndexComparator<TPk>;
904
+ store?: OIMIndexStoreArrayBased<TOIMKeyPath, TPk>;
905
+ };
906
+ };
907
+ type TOIMRelationsOrderedListOptions<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object> = {
700
908
  index?: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
701
909
  };
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> = {
910
+ type TOIMDerivedIndexKeySelector<TEntity extends object, TKey extends TOIMKey> = (entity: TEntity) => TKey | readonly TKey[] | undefined | null;
911
+ type TOIMDerivedCollectionIndexSetBasedOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = {
704
912
  selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>;
705
913
  /**
706
914
  * Build initial index state from existing collection slots.
@@ -709,11 +917,11 @@ type TOIMDerivedCollectionIndexSetBasedOptions<TEntity extends object, TKey exte
709
917
  buildInitial?: boolean;
710
918
  indexOptions?: TOIMCollectionIndexSetBasedOptions<TEntity, TKey, TPk>['indexOptions'];
711
919
  };
712
- type TOIMRelationsDerivedSetIndexOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = Omit<TOIMDerivedCollectionIndexSetBasedOptions<TEntity, TKey, TPk>, 'selectIndexKeys'>;
920
+ type TOIMRelationsDerivedSetIndexOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = Omit<TOIMDerivedCollectionIndexSetBasedOptions<TEntity, TKey, TPk>, 'selectIndexKeys'>;
713
921
  type TOIMDerivedEntityOrderValue = string | number | bigint | boolean;
714
922
  type TOIMDerivedEntityOrderSelector<TEntity extends object> = (entity: TEntity) => TOIMDerivedEntityOrderValue;
715
923
  type TOIMDerivedEntityComparator<TEntity extends object> = (a: TEntity, b: TEntity) => number;
716
- type TOIMDerivedCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
924
+ type TOIMDerivedCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = {
717
925
  selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>;
718
926
  /**
719
927
  * Build initial index state from existing collection slots.
@@ -730,7 +938,7 @@ type TOIMDerivedCollectionIndexArrayBasedOptions<TEntity extends object, TKey ex
730
938
  orderBy?: TOIMDerivedEntityOrderSelector<TEntity>;
731
939
  indexOptions?: TOIMCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>['indexOptions'];
732
940
  };
733
- type TOIMRelationsDerivedArrayIndexOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = Omit<TOIMDerivedCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>, 'selectIndexKeys'>;
941
+ type TOIMRelationsDerivedArrayIndexOptions<TEntity extends object, TKey extends TOIMKey, TPk extends TOIMKey> = Omit<TOIMDerivedCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>, 'selectIndexKeys'>;
734
942
 
735
943
  /**
736
944
  * Manual ordered Array-based index.
@@ -743,9 +951,10 @@ type TOIMRelationsDerivedArrayIndexOptions<TEntity extends object, TKey extends
743
951
  *
744
952
  * It emits UPDATE events per key on every successful mutation. It is a plain
745
953
  * data structure: it knows nothing about "commands" — turning its mutations
746
- * into position-addressed commands is the command stream's job.
954
+ * into position-addressed commands is the command stream's job. Mutations happen
955
+ * on the store's stable carrier bucket in place (via `arrayStore`).
747
956
  */
748
- declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexArrayBased<TKey, TPk> {
957
+ declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndexArrayBased<TKey, TPk> {
749
958
  clear(key?: TKey): void;
750
959
  pushSlot(key: TKey, slot: TOIMAnyEntitySlot<TPk>): number;
751
960
  insertSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TPk>): number;
@@ -765,7 +974,6 @@ declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk extends T
765
974
  */
766
975
  moveRange(key: TKey, from: number, to: number, count: number): number;
767
976
  resetSlots(key: TKey, slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
768
- private getOrCreateList;
769
977
  }
770
978
 
771
979
  /**
@@ -774,17 +982,16 @@ declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk extends T
774
982
  * Raw ordered indexes store slots. This variant provides PK writes and resolves
775
983
  * them to canonical collection slots at construction-bound write time.
776
984
  */
777
- declare class OIMCollectionIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMIndexManualOrderedArrayBased<TKey, TPk> {
778
- private readonly resolveSlot;
985
+ declare class OIMCollectionIndexManualOrderedArrayBased<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMIndexManualOrderedArrayBased<TKey, TPk> {
986
+ private readonly getSlot;
779
987
  constructor(opts: TOIMCollectionOrderedIndexOptions<TEntity, TPk>);
780
988
  push(key: TKey, pk: TPk): number;
781
989
  insertAt(key: TKey, index: number, pk: TPk): number;
782
990
  reset(key: TKey, pks: readonly TPk[]): void;
783
991
  getEntitiesByKey<TItem extends object = TEntity>(key: TKey): (TItem | undefined)[];
784
992
  getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TKey[]): Map<TKey, (TItem | undefined)[]>;
785
- resolvePk(pk: TPk): TOIMAnyEntitySlot<TPk>;
786
- private resolveSlots;
787
- private resolveRequiredSlot;
993
+ getRequiredSlot(pk: TPk): TOIMAnyEntitySlot<TPk>;
994
+ private getRequiredSlots;
788
995
  }
789
996
 
790
997
  type TOIMUpdateEventEmitterDeliveryMode = 'queue' | 'after_flush' | 'immediate';
@@ -792,7 +999,7 @@ type TOIMUpdateEventEmitterDeliveryMode = 'queue' | 'after_flush' | 'immediate';
792
999
  * Universal event emitter that handles subscriptions and notifications for any key type.
793
1000
  * Optimized for performance with adaptive algorithms and memory management.
794
1001
  */
795
- declare class OIMUpdateEventEmitter<TKey extends TOIMPk> {
1002
+ declare class OIMUpdateEventEmitter<TKey extends TOIMKey> {
796
1003
  protected keyHandlers: Map<TKey, Set<TOIMEventHandler<void>>>;
797
1004
  protected queue: OIMEventQueue;
798
1005
  private readonly deliveryMode;
@@ -895,7 +1102,7 @@ type TOIMOrderedListCommand<TItem> = {
895
1102
  * payload, so `consumeCommands(key)` must be called inside the `handler`, before
896
1103
  * the buffer for that key is cleared.
897
1104
  */
898
- interface IOIMOrderedListCommandSource<TKey extends TOIMPk, TItem> {
1105
+ interface IOIMOrderedListCommandSource<TKey extends TOIMKey, TItem> {
899
1106
  /**
900
1107
  * Subscribe to per-key command notifications. The handler receives no
901
1108
  * payload — pull the commands with {@link consumeCommands} synchronously.
@@ -924,7 +1131,7 @@ interface IOIMOrderedListCommandSource<TKey extends TOIMPk, TItem> {
924
1131
  * consulted only on the cold reset-coalescing path, so it stays off the hot
925
1132
  * append path.
926
1133
  */
927
- declare abstract class OIMOrderedListCommandBuffer<TKey extends TOIMPk, TItem> implements IOIMOrderedListCommandSource<TKey, TItem> {
1134
+ declare abstract class OIMOrderedListCommandBuffer<TKey extends TOIMKey, TItem> implements IOIMOrderedListCommandSource<TKey, TItem> {
928
1135
  readonly commandsEventEmitter: OIMUpdateEventEmitter<TKey>;
929
1136
  private readonly unsubscribeAfterFlush;
930
1137
  protected readonly commandsByKey: Map<TKey, TOIMOrderedListCommand<TItem>[]>;
@@ -955,7 +1162,7 @@ declare abstract class OIMOrderedListCommandBuffer<TKey extends TOIMPk, TItem> i
955
1162
  * Command buffering, `after_flush` delivery and the consume/subscribe surface
956
1163
  * come from {@link OIMOrderedListCommandBuffer}.
957
1164
  */
958
- declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMOrderedListCommandBuffer<TKey, TOIMEntitySlot<TEntity, TPk>> {
1165
+ declare class OIMOrderedListCommandStream<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMOrderedListCommandBuffer<TKey, TOIMEntitySlot<TEntity, TPk>> {
959
1166
  /** Underlying slot-first ordered index. */
960
1167
  readonly index: OIMIndexManualOrderedArrayBased<TKey, TPk>;
961
1168
  constructor(queue: OIMEventQueue, index?: OIMIndexManualOrderedArrayBased<TKey, TPk>);
@@ -990,7 +1197,7 @@ declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMP
990
1197
  * Public writes use PKs; they resolve to canonical collection slots (throwing on
991
1198
  * an unresolvable pk) before mutating the index and recording the command.
992
1199
  */
993
- declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMOrderedListCommandStream<TKey, TPk, TEntity> {
1200
+ declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMOrderedListCommandStream<TKey, TPk, TEntity> {
994
1201
  readonly index: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
995
1202
  constructor(queue: OIMEventQueue, opts: TOIMCollectionOrderedListCommandStreamOptions<TKey, TPk, TEntity>);
996
1203
  push(key: TKey, pk: TPk): void;
@@ -1000,32 +1207,41 @@ declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMPk, TPk ext
1000
1207
  set(key: TKey, pks: readonly TPk[]): void;
1001
1208
  getSlotsByKey(key: TKey): readonly TOIMEntitySlot<TEntity, TPk>[];
1002
1209
  getEntitiesByKey(key: TKey): (TEntity | undefined)[];
1003
- private resolvePk;
1210
+ private getRequiredSlot;
1004
1211
  }
1005
1212
 
1006
1213
  /**
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.
1214
+ * Manual Array-based (ordered) index with direct key→slots control.
1215
+ *
1216
+ * Buckets are stable carrier buckets owned by the store (`getOrReserveBucket`):
1217
+ * a write mutates the SAME bucket in place and then calls `emitBucketChanged`,
1218
+ * so the reactive subclass delivers straight off that bucket in O(1). Emptied
1219
+ * buckets are released (kept only while subscribed).
1009
1220
  */
1010
- declare class OIMIndexManualArrayBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexArrayBased<TIndexKey, TPk> {
1221
+ declare class OIMIndexManualArrayBased<TIndexKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndexArrayBased<TIndexKey, TPk> {
1011
1222
  constructor(options?: {
1012
1223
  comparePks?: TOIMIndexComparator<TPk>;
1013
1224
  store?: OIMIndexStoreArrayBased<TIndexKey, TPk>;
1014
1225
  });
1015
1226
  setSlots(key: TIndexKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
1016
1227
  /**
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`.
1228
+ * Appends pre-deduplicated slots to a key's bucket IN PLACE and emits once.
1229
+ * O(added); callers own dedup.
1020
1230
  */
1021
1231
  appendSlots(key: TIndexKey, slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1022
1232
  /**
1023
- * Clear all primary keys for a specific index key, or all keys if no key specified
1233
+ * Clear all primary keys for a specific index key, or all keys if none given.
1024
1234
  */
1025
1235
  clear(key?: TIndexKey): void;
1236
+ /**
1237
+ * Emit that a bucket changed. Base (non-reactive) path emits by key on the
1238
+ * plain event emitter; the reactive subclass overrides this to mark the
1239
+ * bucket carrier directly (O(1), no key→carrier lookup).
1240
+ */
1241
+ protected emitBucketChanged(bucket: OIMKeyedBucketArrayBased<TIndexKey, TPk>): void;
1026
1242
  }
1027
1243
 
1028
- declare class OIMReactiveIndexManualArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMReactiveIndexArrayBased<TKey, TPk, OIMIndexManualArrayBased<TKey, TPk>> {
1244
+ declare class OIMReactiveIndexManualArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMReactiveIndexArrayBased<TKey, TPk, OIMIndexManualArrayBased<TKey, TPk>> {
1029
1245
  constructor(queue: OIMEventQueue, opts?: {
1030
1246
  indexOptions?: {
1031
1247
  comparePks?: TOIMIndexComparator<TPk>;
@@ -1043,9 +1259,10 @@ declare class OIMReactiveIndexManualArrayBased<TKey extends TOIMPk, TPk extends
1043
1259
  * PK writes (`setPks`/`addPks`/`removePks`) resolve canonical entity slots
1044
1260
  * through the collection binding supplied at construction time.
1045
1261
  */
1046
- declare class OIMReactiveCollectionIndexManualArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveIndexManualArrayBased<TKey, TPk> {
1047
- private readonly resolveSlot;
1048
- private readonly pksByKey;
1262
+ declare class OIMReactiveCollectionIndexManualArrayBased<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveIndexManualArrayBased<TKey, TPk> {
1263
+ private readonly getSlot;
1264
+ private readonly findSlotForRemoval;
1265
+ private readonly slotsByKey;
1049
1266
  constructor(queue: OIMEventQueue, opts: TOIMCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>);
1050
1267
  setPks(key: TKey, pks: readonly TPk[]): void;
1051
1268
  addPks(key: TKey, pks: readonly TPk[]): void;
@@ -1058,23 +1275,43 @@ declare class OIMReactiveCollectionIndexManualArrayBased<TKey extends TOIMPk, TP
1058
1275
  private membershipOf;
1059
1276
  getEntitiesByKey<TItem extends object = TEntity>(key: TKey): (TItem | undefined)[];
1060
1277
  getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TKey[]): Map<TKey, (TItem | undefined)[]>;
1061
- private resolveSlots;
1062
- private resolveRequiredSlot;
1278
+ private getSlotsOrTransient;
1279
+ private getSlotOrTransient;
1063
1280
  }
1064
1281
 
1065
1282
  /**
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> {
1283
+ * Manual Set-based index with direct key→slots control.
1284
+ *
1285
+ * Buckets are stable carrier buckets owned by the store (`getOrReserveBucket`):
1286
+ * a write mutates the SAME bucket in place and then calls `emitBucketChanged`,
1287
+ * so the reactive subclass delivers straight off that bucket in O(1). Emptied
1288
+ * buckets are released (kept only while subscribed); the store keeps a
1289
+ * subscribed-but-empty bucket alive so a subscription survives a key going empty
1290
+ * and re-filling.
1291
+ */
1292
+ declare class OIMIndexManualSetBased<TIndexKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndexSetBased<TIndexKey, TPk> {
1070
1293
  constructor(options?: {
1071
1294
  comparePks?: TOIMIndexComparator<TPk>;
1072
1295
  store?: OIMIndexStoreSetBased<TIndexKey, TPk>;
1073
1296
  });
1074
1297
  setSlots(key: TIndexKey, slots: Iterable<TOIMAnyEntitySlot<TPk>>): void;
1298
+ setPks(key: TIndexKey, pks: readonly TPk[], getSlot: (pk: TPk) => TOIMAnyEntitySlot<TPk>): void;
1299
+ addPks(key: TIndexKey, pks: readonly TPk[], getSlot: (pk: TPk) => TOIMAnyEntitySlot<TPk>): void;
1300
+ /**
1301
+ * Removes by pk. `pks` must be canonical `slot.pk` references (membership is
1302
+ * keyed by them): for primitive pks that is just the pk; a collection-bound
1303
+ * composite index canonicalizes raw pks to `slot.pk` before calling this.
1304
+ */
1305
+ removePks(key: TIndexKey, pks: readonly TPk[]): void;
1075
1306
  /**
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`.
1307
+ * The bucket's pk → slot membership, lazily created and seeded from the
1308
+ * bucket's current slots (so it stays correct even if slots were written
1309
+ * through the lower-level `setSlots` path).
1310
+ */
1311
+ private membershipOf;
1312
+ private replaceBucketContents;
1313
+ /**
1314
+ * Adds slots to a key's bucket IN PLACE and emits once. O(added).
1078
1315
  */
1079
1316
  addSlots(key: TIndexKey, slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1080
1317
  /**
@@ -1082,12 +1319,18 @@ declare class OIMIndexManualSetBased<TIndexKey extends TOIMPk, TPk extends TOIMP
1082
1319
  */
1083
1320
  removeSlots(key: TIndexKey, slots: readonly TOIMAnyEntitySlot<TPk>[]): void;
1084
1321
  /**
1085
- * Clear all primary keys for a specific index key, or all keys if no key specified
1322
+ * Clear all primary keys for a specific index key, or all keys if none given.
1086
1323
  */
1087
1324
  clear(key?: TIndexKey): void;
1325
+ /**
1326
+ * Emit that a bucket changed. Base (non-reactive) path emits by key on the
1327
+ * plain event emitter; the reactive subclass overrides this to mark the
1328
+ * bucket carrier directly (O(1), no key→carrier lookup).
1329
+ */
1330
+ protected emitBucketChanged(bucket: OIMKeyedBucketSetBased<TIndexKey, TPk>): void;
1088
1331
  }
1089
1332
 
1090
- declare class OIMReactiveIndexManualSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMReactiveIndexSetBased<TKey, TPk, OIMIndexManualSetBased<TKey, TPk>> {
1333
+ declare class OIMReactiveIndexManualSetBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMReactiveIndexSetBased<TKey, TPk, OIMIndexManualSetBased<TKey, TPk>> {
1091
1334
  constructor(queue: OIMEventQueue, opts?: {
1092
1335
  indexOptions?: {
1093
1336
  comparePks?: TOIMIndexComparator<TPk>;
@@ -1104,24 +1347,77 @@ declare class OIMReactiveIndexManualSetBased<TKey extends TOIMPk, TPk extends TO
1104
1347
  * Collection-bound reactive Set-based index.
1105
1348
  *
1106
1349
  * PK writes (`setPks`/`addPks`/`removePks`) resolve canonical entity slots
1107
- * through the collection binding supplied at construction time.
1350
+ * through the collection binding and delegate to the underlying index, which
1351
+ * keeps each key's pk→slot membership ON the bucket itself — so a write touches
1352
+ * the key's store bucket exactly once (no separate membership map/trie).
1108
1353
  */
1109
- declare class OIMReactiveCollectionIndexManualSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveIndexManualSetBased<TKey, TPk> {
1110
- private readonly resolveSlot;
1111
- private readonly slotByPk;
1354
+ declare class OIMReactiveCollectionIndexManualSetBased<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveIndexManualSetBased<TKey, TPk> {
1355
+ private readonly getSlot;
1356
+ private readonly getSlotOrTransient;
1112
1357
  constructor(queue: OIMEventQueue, opts: TOIMCollectionIndexSetBasedOptions<TEntity, TKey, TPk>);
1358
+ private readonly findSlotForRemoval;
1113
1359
  setPks(key: TKey, pks: readonly TPk[]): void;
1114
1360
  addPks(key: TKey, pks: readonly TPk[]): void;
1115
1361
  removePks(key: TKey, pks: readonly TPk[]): void;
1116
- clear(key?: TKey): void;
1362
+ getEntitiesByKey<TItem extends object = TEntity>(key: TKey): (TItem | undefined)[];
1363
+ getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TKey[]): Map<TKey, (TItem | undefined)[]>;
1364
+ }
1365
+
1366
+ /**
1367
+ * Collection-bound reactive Set-based index keyed by a composite key path
1368
+ * (`TOIMKeyPath`) — an arbitrary-length tuple of primitive segments, e.g.
1369
+ * `[userId, projectId, role]`.
1370
+ *
1371
+ * Composite counterpart of `OIMReactiveCollectionIndexManualSetBased`: same
1372
+ * manual `setPks`/`addPks`/`removePks` surface and collection slot resolution,
1373
+ * but every key is a path matched by content in O(arity). Because the pk→slot
1374
+ * membership lives ON the store bucket (not a separate key-indexed structure), a
1375
+ * pk-write walks the key-path trie exactly once — for both the bucket and its
1376
+ * membership. The full path is the lookup unit (no partial/prefix queries);
1377
+ * subscriptions deliver per full path off the bucket carrier.
1378
+ *
1379
+ * The primitive-keyed indexes are untouched and keep their native-`Map` fast
1380
+ * path — the trie cost is paid only by this opt-in index.
1381
+ */
1382
+ declare class OIMReactiveCollectionIndexCompositeTrieSetBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveIndexManualSetBased<TOIMKeyPath, TPk> {
1383
+ private readonly getSlot;
1384
+ private readonly getSlotOrTransient;
1385
+ constructor(queue: OIMEventQueue, opts: TOIMCollectionIndexCompositeSetBasedOptions<TEntity, TPk>);
1386
+ private readonly findSlotForRemoval;
1387
+ setPks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1388
+ addPks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1389
+ removePks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1390
+ getEntitiesByKey<TItem extends object = TEntity>(key: TOIMKeyPath): (TItem | undefined)[];
1391
+ getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TOIMKeyPath[]): Map<TOIMKeyPath, (TItem | undefined)[]>;
1392
+ }
1393
+
1394
+ /**
1395
+ * Collection-bound reactive Array-based (ordered) index keyed by a composite key
1396
+ * path (`TOIMKeyPath`). The array counterpart of
1397
+ * `OIMReactiveCollectionIndexCompositeTrieSetBased`: same manual
1398
+ * `setPks`/`addPks`/`removePks` surface and collection slot resolution, but keys
1399
+ * are ordered slot arrays and each key is a path matched by content in O(arity).
1400
+ *
1401
+ * Primitive-keyed indexes keep their native-`Map` fast path — the trie cost is
1402
+ * paid only by this opt-in index.
1403
+ */
1404
+ declare class OIMReactiveCollectionIndexCompositeTrieArrayBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveIndexManualArrayBased<TOIMKeyPath, TPk> {
1405
+ private readonly getSlot;
1406
+ private readonly pksByKey;
1407
+ constructor(queue: OIMEventQueue, opts: TOIMCollectionIndexCompositeArrayBasedOptions<TEntity, TPk>);
1408
+ setPks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1409
+ addPks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1410
+ removePks(key: TOIMKeyPath, pks: readonly TPk[]): void;
1411
+ clear(key?: TOIMKeyPath): void;
1117
1412
  /**
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.
1413
+ * The membership set for a key path, lazily seeded from the current bucket so
1414
+ * it stays correct even if slots were set through a lower-level path.
1120
1415
  */
1121
1416
  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)[]>;
1124
- private resolveRequiredSlot;
1417
+ getEntitiesByKey<TItem extends object = TEntity>(key: TOIMKeyPath): (TItem | undefined)[];
1418
+ getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TOIMKeyPath[]): Map<TOIMKeyPath, (TItem | undefined)[]>;
1419
+ private getSlotsOrTransient;
1420
+ private getSlotOrTransient;
1125
1421
  }
1126
1422
 
1127
1423
  /**
@@ -1130,7 +1426,7 @@ declare class OIMReactiveCollectionIndexManualSetBased<TKey extends TOIMPk, TPk
1130
1426
  * The collection remains the source of truth. This index listens to collection
1131
1427
  * updates and maintains key membership automatically.
1132
1428
  */
1133
- declare class OIMDerivedCollectionIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionIndexManualSetBased<TKey, TPk, TEntity> {
1429
+ declare class OIMDerivedCollectionIndexSetBased<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveCollectionIndexManualSetBased<TKey, TPk, TEntity> {
1134
1430
  private readonly collection;
1135
1431
  private readonly selectIndexKeys;
1136
1432
  private readonly unsubscribeFromCollection;
@@ -1150,7 +1446,7 @@ declare class OIMDerivedCollectionIndexSetBased<TKey extends TOIMPk, TPk extends
1150
1446
  * It maintains ordered per-key arrays automatically from collection updates.
1151
1447
  * Use `orderBy` or `compareEntities` when list order matters.
1152
1448
  */
1153
- declare class OIMDerivedCollectionIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity> {
1449
+ declare class OIMDerivedCollectionIndexArrayBased<TKey extends TOIMKey, TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity> {
1154
1450
  private readonly collection;
1155
1451
  private readonly selectIndexKeys;
1156
1452
  private readonly compareEntities?;
@@ -1171,7 +1467,7 @@ declare class OIMDerivedCollectionIndexArrayBased<TKey extends TOIMPk, TPk exten
1171
1467
  * Manual array-based keyless index — direct raw-slot control of the single
1172
1468
  * ordered bucket. Mirrors {@link OIMIndexManualArrayBased} minus the key.
1173
1469
  */
1174
- declare class OIMGlobalIndexManualArrayBased<TPk extends TOIMPk> extends OIMGlobalIndexArrayBased<TPk> {
1470
+ declare class OIMGlobalIndexManualArrayBased<TPk extends TOIMKey> extends OIMGlobalIndexArrayBased<TPk> {
1175
1471
  constructor(options?: {
1176
1472
  comparePks?: TOIMIndexComparator<TPk>;
1177
1473
  });
@@ -1188,7 +1484,7 @@ declare class OIMGlobalIndexManualArrayBased<TPk extends TOIMPk> extends OIMGlob
1188
1484
  * Reactive manual array-based keyless index — raw-slot writes bridged to a
1189
1485
  * single-carrier emitter. Mirrors {@link OIMReactiveIndexManualArrayBased}.
1190
1486
  */
1191
- declare class OIMReactiveGlobalIndexManualArrayBased<TPk extends TOIMPk> extends OIMReactiveGlobalIndexArrayBased<TPk, OIMGlobalIndexManualArrayBased<TPk>> {
1487
+ declare class OIMReactiveGlobalIndexManualArrayBased<TPk extends TOIMKey> extends OIMReactiveGlobalIndexArrayBased<TPk, OIMGlobalIndexManualArrayBased<TPk>> {
1192
1488
  constructor(queue: OIMEventQueue, opts?: {
1193
1489
  indexOptions?: {
1194
1490
  comparePks?: TOIMIndexComparator<TPk>;
@@ -1204,29 +1500,29 @@ declare class OIMReactiveGlobalIndexManualArrayBased<TPk extends TOIMPk> extends
1204
1500
  * Defaults to "the entity exists" (`item !== undefined`) when omitted.
1205
1501
  */
1206
1502
  type TOIMGlobalIndexFilter<TEntity extends object> = (entity: TEntity) => boolean;
1207
- type TOIMCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1503
+ type TOIMCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
1208
1504
  indexOptions?: {
1209
1505
  comparePks?: TOIMIndexComparator<TPk>;
1210
1506
  };
1211
1507
  } & ({
1212
1508
  collection: OIMReactiveCollection<TEntity, TPk>;
1213
- resolveSlot?: never;
1509
+ getSlot?: never;
1214
1510
  } | {
1215
1511
  collection?: never;
1216
- resolveSlot: TOIMEntitySlotResolver<TPk>;
1512
+ getSlot: TOIMEntitySlotGetter<TPk>;
1217
1513
  });
1218
- type TOIMCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1514
+ type TOIMCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
1219
1515
  indexOptions?: {
1220
1516
  comparePks?: TOIMIndexComparator<TPk>;
1221
1517
  };
1222
1518
  } & ({
1223
1519
  collection: OIMReactiveCollection<TEntity, TPk>;
1224
- resolveSlot?: never;
1520
+ getSlot?: never;
1225
1521
  } | {
1226
1522
  collection?: never;
1227
- resolveSlot: TOIMEntitySlotResolver<TPk>;
1523
+ getSlot: TOIMEntitySlotGetter<TPk>;
1228
1524
  });
1229
- type TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1525
+ type TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
1230
1526
  /** Build initial state from existing collection slots. Defaults to true. */
1231
1527
  buildInitial?: boolean;
1232
1528
  /** Sort the list. Takes priority over `orderBy`. */
@@ -1239,7 +1535,7 @@ type TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity extends object, T
1239
1535
  comparePks?: TOIMIndexComparator<TPk>;
1240
1536
  };
1241
1537
  };
1242
- type TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extends TOIMPk> = {
1538
+ type TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk extends TOIMKey> = {
1243
1539
  /** Build initial state from existing collection slots. Defaults to true. */
1244
1540
  buildInitial?: boolean;
1245
1541
  /** Include predicate. Defaults to "entity exists". */
@@ -1248,18 +1544,18 @@ type TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity extends object, TPk
1248
1544
  comparePks?: TOIMIndexComparator<TPk>;
1249
1545
  };
1250
1546
  };
1251
- type TOIMRelationsGlobalArrayIndexOptions<TPk extends TOIMPk> = {
1547
+ type TOIMRelationsGlobalArrayIndexOptions<TPk extends TOIMKey> = {
1252
1548
  indexOptions?: {
1253
1549
  comparePks?: TOIMIndexComparator<TPk>;
1254
1550
  };
1255
1551
  };
1256
- type TOIMRelationsGlobalSetIndexOptions<TPk extends TOIMPk> = {
1552
+ type TOIMRelationsGlobalSetIndexOptions<TPk extends TOIMKey> = {
1257
1553
  indexOptions?: {
1258
1554
  comparePks?: TOIMIndexComparator<TPk>;
1259
1555
  };
1260
1556
  };
1261
- type TOIMRelationsDerivedGlobalArrayIndexOptions<TEntity extends object, TPk extends TOIMPk> = TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity, TPk>;
1262
- type TOIMRelationsDerivedGlobalSetIndexOptions<TEntity extends object, TPk extends TOIMPk> = TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity, TPk>;
1557
+ type TOIMRelationsDerivedGlobalArrayIndexOptions<TEntity extends object, TPk extends TOIMKey> = TOIMDerivedCollectionGlobalIndexArrayBasedOptions<TEntity, TPk>;
1558
+ type TOIMRelationsDerivedGlobalSetIndexOptions<TEntity extends object, TPk extends TOIMKey> = TOIMDerivedCollectionGlobalIndexSetBasedOptions<TEntity, TPk>;
1263
1559
 
1264
1560
  /**
1265
1561
  * Collection-bound reactive array-based keyless index.
@@ -1269,8 +1565,8 @@ type TOIMRelationsDerivedGlobalSetIndexOptions<TEntity extends object, TPk exten
1269
1565
  * dedup. Mirrors {@link OIMReactiveCollectionIndexManualArrayBased} minus the
1270
1566
  * key (one bucket instead of a per-key map).
1271
1567
  */
1272
- declare class OIMReactiveCollectionGlobalIndexManualArrayBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveGlobalIndexManualArrayBased<TPk> {
1273
- private readonly resolveSlot;
1568
+ declare class OIMReactiveCollectionGlobalIndexManualArrayBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveGlobalIndexManualArrayBased<TPk> {
1569
+ private readonly getSlot;
1274
1570
  private readonly membership;
1275
1571
  private membershipSeeded;
1276
1572
  constructor(queue: OIMEventQueue, opts: TOIMCollectionGlobalIndexArrayBasedOptions<TEntity, TPk>);
@@ -1280,15 +1576,15 @@ declare class OIMReactiveCollectionGlobalIndexManualArrayBased<TPk extends TOIMP
1280
1576
  clear(): void;
1281
1577
  private membershipOf;
1282
1578
  getEntities<TItem extends object = TEntity>(): (TItem | undefined)[];
1283
- private resolveSlots;
1284
- private resolveRequiredSlot;
1579
+ private getSlotsOrTransient;
1580
+ private getSlotOrTransient;
1285
1581
  }
1286
1582
 
1287
1583
  /**
1288
1584
  * Manual set-based keyless index — direct raw-slot control of the single
1289
1585
  * unordered bucket. Mirrors {@link OIMIndexManualSetBased} minus the key.
1290
1586
  */
1291
- declare class OIMGlobalIndexManualSetBased<TPk extends TOIMPk> extends OIMGlobalIndexSetBased<TPk> {
1587
+ declare class OIMGlobalIndexManualSetBased<TPk extends TOIMKey> extends OIMGlobalIndexSetBased<TPk> {
1292
1588
  constructor(options?: {
1293
1589
  comparePks?: TOIMIndexComparator<TPk>;
1294
1590
  });
@@ -1304,7 +1600,7 @@ declare class OIMGlobalIndexManualSetBased<TPk extends TOIMPk> extends OIMGlobal
1304
1600
  * Reactive manual set-based keyless index — raw-slot writes bridged to a
1305
1601
  * single-carrier emitter. Mirrors {@link OIMReactiveIndexManualSetBased}.
1306
1602
  */
1307
- declare class OIMReactiveGlobalIndexManualSetBased<TPk extends TOIMPk> extends OIMReactiveGlobalIndexSetBased<TPk, OIMGlobalIndexManualSetBased<TPk>> {
1603
+ declare class OIMReactiveGlobalIndexManualSetBased<TPk extends TOIMKey> extends OIMReactiveGlobalIndexSetBased<TPk, OIMGlobalIndexManualSetBased<TPk>> {
1308
1604
  constructor(queue: OIMEventQueue, opts?: {
1309
1605
  indexOptions?: {
1310
1606
  comparePks?: TOIMIndexComparator<TPk>;
@@ -1324,8 +1620,8 @@ declare class OIMReactiveGlobalIndexManualSetBased<TPk extends TOIMPk> extends O
1324
1620
  * add (dedup) and O(1) remove. Mirrors
1325
1621
  * {@link OIMReactiveCollectionIndexManualSetBased} minus the key.
1326
1622
  */
1327
- declare class OIMReactiveCollectionGlobalIndexManualSetBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveGlobalIndexManualSetBased<TPk> {
1328
- private readonly resolveSlot;
1623
+ declare class OIMReactiveCollectionGlobalIndexManualSetBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveGlobalIndexManualSetBased<TPk> {
1624
+ private readonly getSlot;
1329
1625
  private readonly membership;
1330
1626
  private membershipSeeded;
1331
1627
  constructor(queue: OIMEventQueue, opts: TOIMCollectionGlobalIndexSetBasedOptions<TEntity, TPk>);
@@ -1335,7 +1631,7 @@ declare class OIMReactiveCollectionGlobalIndexManualSetBased<TPk extends TOIMPk,
1335
1631
  clear(): void;
1336
1632
  private membershipOf;
1337
1633
  getEntities<TItem extends object = TEntity>(): (TItem | undefined)[];
1338
- private resolveRequiredSlot;
1634
+ private getSlotOrTransient;
1339
1635
  }
1340
1636
 
1341
1637
  /**
@@ -1346,7 +1642,7 @@ declare class OIMReactiveCollectionGlobalIndexManualSetBased<TPk extends TOIMPk,
1346
1642
  * {@link OIMDerivedCollectionIndexArrayBased}, but membership is a single
1347
1643
  * boolean set (`presentPks`) instead of a per-pk key-set.
1348
1644
  */
1349
- declare class OIMDerivedCollectionGlobalIndexArrayBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionGlobalIndexManualArrayBased<TPk, TEntity> {
1645
+ declare class OIMDerivedCollectionGlobalIndexArrayBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveCollectionGlobalIndexManualArrayBased<TPk, TEntity> {
1350
1646
  private readonly collection;
1351
1647
  private readonly compareEntities?;
1352
1648
  private readonly orderBy?;
@@ -1369,7 +1665,7 @@ declare class OIMDerivedCollectionGlobalIndexArrayBased<TPk extends TOIMPk, TEnt
1369
1665
  * (default: "entity exists"). Mirrors {@link OIMDerivedCollectionIndexSetBased}
1370
1666
  * minus the key.
1371
1667
  */
1372
- declare class OIMDerivedCollectionGlobalIndexSetBased<TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionGlobalIndexManualSetBased<TPk, TEntity> {
1668
+ declare class OIMDerivedCollectionGlobalIndexSetBased<TPk extends TOIMKey, TEntity extends object = object> extends OIMReactiveCollectionGlobalIndexManualSetBased<TPk, TEntity> {
1373
1669
  private readonly collection;
1374
1670
  private readonly filter?;
1375
1671
  private readonly unsubscribeFromCollection;
@@ -1388,14 +1684,28 @@ declare class OIMDerivedCollectionGlobalIndexSetBased<TPk extends TOIMPk, TEntit
1388
1684
  * `queue + collection` binding in one place, so related structures can be
1389
1685
  * created next to the collection with less generic noise.
1390
1686
  */
1391
- declare class OIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMPk> {
1687
+ declare class OIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMKey> {
1392
1688
  readonly queue: OIMEventQueue;
1393
1689
  readonly collection: OIMReactiveCollection<TEntity, TPk>;
1394
1690
  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>;
1691
+ setBasedIndex<TKey extends TOIMKey = string>(opts?: TOIMRelationsSetIndexOptions<TKey, TPk>): OIMReactiveCollectionIndexManualSetBased<TKey, TPk, TEntity>;
1692
+ /**
1693
+ * Composite (trie-backed) manual Set-based index keyed by an
1694
+ * arbitrary-length key path, e.g. `setPks([userId, projectId, role], pks)`.
1695
+ * Key paths are matched by content in O(arity) — no string concatenation,
1696
+ * no separator collisions, each segment keeps its type. Primitive-keyed
1697
+ * indexes are unaffected and keep their native-`Map` fast path.
1698
+ */
1699
+ compositeSetIndex(opts?: TOIMRelationsCompositeSetIndexOptions<TPk>): OIMReactiveCollectionIndexCompositeTrieSetBased<TPk, TEntity>;
1700
+ /**
1701
+ * Composite (trie-backed) manual Array-based (ordered) index keyed by an
1702
+ * arbitrary-length key path, e.g. `setPks([channelId, threadId], pks)`.
1703
+ * Ordered counterpart of `compositeSetIndex`.
1704
+ */
1705
+ compositeArrayIndex(opts?: TOIMRelationsCompositeArrayIndexOptions<TPk>): OIMReactiveCollectionIndexCompositeTrieArrayBased<TPk, TEntity>;
1706
+ derivedSetIndex<TKey extends TOIMKey = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedSetIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexSetBased<TKey, TPk, TEntity>;
1707
+ arrayBasedIndex<TKey extends TOIMKey = string>(opts?: TOIMRelationsArrayIndexOptions<TKey, TPk>): OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity>;
1708
+ derivedArrayIndex<TKey extends TOIMKey = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedArrayIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexArrayBased<TKey, TPk, TEntity>;
1399
1709
  /**
1400
1710
  * Keyless (whole-collection / "all") manual array-based index. No key —
1401
1711
  * write pks directly with `setPks`/`addPks`/`removePks`.
@@ -1410,10 +1720,10 @@ declare class OIMCollectionIndexFactory<TEntity extends object, TPk extends TOIM
1410
1720
  derivedArrayGlobalIndex(opts?: TOIMRelationsDerivedGlobalArrayIndexOptions<TEntity, TPk>): OIMDerivedCollectionGlobalIndexArrayBased<TPk, TEntity>;
1411
1721
  /** Keyless set auto-derived from the whole collection. */
1412
1722
  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>;
1723
+ orderedIndex<TKey extends TOIMKey = string>(): OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
1724
+ orderedList<TKey extends TOIMKey = string>(opts?: TOIMRelationsOrderedListOptions<TKey, TPk, TEntity>): OIMCollectionOrderedListCommandStream<TKey, TPk, TEntity>;
1415
1725
  }
1416
- declare function createOIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMPk>(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>): OIMCollectionIndexFactory<TEntity, TPk>;
1726
+ declare function createOIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMKey>(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>): OIMCollectionIndexFactory<TEntity, TPk>;
1417
1727
 
1418
1728
  /**
1419
1729
  * Payload type for update events that contain keys */
@@ -1479,7 +1789,13 @@ declare class OIMReactiveObject<TKey extends string, TValue> extends OIMObject<T
1479
1789
  destroy(): void;
1480
1790
  }
1481
1791
 
1482
- declare class OIMCollectionStoreMapDriven<TEntity extends object, TPk extends TOIMPk> extends OIMCollectionStore<TEntity, TPk> {
1792
+ /**
1793
+ * Native-`Map` collection store for primitive PKs. The hot path is a plain
1794
+ * `Map` — this class NEVER holds a trie, so its `.get`/`.set` call sites stay
1795
+ * monomorphic even in a process that also runs composite-PK collections (those
1796
+ * use `OIMCollectionStoreTrieDriven`). Byte-for-byte the pre-seam behavior.
1797
+ */
1798
+ declare class OIMCollectionStoreMapDriven<TEntity extends object, TPk extends TOIMKey> extends OIMCollectionStore<TEntity, TPk> {
1483
1799
  protected readonly slots: Map<TPk, TOIMEntitySlot<TEntity, TPk>>;
1484
1800
  protected readonly reservedSlots: Map<TPk, TOIMEntitySlot<TEntity, TPk>>;
1485
1801
  setOneByPk(pk: TPk, entity: TEntity): TOIMEntitySlot<TEntity, TPk>;
@@ -1501,6 +1817,57 @@ declare class OIMCollectionStoreMapDriven<TEntity extends object, TPk extends TO
1501
1817
  destroy(): void;
1502
1818
  }
1503
1819
 
1820
+ declare class OIMTrieMap<TSegment, TValue> {
1821
+ private readonly root;
1822
+ private _size;
1823
+ /** Number of stored paths (terminal nodes), not the number of trie nodes. */
1824
+ get size(): number;
1825
+ set(path: readonly TSegment[], value: TValue): void;
1826
+ get(path: readonly TSegment[]): TValue | undefined;
1827
+ has(path: readonly TSegment[]): boolean;
1828
+ delete(path: readonly TSegment[]): boolean;
1829
+ clear(): void;
1830
+ /** Depth-first iteration over `[path, value]` for every stored path. */
1831
+ entries(): IterableIterator<[TSegment[], TValue]>;
1832
+ keys(): IterableIterator<TSegment[]>;
1833
+ values(): IterableIterator<TValue>;
1834
+ private findNode;
1835
+ }
1836
+
1837
+ /**
1838
+ * Composite-PK collection store: keys slots by a `TOIMKeyPath` via a trie, so a
1839
+ * freshly built `[a, b]` resolves to the same slot as one stored earlier, and
1840
+ * `slot.pk` is interned to one canonical reference per logical key (downstream
1841
+ * native `Set<slot.pk>` stay correct).
1842
+ *
1843
+ * It is a SEPARATE class from `OIMCollectionStoreMapDriven` on purpose: each
1844
+ * store's `.get`/`.set` call sites see exactly one container shape (all-`Map`
1845
+ * there, all-trie here), so a process running both primitive and composite
1846
+ * collections keeps both hot paths monomorphic — no shared-class inline-cache
1847
+ * pollution. Method bodies mirror the Map store.
1848
+ */
1849
+ declare class OIMCollectionStoreTrieDriven<TEntity extends object> extends OIMCollectionStore<TEntity, TOIMKeyPath> {
1850
+ protected readonly slots: OIMTrieMap<TOIMPk, TOIMEntitySlot<TEntity, TOIMKeyPath>>;
1851
+ protected readonly reservedSlots: OIMTrieMap<TOIMPk, TOIMEntitySlot<TEntity, TOIMKeyPath>>;
1852
+ setOneByPk(pk: TOIMKeyPath, entity: TEntity): TOIMEntitySlot<TEntity, TOIMKeyPath>;
1853
+ getOrReserveSlotByPk(pk: TOIMKeyPath): TOIMEntitySlot<TEntity, TOIMKeyPath>;
1854
+ setManyByPks(pks: readonly TOIMKeyPath[], entities: TEntity[]): TOIMEntitySlot<TEntity, TOIMKeyPath>[];
1855
+ getSlotByPk(pk: TOIMKeyPath): TOIMEntitySlot<TEntity, TOIMKeyPath> | undefined;
1856
+ findSlotByPk(pk: TOIMKeyPath): TOIMEntitySlot<TEntity, TOIMKeyPath> | undefined;
1857
+ private hasSubscribers;
1858
+ getSlotsByPks(pks: readonly TOIMKeyPath[]): TOIMEntitySlot<TEntity, TOIMKeyPath>[];
1859
+ getAllSlots(): TOIMEntitySlot<TEntity, TOIMKeyPath>[];
1860
+ removeOneByPk(pk: TOIMKeyPath): void;
1861
+ removeManyByPks(pks: readonly TOIMKeyPath[]): void;
1862
+ getOneByPk(pk: TOIMKeyPath): TEntity | undefined;
1863
+ getManyByPks(pks: readonly TOIMKeyPath[]): TEntity[];
1864
+ getAll(): TEntity[];
1865
+ countAll(): number;
1866
+ clear(): void;
1867
+ getAllPks(): TOIMKeyPath[];
1868
+ destroy(): void;
1869
+ }
1870
+
1504
1871
  declare class OIMObjectStoreMapDriven<TKey extends TOIMPk, TValue> extends OIMObjectStore<TKey, TValue> {
1505
1872
  protected readonly properties: Map<TKey, TValue>;
1506
1873
  setProperty(key: TKey, value: TValue): void;
@@ -1538,8 +1905,14 @@ declare class OIMObjectStoreRecordDriven<TKey extends string, TValue> extends OI
1538
1905
  destroy(): void;
1539
1906
  }
1540
1907
 
1541
- declare class OIMIndexStoreMapDrivenSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexStoreSetBased<TKey, TPk> {
1542
- protected readonly slots: Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
1908
+ declare class OIMIndexStoreMapDrivenSetBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndexStoreSetBased<TKey, TPk> {
1909
+ protected readonly slots: Map<TKey, OIMKeyedBucketSetBased<TKey, TPk>>;
1910
+ protected readonly reservedBuckets: Map<TKey, OIMKeyedBucketSetBased<TKey, TPk>>;
1911
+ getOrReserveBucket(key: TKey): OIMKeyedBucketSetBased<TKey, TPk>;
1912
+ findBucket(key: TKey): OIMKeyedBucketSetBased<TKey, TPk> | undefined;
1913
+ retainBucket(bucket: OIMKeyedBucketSetBased<TKey, TPk>): void;
1914
+ releaseBucket(bucket: OIMKeyedBucketSetBased<TKey, TPk>): void;
1915
+ dropIfReserved(key: TKey): void;
1543
1916
  setOneByKey(key: TKey, slots: Set<TOIMAnyEntitySlot<TPk>>): void;
1544
1917
  removeOneByKey(key: TKey): void;
1545
1918
  removeManyByKeys(keys: readonly TKey[]): void;
@@ -1551,8 +1924,14 @@ declare class OIMIndexStoreMapDrivenSetBased<TKey extends TOIMPk, TPk extends TO
1551
1924
  clear(): void;
1552
1925
  }
1553
1926
 
1554
- declare class OIMIndexStoreMapDrivenArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexStoreArrayBased<TKey, TPk> {
1555
- protected readonly slots: Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
1927
+ declare class OIMIndexStoreMapDrivenArrayBased<TKey extends TOIMKey, TPk extends TOIMKey> extends OIMIndexStoreArrayBased<TKey, TPk> {
1928
+ protected readonly slots: Map<TKey, OIMKeyedBucketArrayBased<TKey, TPk>>;
1929
+ protected readonly reservedBuckets: Map<TKey, OIMKeyedBucketArrayBased<TKey, TPk>>;
1930
+ getOrReserveBucket(key: TKey): OIMKeyedBucketArrayBased<TKey, TPk>;
1931
+ findBucket(key: TKey): OIMKeyedBucketArrayBased<TKey, TPk> | undefined;
1932
+ retainBucket(bucket: OIMKeyedBucketArrayBased<TKey, TPk>): void;
1933
+ releaseBucket(bucket: OIMKeyedBucketArrayBased<TKey, TPk>): void;
1934
+ dropIfReserved(key: TKey): void;
1556
1935
  setOneByKey(key: TKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
1557
1936
  removeOneByKey(key: TKey): void;
1558
1937
  removeManyByKeys(keys: readonly TKey[]): void;
@@ -1564,6 +1943,106 @@ declare class OIMIndexStoreMapDrivenArrayBased<TKey extends TOIMPk, TPk extends
1564
1943
  clear(): void;
1565
1944
  }
1566
1945
 
1946
+ /**
1947
+ * Set-based index store keyed by a composite key path (`TOIMKeyPath`), backed by
1948
+ * a trie (`OIMTrieMap`) instead of a native `Map`. Key paths are matched by
1949
+ * content in O(arity) without building a string key. Buckets are carrier buckets
1950
+ * with the same live/reserved lifecycle as the Map-driven store.
1951
+ */
1952
+ declare class OIMIndexStoreTrieDrivenSetBased<TPk extends TOIMKey> extends OIMIndexStoreSetBased<TOIMKeyPath, TPk> {
1953
+ protected readonly slots: OIMTrieMap<TOIMPk, OIMKeyedBucketSetBased<TOIMKeyPath, TPk>>;
1954
+ protected readonly reservedBuckets: OIMTrieMap<TOIMPk, OIMKeyedBucketSetBased<TOIMKeyPath, TPk>>;
1955
+ getOrReserveBucket(key: TOIMKeyPath): OIMKeyedBucketSetBased<TOIMKeyPath, TPk>;
1956
+ findBucket(key: TOIMKeyPath): OIMKeyedBucketSetBased<TOIMKeyPath, TPk> | undefined;
1957
+ retainBucket(bucket: OIMKeyedBucketSetBased<TOIMKeyPath, TPk>): void;
1958
+ releaseBucket(bucket: OIMKeyedBucketSetBased<TOIMKeyPath, TPk>): void;
1959
+ dropIfReserved(key: TOIMKeyPath): void;
1960
+ setOneByKey(key: TOIMKeyPath, slots: Set<TOIMAnyEntitySlot<TPk>>): void;
1961
+ removeOneByKey(key: TOIMKeyPath): void;
1962
+ removeManyByKeys(keys: readonly TOIMKeyPath[]): void;
1963
+ getOneByKey(key: TOIMKeyPath): Set<TOIMAnyEntitySlot<TPk>> | undefined;
1964
+ getManyByKeys(keys: readonly TOIMKeyPath[]): Map<TOIMKeyPath, Set<TOIMAnyEntitySlot<TPk>>>;
1965
+ getAllKeys(): TOIMKeyPath[];
1966
+ getAll(): Map<TOIMKeyPath, Set<TOIMAnyEntitySlot<TPk>>>;
1967
+ countAll(): number;
1968
+ clear(): void;
1969
+ }
1970
+
1971
+ /**
1972
+ * Array-based (ordered) index store keyed by a composite key path
1973
+ * (`TOIMKeyPath`), backed by a trie (`OIMTrieMap`). The array counterpart of
1974
+ * `OIMIndexStoreTrieDrivenSetBased`: each key path maps to an ordered carrier
1975
+ * bucket (`OIMKeyedBucketArrayBased`) with the same live/reserved lifecycle,
1976
+ * matched by content in O(arity) without building a string key.
1977
+ */
1978
+ declare class OIMIndexStoreTrieDrivenArrayBased<TPk extends TOIMKey> extends OIMIndexStoreArrayBased<TOIMKeyPath, TPk> {
1979
+ protected readonly slots: OIMTrieMap<TOIMPk, OIMKeyedBucketArrayBased<TOIMKeyPath, TPk>>;
1980
+ protected readonly reservedBuckets: OIMTrieMap<TOIMPk, OIMKeyedBucketArrayBased<TOIMKeyPath, TPk>>;
1981
+ getOrReserveBucket(key: TOIMKeyPath): OIMKeyedBucketArrayBased<TOIMKeyPath, TPk>;
1982
+ findBucket(key: TOIMKeyPath): OIMKeyedBucketArrayBased<TOIMKeyPath, TPk> | undefined;
1983
+ retainBucket(bucket: OIMKeyedBucketArrayBased<TOIMKeyPath, TPk>): void;
1984
+ releaseBucket(bucket: OIMKeyedBucketArrayBased<TOIMKeyPath, TPk>): void;
1985
+ dropIfReserved(key: TOIMKeyPath): void;
1986
+ setOneByKey(key: TOIMKeyPath, slots: TOIMAnyEntitySlot<TPk>[]): void;
1987
+ removeOneByKey(key: TOIMKeyPath): void;
1988
+ removeManyByKeys(keys: readonly TOIMKeyPath[]): void;
1989
+ getOneByKey(key: TOIMKeyPath): TOIMAnyEntitySlot<TPk>[] | undefined;
1990
+ getManyByKeys(keys: readonly TOIMKeyPath[]): Map<TOIMKeyPath, TOIMAnyEntitySlot<TPk>[]>;
1991
+ getAllKeys(): TOIMKeyPath[];
1992
+ getAll(): Map<TOIMKeyPath, TOIMAnyEntitySlot<TPk>[]>;
1993
+ countAll(): number;
1994
+ clear(): void;
1995
+ }
1996
+
1997
+ /**
1998
+ * Composite-key counterpart of `OIMKeyedCarrierProvider`: backs the index keyed
1999
+ * emitter for key paths. Maps each key path to a carrier holding that path's
2000
+ * subscribers + dirty flag, via a trie (`OIMTrieMap`) so a freshly built
2001
+ * `[a, b, c]` resolves to the same carrier as the one subscribed earlier.
2002
+ *
2003
+ * Carriers are created on first subscribe (`getOrReserveCarrier`) and pruned
2004
+ * when their last subscriber leaves (`onCarrierEmptied`) — the trie drops the
2005
+ * empty branch, so a churning key-path space does not leak carriers.
2006
+ */
2007
+ declare class OIMKeyPathCarrierProvider implements IOIMCarrierProvider<TOIMKeyPath, IOIMKeyCarrier<TOIMKeyPath>> {
2008
+ private readonly carriers;
2009
+ getOrReserveCarrier(key: TOIMKeyPath): IOIMKeyCarrier<TOIMKeyPath>;
2010
+ findCarrier(key: TOIMKeyPath): IOIMKeyCarrier<TOIMKeyPath> | undefined;
2011
+ onCarrierEmptied(carrier: IOIMKeyCarrier<TOIMKeyPath>): void;
2012
+ }
2013
+
2014
+ /**
2015
+ * The bucket-lifecycle surface a carrier provider needs from an index store —
2016
+ * implemented by both the set-based and array-based stores. `getOrReserveBucket`
2017
+ * creates a reserved (empty) bucket so a subscription can exist before its data;
2018
+ * `dropIfReserved` prunes such a bucket once its last subscriber leaves.
2019
+ */
2020
+ interface IOIMCarrierBucketStore<TKey extends TOIMKey, TBucket extends IOIMSubscribable> {
2021
+ getOrReserveBucket(key: TKey): TBucket;
2022
+ findBucket(key: TKey): TBucket | undefined;
2023
+ dropIfReserved(key: TKey): void;
2024
+ }
2025
+ /**
2026
+ * Resolves an index key to its carrier — where the carrier IS the index bucket,
2027
+ * owned by the store. Mirrors the collection's slot-based provider: subscribers
2028
+ * live on the bucket, so on a write the reactive index marks the bucket it just
2029
+ * touched in O(1) with no key→carrier map/trie. Works uniformly for primitive
2030
+ * (Map) and composite (trie) stores, and for set- and array-based buckets.
2031
+ *
2032
+ * `getOrReserveCarrier` creates a reserved (empty) bucket so a subscription can
2033
+ * exist before its data; `onCarrierEmptied` drops such a bucket once its last
2034
+ * subscriber leaves and it holds no slots.
2035
+ */
2036
+ declare class OIMBucketCarrierProvider<TKey extends TOIMKey, TBucket extends IOIMSubscribable & {
2037
+ readonly key: TKey;
2038
+ }> implements IOIMCarrierProvider<TKey, TBucket> {
2039
+ private readonly store;
2040
+ constructor(store: IOIMCarrierBucketStore<TKey, TBucket>);
2041
+ getOrReserveCarrier(key: TKey): TBucket;
2042
+ findCarrier(key: TKey): TBucket | undefined;
2043
+ onCarrierEmptied(carrier: TBucket): void;
2044
+ }
2045
+
1567
2046
  type TOIMComparator<TEntity extends object> = (a: TEntity, b: TEntity) => boolean;
1568
2047
 
1569
2048
  declare class OIMComparatorFactory<TEntity extends object> {
@@ -1604,7 +2083,7 @@ declare function createMergeEntityUpdater<TEntity extends object>(): TOIMEntityU
1604
2083
  /**
1605
2084
  * Keyless (single-carrier) pub/sub. The emitter IS the carrier: it holds one
1606
2085
  * subscriber set and one dirty flag, so the hot path — marking updated and
1607
- * delivering — needs no resolver, no `Map`, no per-key hashing, and no
2086
+ * delivering — needs no provider, no `Map`, no per-key hashing, and no
1608
2087
  * `dirtyCarriers[]` batch (there is only ever one carrier).
1609
2088
  *
1610
2089
  * This is the {@link OIMCarrierKeyedEmitter} analogue for a whole-collection
@@ -1642,22 +2121,22 @@ declare class OIMIndexComparatorFactory {
1642
2121
  * Create an element-wise comparator that checks arrays for strict equality.
1643
2122
  * Compares array lengths and each element using strict equality (===).
1644
2123
  */
1645
- static createElementWiseComparator<TPk extends TOIMPk>(): TOIMIndexComparator<TPk>;
2124
+ static createElementWiseComparator<TPk extends TOIMKey>(): TOIMIndexComparator<TPk>;
1646
2125
  /**
1647
2126
  * Create a set-based comparator that checks if arrays contain the same elements.
1648
2127
  * Order doesn't matter, only the presence of elements.
1649
2128
  */
1650
- static createSetBasedComparator<TPk extends TOIMPk>(): TOIMIndexComparator<TPk>;
2129
+ static createSetBasedComparator<TPk extends TOIMKey>(): TOIMIndexComparator<TPk>;
1651
2130
  /**
1652
2131
  * Create a shallow comparator that only checks array references.
1653
2132
  * Fastest but only works if you're reusing the same array instances.
1654
2133
  */
1655
- static createShallowComparator<TPk extends TOIMPk>(): TOIMIndexComparator<TPk>;
2134
+ static createShallowComparator<TPk extends TOIMKey>(): TOIMIndexComparator<TPk>;
1656
2135
  /**
1657
2136
  * Create a no-comparison comparator that always returns false (always updates).
1658
2137
  * Useful for disabling comparison while keeping the same interface.
1659
2138
  */
1660
- static createAlwaysUpdateComparator<TPk extends TOIMPk>(): TOIMIndexComparator<TPk>;
2139
+ static createAlwaysUpdateComparator<TPk extends TOIMKey>(): TOIMIndexComparator<TPk>;
1661
2140
  }
1662
2141
 
1663
2142
  declare class OIMMap2Keys<K1, K2, V> {
@@ -1671,7 +2150,136 @@ declare class OIMMap2Keys<K1, K2, V> {
1671
2150
  clear(): void;
1672
2151
  }
1673
2152
 
1674
- declare class OIMPkSelectorFactory<TEntity extends object, TPk extends TOIMPk> {
2153
+ /**
2154
+ * Anything with a `destroy()` teardown. `destroy(): void` is the de-facto
2155
+ * convention across oimdb (collections, indexes, objects, emitters, effects,
2156
+ * computed, streams); this interface just names it so a dispose scope can hold
2157
+ * them uniformly.
2158
+ */
2159
+ interface IOIMDisposable {
2160
+ destroy(): void;
2161
+ }
2162
+
2163
+ /**
2164
+ * A unit of teardown a dispose scope can hold: either an object with `destroy()`
2165
+ * (collection, index, object, stream, effect, computed…) or a bare unsubscribe
2166
+ * function — the `() => void` returned by `subscribeOnKey`, `emitter.on`,
2167
+ * `selector.watch`, `runtime.schedule`, etc. Many resources (selectors, per-key
2168
+ * subscriptions, scheduler tasks) expose ONLY the function form.
2169
+ */
2170
+ type TOIMDisposable = IOIMDisposable | (() => void);
2171
+
2172
+ /**
2173
+ * Collects disposables and tears them ALL down at once, in reverse registration
2174
+ * (LIFO) order — so dependents are disposed before the things they depend on
2175
+ * (indexes/streams/selectors before the collection, the collection before the
2176
+ * queue). This is the correct teardown order in oimdb, and doing it by hand is
2177
+ * the classic source of leaks and use-after-destroy bugs.
2178
+ *
2179
+ * Register as you build, capturing the value inline:
2180
+ *
2181
+ * ```ts
2182
+ * const scope = new OIMDisposeScope();
2183
+ * const queue = scope.add(new OIMEventQueue());
2184
+ * const users = scope.add(new OIMReactiveCollection(queue, { selectPk: u => u.id }));
2185
+ * const byTeam = scope.add(users.indexFactory.setBasedIndex());
2186
+ * scope.add(selector.watch(v => render(v))); // bare unsubscribe fn also works
2187
+ * // …later, one call tears everything down, LIFO:
2188
+ * scope.destroy();
2189
+ * ```
2190
+ *
2191
+ * Accepts both `{ destroy(): void }` objects and bare `() => void` unsubscribe
2192
+ * functions (selectors, per-key subscriptions and scheduler tasks only expose
2193
+ * the latter). Idempotent; every registered item is disposed even if one throws
2194
+ * (the first error is rethrown afterwards). Nestable via `child()`.
2195
+ */
2196
+ declare class OIMDisposeScope implements IOIMDisposable {
2197
+ private readonly disposables;
2198
+ private disposed;
2199
+ /** Number of not-yet-disposed items currently held. */
2200
+ get size(): number;
2201
+ get isDisposed(): boolean;
2202
+ /**
2203
+ * Register a disposable (object with `destroy()` or an unsubscribe function)
2204
+ * and return it unchanged, so it can be captured inline. If the scope is
2205
+ * already disposed the item is disposed immediately, so nothing leaks.
2206
+ */
2207
+ add<T extends TOIMDisposable>(disposable: T): T;
2208
+ /** A nested scope, itself registered here — dispose it early or with the parent. */
2209
+ child(): OIMDisposeScope;
2210
+ /**
2211
+ * Dispose everything in reverse registration order, then clear. Idempotent.
2212
+ * If any `destroy()`/unsubscribe throws, the rest are still disposed and the
2213
+ * first error is rethrown once teardown completes.
2214
+ */
2215
+ destroy(): void;
2216
+ private disposeOne;
2217
+ }
2218
+ declare function createOIMDisposeScope(): OIMDisposeScope;
2219
+
2220
+ /**
2221
+ * The Set surface the PK / index-key axis needs, abstracted so the concrete
2222
+ * keying strategy is pluggable. A native `Set` satisfies this interface
2223
+ * structurally (primitive default is a plain `Set`, zero wrapper); a composite
2224
+ * key uses a trie-backed implementation matching array keys by content.
2225
+ */
2226
+ interface IOIMKeyedSet<TKey> {
2227
+ add(key: TKey): void;
2228
+ has(key: TKey): boolean;
2229
+ delete(key: TKey): boolean;
2230
+ readonly size: number;
2231
+ values(): IterableIterator<TKey>;
2232
+ clear(): void;
2233
+ }
2234
+
2235
+ /**
2236
+ * Trie-backed Set of composite key paths — the `Set` counterpart of
2237
+ * `OIMTrieMap`. Membership is by content, so a freshly built `[a, b]` is the
2238
+ * same member as one added earlier. Implemented over an `OIMTrieMap<TOIMPk,
2239
+ * true>` to reuse its terminal-flagged nodes and empty-branch pruning.
2240
+ */
2241
+ declare class OIMTrieSet implements IOIMKeyedSet<TOIMKeyPath> {
2242
+ private readonly map;
2243
+ get size(): number;
2244
+ add(key: TOIMKeyPath): void;
2245
+ has(key: TOIMKeyPath): boolean;
2246
+ delete(key: TOIMKeyPath): boolean;
2247
+ values(): IterableIterator<TOIMKeyPath>;
2248
+ clear(): void;
2249
+ }
2250
+
2251
+ /**
2252
+ * Projects a PK to/from a string, for the serialization boundaries that can only
2253
+ * key state by a string: the Redux adapter (state object keyed by id), persist
2254
+ * storage, JSON snapshots. In-memory core never needs this — it keys PKs by
2255
+ * content via a trie — but a composite PK path cannot be a string key, so those
2256
+ * boundaries require a codec.
2257
+ *
2258
+ * There is intentionally NO default codec for composite keys: a hidden
2259
+ * `JSON.stringify` would silently couple correctness to key order / escaping.
2260
+ * Callers pass one explicitly (`OIMPkCodecKeyPath` is a ready opt-in for paths).
2261
+ */
2262
+ interface IOIMPkCodec<TPk extends TOIMKey> {
2263
+ encode(pk: TPk): string;
2264
+ decode(encoded: string): TPk;
2265
+ }
2266
+
2267
+ /**
2268
+ * Opt-in `IOIMPkCodec` for composite key paths at serialization boundaries. Uses
2269
+ * a JSON array encoding, which is collision-safe (a segment containing the
2270
+ * delimiter cannot forge a boundary the way `"a|b"` concatenation can) and
2271
+ * preserves each segment's JSON type, so `decode(encode(pk))` round-trips
2272
+ * `string`/`number` segments exactly.
2273
+ *
2274
+ * It is NOT a default — pass it explicitly where a boundary needs to key a
2275
+ * composite PK by string (Redux state, persist storage, snapshots).
2276
+ */
2277
+ declare class OIMPkCodecKeyPath implements IOIMPkCodec<TOIMKeyPath> {
2278
+ encode(pk: TOIMKeyPath): string;
2279
+ decode(encoded: string): TOIMKeyPath;
2280
+ }
2281
+
2282
+ declare class OIMPkSelectorFactory<TEntity extends object, TPk extends TOIMKey> {
1675
2283
  createIdSelector(): TOIMPkSelector<TEntity & {
1676
2284
  id: TPk;
1677
2285
  }, TPk>;
@@ -1748,29 +2356,45 @@ declare abstract class OIMSelector<TValue> {
1748
2356
  type TOIMCollectionEntitySelector<TEntity extends object> = OIMSelector<TEntity | undefined>;
1749
2357
  type TOIMCollectionEntitiesSelector<TEntity extends object> = OIMSelector<readonly (TEntity | undefined)[]>;
1750
2358
 
1751
- declare class OIMCollectionSelectors<TEntity extends object, TPk extends TOIMPk> {
2359
+ declare class OIMCollectionSelectors<TEntity extends object, TPk extends TOIMKey> {
1752
2360
  private readonly collection;
1753
2361
  readonly runtime: OIMComputeRuntime;
1754
2362
  constructor(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>);
1755
2363
  byPk(pk: TPk): TOIMCollectionEntitySelector<TEntity>;
1756
2364
  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>;
2365
+ entitiesBySetIndexKey<TKey extends TOIMKey, TIndex extends OIMIndexSetBased<TKey, TPk>>(index: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
2366
+ entitiesByArrayIndexKey<TKey extends TOIMKey, TIndex extends OIMIndexArrayBased<TKey, TPk>>(index: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
2367
+ /**
2368
+ * Entities of a composite (key-path) set-based index for one key path, e.g.
2369
+ * `entitiesByCompositeSetIndexKey(index, [projectId, role])`.
2370
+ */
2371
+ entitiesByCompositeSetIndexKey<TIndex extends OIMIndexSetBased<TOIMKeyPath, TPk>>(index: OIMReactiveIndexSetBased<TOIMKeyPath, TPk, TIndex>, key: TOIMKeyPath): TOIMCollectionEntitiesSelector<TEntity>;
2372
+ /** Entities of a composite (key-path) array-based index for one key path. */
2373
+ entitiesByCompositeArrayIndexKey<TIndex extends OIMIndexArrayBased<TOIMKeyPath, TPk>>(index: OIMReactiveIndexArrayBased<TOIMKeyPath, TPk, TIndex>, key: TOIMKeyPath): TOIMCollectionEntitiesSelector<TEntity>;
1759
2374
  /** Entities of a keyless (whole-collection) array-based index, ordered. */
1760
2375
  entitiesByArrayGlobalIndex<TIndex extends OIMGlobalIndexArrayBased<TPk>>(index: OIMReactiveGlobalIndexArrayBased<TPk, TIndex>): TOIMCollectionEntitiesSelector<TEntity>;
1761
2376
  /** Entities of a keyless (whole-collection) set-based index. */
1762
2377
  entitiesBySetGlobalIndex<TIndex extends OIMGlobalIndexSetBased<TPk>>(index: OIMReactiveGlobalIndexSetBased<TPk, TIndex>): TOIMCollectionEntitiesSelector<TEntity>;
1763
2378
  }
1764
2379
 
1765
- type TOIMReactiveCollectionFactoryOptions<TEntity extends object, TPk extends TOIMPk> = TOIMCollectionOptions<TEntity, TPk>;
1766
- type TOIMCollectionKit<TEntity extends object, TPk extends TOIMPk> = {
2380
+ type TOIMReactiveCollectionFactoryOptions<TEntity extends object, TPk extends TOIMKey> = TOIMCollectionOptions<TEntity, TPk>;
2381
+ type TOIMCollectionKit<TEntity extends object, TPk extends TOIMKey> = {
1767
2382
  queue: OIMEventQueue;
1768
2383
  collection: OIMReactiveCollection<TEntity, TPk>;
1769
2384
  indexFactory: OIMCollectionIndexFactory<TEntity, TPk>;
1770
2385
  select: OIMCollectionSelectors<TEntity, TPk>;
2386
+ /**
2387
+ * Dispose scope owning the kit's collection. `add()` indexes/streams/
2388
+ * subscriptions you create off the kit, then `destroy()` tears them all down
2389
+ * in reverse order. Does NOT own the `queue` (it is passed in and may be
2390
+ * shared) — destroy the queue yourself when nothing else uses it.
2391
+ */
2392
+ scope: OIMDisposeScope;
2393
+ /** Tear down the kit's scope (collection + everything added to it). */
2394
+ destroy: () => void;
1771
2395
  };
1772
2396
 
1773
- declare function createOIMCollectionKit<TEntity extends object, TPk extends TOIMPk>(queue: OIMEventQueue, opts?: TOIMReactiveCollectionFactoryOptions<TEntity, TPk>): TOIMCollectionKit<TEntity, TPk>;
2397
+ declare function createOIMCollectionKit<TEntity extends object, TPk extends TOIMKey>(queue: OIMEventQueue, opts?: TOIMReactiveCollectionFactoryOptions<TEntity, TPk>): TOIMCollectionKit<TEntity, TPk>;
1774
2398
 
1775
2399
  type TOIMFieldKey<TEntity extends object> = keyof TEntity & string;
1776
2400
  /**
@@ -1781,7 +2405,7 @@ type TOIMFieldKey<TEntity extends object> = keyof TEntity & string;
1781
2405
  * DX: if the underlying collection is mutated directly, we detect it via collection
1782
2406
  * update events and infer changed fields by diffing the last observed entity snapshot.
1783
2407
  */
1784
- declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOIMPk> {
2408
+ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOIMKey> {
1785
2409
  readonly collection: OIMCollection<TEntity, TPk>;
1786
2410
  private readonly selectPk;
1787
2411
  private readonly unsubscribeAfterFlush;
@@ -1866,7 +2490,7 @@ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOI
1866
2490
  * The output is itself an {@link IOIMOrderedListCommandSource}, so maps chain:
1867
2491
  * `source.map(...)` → `.map(...)`.
1868
2492
  */
1869
- declare class OIMOrderedListMappedCommandStream<TKey extends TOIMPk, TOut, TIn> implements IOIMOrderedListCommandSource<TKey, TOut> {
2493
+ declare class OIMOrderedListMappedCommandStream<TKey extends TOIMKey, TOut, TIn> implements IOIMOrderedListCommandSource<TKey, TOut> {
1870
2494
  private readonly source;
1871
2495
  private readonly create;
1872
2496
  /** Per-key positional mirror of the mapped elements. */
@@ -1902,7 +2526,7 @@ declare class OIMOrderedListMappedCommandStream<TKey extends TOIMPk, TOut, TIn>
1902
2526
  * });
1903
2527
  * ```
1904
2528
  */
1905
- declare function createOIMOrderedListMappedCommandStream<TKey extends TOIMPk, TIn, TOut>(source: IOIMOrderedListCommandSource<TKey, TIn>, create: (item: TIn) => TOut): OIMOrderedListMappedCommandStream<TKey, TOut, TIn>;
2529
+ declare function createOIMOrderedListMappedCommandStream<TKey extends TOIMKey, TIn, TOut>(source: IOIMOrderedListCommandSource<TKey, TIn>, create: (item: TIn) => TOut): OIMOrderedListMappedCommandStream<TKey, TOut, TIn>;
1906
2530
 
1907
2531
  /**
1908
2532
  * Minimal read/subscribe surface a keyed index exposes for slot mapping:
@@ -1912,7 +2536,7 @@ declare function createOIMOrderedListMappedCommandStream<TKey extends TOIMPk, TI
1912
2536
  * `OIMReactiveIndexArrayBased` (slots as a `readonly` array) satisfy it
1913
2537
  * structurally — a `Set` and an array are both `Iterable`.
1914
2538
  */
1915
- interface IOIMIndexSlotSource<TKey extends TOIMPk, TPk extends TOIMPk> extends IOIMKeyedSubscription<TKey> {
2539
+ interface IOIMIndexSlotSource<TKey extends TOIMKey, TPk extends TOIMKey> extends IOIMKeyedSubscription<TKey> {
1916
2540
  getSlotsByKey(key: TKey): Iterable<TOIMAnyEntitySlot<TPk>>;
1917
2541
  }
1918
2542
 
@@ -1935,7 +2559,7 @@ interface IOIMIndexSlotSource<TKey extends TOIMPk, TPk extends TOIMPk> extends I
1935
2559
  * This is a thin wrapper: it holds no queue and no standing subscription of its
1936
2560
  * own — `subscribeOnKey` is a passthrough to the index.
1937
2561
  */
1938
- declare class OIMIndexSlotMap<TKey extends TOIMPk, TPk extends TOIMPk, TMapped> {
2562
+ declare class OIMIndexSlotMap<TKey extends TOIMKey, TPk extends TOIMKey, TMapped> {
1939
2563
  private readonly index;
1940
2564
  private readonly create;
1941
2565
  private readonly cache;
@@ -1974,7 +2598,7 @@ declare class OIMIndexSlotMap<TKey extends TOIMPk, TPk extends TOIMPk, TMapped>
1974
2598
  * }
1975
2599
  * ```
1976
2600
  */
1977
- declare function createOIMIndexSlotMap<TKey extends TOIMPk, TPk extends TOIMPk, TMapped>(index: IOIMIndexSlotSource<TKey, TPk>, create: (slot: TOIMAnyEntitySlot<TPk>) => TMapped): OIMIndexSlotMap<TKey, TPk, TMapped>;
2601
+ declare function createOIMIndexSlotMap<TKey extends TOIMKey, TPk extends TOIMKey, TMapped>(index: IOIMIndexSlotSource<TKey, TPk>, create: (slot: TOIMAnyEntitySlot<TPk>) => TMapped): OIMIndexSlotMap<TKey, TPk, TMapped>;
1978
2602
 
1979
2603
  /**
1980
2604
  * Minimal read/subscribe surface a keyless (whole-collection) index exposes for
@@ -1985,7 +2609,7 @@ declare function createOIMIndexSlotMap<TKey extends TOIMPk, TPk extends TOIMPk,
1985
2609
  * `OIMReactiveGlobalIndexArrayBased` (slots as a `readonly` array) satisfy it
1986
2610
  * structurally — a `Set` and an array are both `Iterable`.
1987
2611
  */
1988
- interface IOIMGlobalIndexSlotSource<TPk extends TOIMPk> extends IOIMSubscription {
2612
+ interface IOIMGlobalIndexSlotSource<TPk extends TOIMKey> extends IOIMSubscription {
1989
2613
  getSlots(): Iterable<TOIMAnyEntitySlot<TPk>>;
1990
2614
  }
1991
2615
 
@@ -2007,7 +2631,7 @@ interface IOIMGlobalIndexSlotSource<TPk extends TOIMPk> extends IOIMSubscription
2007
2631
  * Thin wrapper: no queue, no standing subscription of its own — `subscribe` is a
2008
2632
  * passthrough to the index.
2009
2633
  */
2010
- declare class OIMGlobalIndexSlotMap<TPk extends TOIMPk, TMapped> {
2634
+ declare class OIMGlobalIndexSlotMap<TPk extends TOIMKey, TMapped> {
2011
2635
  private readonly index;
2012
2636
  private readonly create;
2013
2637
  private readonly cache;
@@ -2044,7 +2668,7 @@ declare class OIMGlobalIndexSlotMap<TPk extends TOIMPk, TMapped> {
2044
2668
  * }
2045
2669
  * ```
2046
2670
  */
2047
- declare function createOIMGlobalIndexSlotMap<TPk extends TOIMPk, TMapped>(index: IOIMGlobalIndexSlotSource<TPk>, create: (slot: TOIMAnyEntitySlot<TPk>) => TMapped): OIMGlobalIndexSlotMap<TPk, TMapped>;
2671
+ declare function createOIMGlobalIndexSlotMap<TPk extends TOIMKey, TMapped>(index: IOIMGlobalIndexSlotSource<TPk>, create: (slot: TOIMAnyEntitySlot<TPk>) => TMapped): OIMGlobalIndexSlotMap<TPk, TMapped>;
2048
2672
 
2049
2673
  /**
2050
2674
  * Options for {@link OIMOrderedListCommandStreamDiffDriven}.
@@ -2082,7 +2706,7 @@ type TOIMOrderedListDiffOptions = {
2082
2706
  * worst case (an index scan per placed item), acceptable for the moderate bucket
2083
2707
  * sizes indexes produce, where it runs only on an actual change.
2084
2708
  */
2085
- declare function diffOrderedListByPk<TPk extends TOIMPk, TItem extends {
2709
+ declare function diffOrderedListByPk<TPk extends TOIMKey, TItem extends {
2086
2710
  pk: TPk;
2087
2711
  }>(prev: readonly TItem[], next: readonly TItem[]): TOIMOrderedListCommand<TItem>[];
2088
2712
 
@@ -2104,7 +2728,7 @@ declare function diffOrderedListByPk<TPk extends TOIMPk, TItem extends {
2104
2728
  * `IOIMOrderedListCommandSource`, so it consumes exactly like the writer stream
2105
2729
  * and composes with `createOIMOrderedListMappedCommandStream`.
2106
2730
  */
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>> {
2731
+ 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
2732
  private readonly index;
2109
2733
  private readonly resetThreshold;
2110
2734
  private readonly prevByKey;
@@ -2134,7 +2758,7 @@ declare class OIMOrderedListCommandStreamDiffDriven<TKey extends TOIMPk, TPk ext
2134
2758
  * );
2135
2759
  * ```
2136
2760
  */
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>;
2761
+ 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
2762
 
2139
2763
  /**
2140
2764
  * Animation frame-based scheduler that executes flushes synchronized with the browser's repaint cycle.
@@ -2278,18 +2902,18 @@ type TOIMIndexKey = string | number | bigint;
2278
2902
 
2279
2903
  /**
2280
2904
  * Configuration options for Set-based index instances */
2281
- type TOIMIndexOptionsSetBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> = {
2905
+ type TOIMIndexOptionsSetBased<TIndexKey extends TOIMKey, TPk extends TOIMKey> = {
2282
2906
  comparePks?: TOIMIndexComparator<TPk>;
2283
2907
  store?: OIMIndexStoreSetBased<TIndexKey, TPk>;
2284
2908
  };
2285
2909
  /**
2286
2910
  * Configuration options for Array-based index instances */
2287
- type TOIMIndexOptionsArrayBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> = {
2911
+ type TOIMIndexOptionsArrayBased<TIndexKey extends TOIMKey, TPk extends TOIMKey> = {
2288
2912
  comparePks?: TOIMIndexComparator<TPk>;
2289
2913
  store?: OIMIndexStoreArrayBased<TIndexKey, TPk>;
2290
2914
  };
2291
2915
 
2292
- type TOIMIndexPksUpdatePayload<TKey extends TOIMPk, TPk extends TOIMPk> = {
2916
+ type TOIMIndexPksUpdatePayload<TKey extends TOIMKey, TPk extends TOIMKey> = {
2293
2917
  key: TKey;
2294
2918
  pks: readonly TPk[];
2295
2919
  };
@@ -2317,7 +2941,7 @@ type TOIMComputedOptions<TValue> = {
2317
2941
  compare?: (a: TValue, b: TValue) => boolean;
2318
2942
  };
2319
2943
 
2320
- type TOIMComputedUpdatePayload<TKey extends TOIMPk> = {
2944
+ type TOIMComputedUpdatePayload<TKey extends TOIMKey> = {
2321
2945
  keys: readonly TKey[];
2322
2946
  };
2323
2947
 
@@ -2389,34 +3013,36 @@ declare class OIMEffect {
2389
3013
  private readonly onAfterFlush;
2390
3014
  }
2391
3015
 
2392
- declare class OIMEffectDependencyKeyed<TKey extends TOIMPk> implements IOIMEffectDependency {
3016
+ /**
3017
+ * Depends on updates to ONE key of a keyed source. The key argument is the whole
3018
+ * key — a composite key `[a, b]` is one key, never split — so there is no
3019
+ * `key | key[]` ambiguity to guess at. To depend on several keys, use several
3020
+ * dependencies (an effect already takes a `deps` array).
3021
+ */
3022
+ declare class OIMEffectDependencyKeyed<TKey extends TOIMKey> implements IOIMEffectDependency {
2393
3023
  readonly source: IOIMKeyedSubscription<TKey>;
2394
3024
  private readonly key;
2395
- private readonly keys;
2396
- constructor(source: IOIMKeyedSubscription<TKey>, keyOrKeys: TKey | readonly TKey[]);
3025
+ constructor(source: IOIMKeyedSubscription<TKey>, key: TKey);
2397
3026
  subscribe(onUpdate: () => void): () => void;
2398
3027
  }
2399
3028
 
2400
3029
  declare class OIMEffectDependencyKeyedObject<TKey extends string, TValue> implements IOIMEffectDependency {
2401
3030
  private readonly dep;
2402
3031
  constructor(object: OIMReactiveObject<TKey, TValue>, key: TKey);
2403
- constructor(object: OIMReactiveObject<TKey, TValue>, keys: readonly TKey[]);
2404
3032
  get source(): OIMReactiveObject<TKey, TValue>;
2405
3033
  subscribe(onUpdate: () => void): () => void;
2406
3034
  }
2407
3035
 
2408
- declare class OIMEffectDependencyKeyedCollection<TEntity extends object, TPk extends TOIMPk> implements IOIMEffectDependency {
3036
+ declare class OIMEffectDependencyKeyedCollection<TEntity extends object, TPk extends TOIMKey> implements IOIMEffectDependency {
2409
3037
  private readonly dep;
2410
3038
  constructor(collection: OIMReactiveCollection<TEntity, TPk>, pk: TPk);
2411
- constructor(collection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]);
2412
3039
  get source(): OIMReactiveCollection<TEntity, TPk>;
2413
3040
  subscribe(onUpdate: () => void): () => void;
2414
3041
  }
2415
3042
 
2416
- declare class OIMEffectDependencyKeyedIndex<TKey extends TOIMPk> implements IOIMEffectDependency {
3043
+ declare class OIMEffectDependencyKeyedIndex<TKey extends TOIMKey> implements IOIMEffectDependency {
2417
3044
  private readonly dep;
2418
3045
  constructor(index: IOIMKeyedSubscription<TKey>, key: TKey);
2419
- constructor(index: IOIMKeyedSubscription<TKey>, keys: readonly TKey[]);
2420
3046
  get source(): IOIMKeyedSubscription<TKey>;
2421
3047
  subscribe(onUpdate: () => void): () => void;
2422
3048
  }
@@ -2437,14 +3063,14 @@ declare class OIMEffectDependencyComputed implements IOIMEffectDependency {
2437
3063
  subscribe(onUpdate: () => void): () => void;
2438
3064
  }
2439
3065
 
2440
- declare class OIMCollectionByPkSelector<TEntity extends object, TPk extends TOIMPk> extends OIMSelector<TEntity | undefined> {
3066
+ declare class OIMCollectionByPkSelector<TEntity extends object, TPk extends TOIMKey> extends OIMSelector<TEntity | undefined> {
2441
3067
  private readonly collection;
2442
3068
  private readonly pk;
2443
3069
  constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pk: TPk);
2444
3070
  getValue(): TEntity | undefined;
2445
3071
  }
2446
3072
 
2447
- declare class OIMCollectionByPksSelector<TEntity extends object, TPk extends TOIMPk> extends OIMSelector<readonly (TEntity | undefined)[]> {
3073
+ declare class OIMCollectionByPksSelector<TEntity extends object, TPk extends TOIMKey> extends OIMSelector<readonly (TEntity | undefined)[]> {
2448
3074
  private readonly collection;
2449
3075
  private readonly pks;
2450
3076
  constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]);
@@ -2467,14 +3093,14 @@ declare class OIMObjectValuesByKeysSelector<TKey extends string, TValue> extends
2467
3093
  protected areEqual(prev: readonly (TValue | undefined)[], next: readonly (TValue | undefined)[]): boolean;
2468
3094
  }
2469
3095
 
2470
- declare class OIMIndexPksByKeySetBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<Set<TPk>> {
3096
+ declare class OIMIndexPksByKeySetBasedSelector<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<Set<TPk>> {
2471
3097
  private readonly reactiveIndex;
2472
3098
  private readonly key;
2473
3099
  constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey);
2474
3100
  getValue(): Set<TPk>;
2475
3101
  }
2476
3102
 
2477
- declare class OIMIndexPksByKeyArrayBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
3103
+ declare class OIMIndexPksByKeyArrayBasedSelector<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
2478
3104
  private readonly reactiveIndex;
2479
3105
  private readonly key;
2480
3106
  constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey);
@@ -2482,7 +3108,7 @@ declare class OIMIndexPksByKeyArrayBasedSelector<TKey extends TOIMPk, TPk extend
2482
3108
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
2483
3109
  }
2484
3110
 
2485
- declare class OIMIndexPksByKeysSetBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
3111
+ declare class OIMIndexPksByKeysSetBasedSelector<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
2486
3112
  private readonly reactiveIndex;
2487
3113
  private readonly keys;
2488
3114
  constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
@@ -2490,7 +3116,7 @@ declare class OIMIndexPksByKeysSetBasedSelector<TKey extends TOIMPk, TPk extends
2490
3116
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
2491
3117
  }
2492
3118
 
2493
- declare class OIMIndexPksByKeysArrayBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
3119
+ declare class OIMIndexPksByKeysArrayBasedSelector<TKey extends TOIMKey, TPk extends TOIMKey, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
2494
3120
  private readonly reactiveIndex;
2495
3121
  private readonly keys;
2496
3122
  constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
@@ -2498,7 +3124,7 @@ declare class OIMIndexPksByKeysArrayBasedSelector<TKey extends TOIMPk, TPk exten
2498
3124
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
2499
3125
  }
2500
3126
 
2501
- declare class OIMEntitiesByIndexKeySetBasedSelector<TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
3127
+ declare class OIMEntitiesByIndexKeySetBasedSelector<TEntity extends object, TPk extends TOIMKey, TKey extends TOIMKey, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
2502
3128
  private readonly collection;
2503
3129
  private readonly reactiveIndex;
2504
3130
  private readonly key;
@@ -2507,7 +3133,7 @@ declare class OIMEntitiesByIndexKeySetBasedSelector<TEntity extends object, TPk
2507
3133
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
2508
3134
  }
2509
3135
 
2510
- declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TPk extends TOIMPk, TKey extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
3136
+ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TPk extends TOIMKey, TKey extends TOIMKey, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
2511
3137
  private readonly collection;
2512
3138
  private readonly reactiveIndex;
2513
3139
  private readonly key;
@@ -2516,7 +3142,7 @@ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TP
2516
3142
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
2517
3143
  }
2518
3144
 
2519
- declare class OIMEntitiesByGlobalIndexSetBasedSelector<TEntity extends object, TPk extends TOIMPk, TIndex extends OIMGlobalIndexSetBased<TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
3145
+ declare class OIMEntitiesByGlobalIndexSetBasedSelector<TEntity extends object, TPk extends TOIMKey, TIndex extends OIMGlobalIndexSetBased<TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
2520
3146
  private readonly collection;
2521
3147
  private readonly reactiveIndex;
2522
3148
  constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveGlobalIndexSetBased<TPk, TIndex>);
@@ -2524,7 +3150,7 @@ declare class OIMEntitiesByGlobalIndexSetBasedSelector<TEntity extends object, T
2524
3150
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
2525
3151
  }
2526
3152
 
2527
- declare class OIMEntitiesByGlobalIndexArrayBasedSelector<TEntity extends object, TPk extends TOIMPk, TIndex extends OIMGlobalIndexArrayBased<TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
3153
+ declare class OIMEntitiesByGlobalIndexArrayBasedSelector<TEntity extends object, TPk extends TOIMKey, TIndex extends OIMGlobalIndexArrayBased<TPk>> extends OIMSelector<readonly (TEntity | undefined)[]> {
2528
3154
  private readonly collection;
2529
3155
  private readonly reactiveIndex;
2530
3156
  constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveGlobalIndexArrayBased<TPk, TIndex>);
@@ -2532,4 +3158,4 @@ declare class OIMEntitiesByGlobalIndexArrayBasedSelector<TEntity extends object,
2532
3158
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
2533
3159
  }
2534
3160
 
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 };
3161
+ export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierBucketStore, type IOIMCarrierProvider, type IOIMComputedEventSource, type IOIMDisposable, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMGlobalIndexSlotSource, type IOIMIndexSlotSource, type IOIMIndexStore, type IOIMKeyedMap, type IOIMKeyedSet, type IOIMKeyedUpdateEmitter, type IOIMOrderedListCommandSource, type IOIMPkCodec, type IOIMSingleUpdateEmitter, type IOIMSubscribable, type IOIMSubscription, OIMBucketCarrierProvider, 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, OIMKeyPathCarrierProvider, 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 TOIMEntitySlotGetter, 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 };