@oimdb/core 1.5.0 → 2.0.1

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
@@ -8,7 +8,7 @@ type TOIMAnyEntitySlot<TPk extends TOIMPk> = TOIMEntitySlot<object, TPk>;
8
8
  type TOIMEntitySlotResolver<TPk extends TOIMPk> = (pk: TPk) => TOIMAnyEntitySlot<TPk> | undefined;
9
9
 
10
10
  declare abstract class OIMCollectionStore<TEntity extends object, TPk extends TOIMPk> {
11
- abstract setOneByPk(pk: TPk, entity: TEntity): void;
11
+ abstract setOneByPk(pk: TPk, entity: TEntity): TOIMEntitySlot<TEntity, TPk>;
12
12
  abstract getSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk> | undefined;
13
13
  abstract getSlotsByPks(pks: readonly TPk[]): TOIMEntitySlot<TEntity, TPk>[];
14
14
  abstract getAllSlots(): TOIMEntitySlot<TEntity, TPk>[];
@@ -23,6 +23,74 @@ declare abstract class OIMCollectionStore<TEntity extends object, TPk extends TO
23
23
  abstract destroy(): void;
24
24
  }
25
25
 
26
+ type TOIMEventHandler<T> = (payload: T) => void;
27
+
28
+ declare class OIMEventEmitter<T extends Record<string, unknown>> {
29
+ private buckets;
30
+ hasHandlers<K extends keyof T>(event: K): boolean;
31
+ private getOrCreateBucket;
32
+ /**
33
+ * Compacts the handlers array by removing null entries (tombstones) left by handler removal.
34
+ * Rebuilds the indexByHandler map with updated indices and resets the tombstone count.
35
+ * This reduces array fragmentation and improves iteration performance.
36
+ */
37
+ private compactBucket;
38
+ on<K extends keyof T>(event: K, handler: TOIMEventHandler<T[K]>): () => void;
39
+ emit<K extends keyof T>(event: K, payload: T[K]): void;
40
+ off<K extends keyof T>(event: K, handler: TOIMEventHandler<T[K]>): void;
41
+ offAll<K extends keyof T>(event?: K): void;
42
+ }
43
+
44
+ /**
45
+ * Payload for index update events containing the keys that were modified */
46
+ interface TOIMIndexUpdatePayload<TKey> {
47
+ keys: readonly TKey[];
48
+ }
49
+
50
+ /**
51
+ * Comparator function for index primary key arrays.
52
+ * Returns true if the arrays are considered equal, false if they differ. */
53
+ type TOIMIndexComparator<TPk extends TOIMPk> = (existingPks: readonly TPk[], newPks: readonly TPk[]) => boolean;
54
+
55
+ interface IOIMIndexStore<TKey, TBucket> {
56
+ setOneByKey(key: TKey, bucket: TBucket): void;
57
+ removeOneByKey(key: TKey): void;
58
+ removeManyByKeys(keys: readonly TKey[]): void;
59
+ getOneByKey(key: TKey): TBucket | undefined;
60
+ getManyByKeys(keys: readonly TKey[]): Map<TKey, TBucket>;
61
+ getAllKeys(): TKey[];
62
+ getAll(): Map<TKey, TBucket>;
63
+ countAll(): number;
64
+ clear(): void;
65
+ }
66
+ declare abstract class OIMIndex<TKey extends TOIMPk, TPk extends TOIMPk, TBucket extends Iterable<TOIMAnyEntitySlot<TPk>>> {
67
+ protected readonly comparePks?: TOIMIndexComparator<TPk>;
68
+ protected readonly store: IOIMIndexStore<TKey, TBucket>;
69
+ readonly emitter: OIMEventEmitter<{
70
+ 0: TOIMIndexUpdatePayload<TKey>;
71
+ }>;
72
+ constructor(store: IOIMIndexStore<TKey, TBucket>, comparePks?: TOIMIndexComparator<TPk>);
73
+ protected abstract getBucketSize(bucket: TBucket): number;
74
+ hasKey(key: TKey): boolean;
75
+ getKeys(): readonly TKey[];
76
+ getKeySize(key: TKey): number;
77
+ get size(): number;
78
+ get isEmpty(): boolean;
79
+ getEntitiesByKey<TEntity extends object = object>(key: TKey): TEntity[];
80
+ getEntitiesByKeys<TEntity extends object = object>(keys: readonly TKey[]): Map<TKey, TEntity[]>;
81
+ getMetrics(): {
82
+ totalKeys: number;
83
+ totalPks: number;
84
+ averagePksPerKey: number;
85
+ maxBucketSize: number;
86
+ minBucketSize: number;
87
+ };
88
+ destroy(): void;
89
+ protected emitUpdate(keys: TKey[]): void;
90
+ protected emitUpdateOne(key: TKey): void;
91
+ protected slotsToEntities<TEntity extends object>(slots: Iterable<TOIMAnyEntitySlot<TPk>>): TEntity[];
92
+ }
93
+
26
94
  declare abstract class OIMIndexStoreSetBased<TKey extends TOIMPk, TPk extends TOIMPk> {
27
95
  abstract setOneByKey(key: TKey, slots: Set<TOIMAnyEntitySlot<TPk>>): void;
28
96
  abstract removeOneByKey(key: TKey): void;
@@ -47,24 +115,6 @@ declare abstract class OIMIndexStoreArrayBased<TKey extends TOIMPk, TPk extends
47
115
  abstract clear(): void;
48
116
  }
49
117
 
50
- type TOIMEventHandler<T> = (payload: T) => void;
51
-
52
- declare class OIMEventEmitter<T extends Record<string, unknown>> {
53
- private buckets;
54
- hasHandlers<K extends keyof T>(event: K): boolean;
55
- private getOrCreateBucket;
56
- /**
57
- * Compacts the handlers array by removing null entries (tombstones) left by handler removal.
58
- * Rebuilds the indexByHandler map with updated indices and resets the tombstone count.
59
- * This reduces array fragmentation and improves iteration performance.
60
- */
61
- private compactBucket;
62
- on<K extends keyof T>(event: K, handler: TOIMEventHandler<T[K]>): () => void;
63
- emit<K extends keyof T>(event: K, payload: T[K]): void;
64
- off<K extends keyof T>(event: K, handler: TOIMEventHandler<T[K]>): void;
65
- offAll<K extends keyof T>(event?: K): void;
66
- }
67
-
68
118
  declare enum EOIMEventQueueSchedulerEventType {
69
119
  FLUSH = 0
70
120
  }
@@ -91,182 +141,32 @@ declare abstract class OIMEventQueueScheduler {
91
141
  protected flush(): void;
92
142
  }
93
143
 
94
- /**
95
- * Payload for index update events containing the keys that were modified */
96
- interface TOIMIndexUpdatePayload<TKey> {
97
- keys: readonly TKey[];
98
- }
99
-
100
- /**
101
- * Comparator function for index primary key arrays.
102
- * Returns true if the arrays are considered equal, false if they differ. */
103
- type TOIMIndexComparator<TPk extends TOIMPk> = (existingPks: readonly TPk[], newPks: readonly TPk[]) => boolean;
104
-
105
- /**
106
- * Abstract base class for Set-based index types.
107
- * Provides common functionality and event system for key-to-PKs mappings using Set storage.
108
- */
109
- declare abstract class OIMIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk> {
110
- protected readonly comparePks?: TOIMIndexComparator<TPk>;
111
- protected readonly store: OIMIndexStoreSetBased<TKey, TPk>;
112
- protected resolveSlot?: TOIMEntitySlotResolver<TPk>;
113
- private readonly fallbackSlots;
114
- readonly emitter: OIMEventEmitter<{
115
- 0: TOIMIndexUpdatePayload<TKey>;
116
- }>;
144
+ declare abstract class OIMIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndex<TKey, TPk, Set<TOIMAnyEntitySlot<TPk>>> {
117
145
  constructor(options?: {
118
146
  comparePks?: TOIMIndexComparator<TPk>;
119
147
  store?: OIMIndexStoreSetBased<TKey, TPk>;
120
- resolveSlot?: TOIMEntitySlotResolver<TPk>;
121
148
  });
122
- /**
123
- * Get primary keys for multiple index keys
124
- */
125
- getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
126
- setSlotResolver(resolveSlot: TOIMEntitySlotResolver<TPk>): void;
127
- /**
128
- * @deprecated Use getPksByKey instead
129
- * Get primary keys for a specific index key
130
- */
131
- getPks(key: TKey): Set<TPk>;
132
- /**
133
- * Get primary keys for a specific index key
134
- */
149
+ protected getBucketSize(bucket: Set<TOIMAnyEntitySlot<TPk>>): number;
135
150
  getPksByKey(key: TKey): Set<TPk>;
151
+ getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
136
152
  getSlotsByKey(key: TKey): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
137
153
  getSlotsByKeys(keys: readonly TKey[]): Map<TKey, ReadonlySet<TOIMAnyEntitySlot<TPk>>>;
138
- /**
139
- * Check if an index key exists
140
- */
141
- hasKey(key: TKey): boolean;
142
- /**
143
- * Get all index keys
144
- */
145
- getKeys(): readonly TKey[];
146
- /**
147
- * Get the number of primary keys for a specific index key
148
- */
149
- getKeySize(key: TKey): number;
150
- /**
151
- * Get total number of index keys
152
- */
153
- get size(): number;
154
- /**
155
- * Check if the index is empty
156
- */
157
- get isEmpty(): boolean;
158
- /**
159
- * Get performance metrics for monitoring and debugging
160
- */
161
- getMetrics(): {
162
- totalKeys: number;
163
- totalPks: number;
164
- averagePksPerKey: number;
165
- maxBucketSize: number;
166
- minBucketSize: number;
167
- };
168
- /**
169
- * Clean up event listeners when index is no longer needed
170
- */
171
- destroy(): void;
172
- /**
173
- * Set primary keys for a specific index key with optional comparison.
174
- * If comparator is provided and returns true (no changes), skip the update.
175
- */
176
- protected setPksWithComparison(key: TKey, newPks: Set<TPk>): boolean;
177
- protected setSlotsWithComparison(key: TKey, newSlots: Set<TOIMAnyEntitySlot<TPk>>): boolean;
178
- protected resolveSlots(pks: Iterable<TPk>): Set<TOIMAnyEntitySlot<TPk>>;
179
- protected getOrCreateSlot(pk: TPk): TOIMAnyEntitySlot<TPk>;
180
154
  protected slotsToPks(slots: Iterable<TOIMAnyEntitySlot<TPk>>): Set<TPk>;
181
- /**
182
- * Emit update event with changed keys
183
- */
184
- protected emitUpdate(keys: TKey[]): void;
185
- /**
186
- * Emit update event for a single key (fast-path override point).
187
- */
188
- protected emitUpdateOne(key: TKey): void;
155
+ protected setSlotsWithComparison(key: TKey, newSlots: Set<TOIMAnyEntitySlot<TPk>>): boolean;
189
156
  }
190
157
 
191
- /**
192
- * Abstract base class for Array-based index types.
193
- * Provides common functionality and event system for key-to-PKs mappings using Array storage.
194
- */
195
- declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> {
196
- protected readonly comparePks?: TOIMIndexComparator<TPk>;
197
- protected readonly store: OIMIndexStoreArrayBased<TKey, TPk>;
198
- protected resolveSlot?: TOIMEntitySlotResolver<TPk>;
199
- private readonly fallbackSlots;
200
- readonly emitter: OIMEventEmitter<{
201
- 0: TOIMIndexUpdatePayload<TKey>;
202
- }>;
158
+ declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndex<TKey, TPk, TOIMAnyEntitySlot<TPk>[]> {
203
159
  constructor(options?: {
204
160
  comparePks?: TOIMIndexComparator<TPk>;
205
161
  store?: OIMIndexStoreArrayBased<TKey, TPk>;
206
- resolveSlot?: TOIMEntitySlotResolver<TPk>;
207
162
  });
208
- /**
209
- * Get primary keys for multiple index keys
210
- */
211
- getPksByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
212
- setSlotResolver(resolveSlot: TOIMEntitySlotResolver<TPk>): void;
213
- /**
214
- * Get primary keys for a specific index key
215
- */
163
+ protected getBucketSize(bucket: TOIMAnyEntitySlot<TPk>[]): number;
216
164
  getPksByKey(key: TKey): TPk[];
165
+ getPksByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
217
166
  getSlotsByKey(key: TKey): readonly TOIMAnyEntitySlot<TPk>[];
218
167
  getSlotsByKeys(keys: readonly TKey[]): Map<TKey, readonly TOIMAnyEntitySlot<TPk>[]>;
219
- /**
220
- * Check if an index key exists
221
- */
222
- hasKey(key: TKey): boolean;
223
- /**
224
- * Get all index keys
225
- */
226
- getKeys(): readonly TKey[];
227
- /**
228
- * Get the number of primary keys for a specific index key
229
- */
230
- getKeySize(key: TKey): number;
231
- /**
232
- * Get total number of index keys
233
- */
234
- get size(): number;
235
- /**
236
- * Check if the index is empty
237
- */
238
- get isEmpty(): boolean;
239
- /**
240
- * Get performance metrics for monitoring and debugging
241
- */
242
- getMetrics(): {
243
- totalKeys: number;
244
- totalPks: number;
245
- averagePksPerKey: number;
246
- maxBucketSize: number;
247
- minBucketSize: number;
248
- };
249
- /**
250
- * Clean up event listeners when index is no longer needed
251
- */
252
- destroy(): void;
253
- /**
254
- * Set primary keys for a specific index key with optional comparison.
255
- * If comparator is provided and returns true (no changes), skip the update.
256
- */
257
- protected setPksWithComparison(key: TKey, newPks: TPk[]): boolean;
258
- protected setSlotsWithComparison(key: TKey, newSlots: TOIMAnyEntitySlot<TPk>[]): boolean;
259
- protected resolveSlots(pks: readonly TPk[]): TOIMAnyEntitySlot<TPk>[];
260
- protected getOrCreateSlot(pk: TPk): TOIMAnyEntitySlot<TPk>;
261
168
  protected slotsToPks(slots: readonly TOIMAnyEntitySlot<TPk>[]): TPk[];
262
- /**
263
- * Emit update event with changed keys
264
- */
265
- protected emitUpdate(keys: TKey[]): void;
266
- /**
267
- * Emit update event for a single key (fast-path override point).
268
- */
269
- protected emitUpdateOne(key: TKey): void;
169
+ protected setSlotsWithComparison(key: TKey, newSlots: TOIMAnyEntitySlot<TPk>[]): boolean;
270
170
  }
271
171
 
272
172
  /**
@@ -392,14 +292,12 @@ interface IOIMKeyedSubscription<TKey extends TOIMPk> {
392
292
  subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
393
293
  }
394
294
 
395
- declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> implements IOIMKeyedSubscription<TKey> {
295
+ declare abstract class OIMReactiveIndex<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndex<TKey, TPk, Iterable<TOIMAnyEntitySlot<TPk>>>> implements IOIMKeyedSubscription<TKey> {
396
296
  readonly index: TIndex;
397
297
  protected readonly updateEmitter: OIMUpdateEventEmitter<TKey>;
398
298
  constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
399
- getPksByKey(key: TKey): Set<TPk>;
400
- getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
401
- getSlotsByKey(key: TKey): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
402
- getSlotsByKeys(keys: readonly TKey[]): Map<TKey, ReadonlySet<TOIMAnyEntitySlot<TPk>>>;
299
+ getEntitiesByKey<TEntity extends object = object>(key: TKey): TEntity[];
300
+ getEntitiesByKeys<TEntity extends object = object>(keys: readonly TKey[]): Map<TKey, TEntity[]>;
403
301
  hasKey(key: TKey): boolean;
404
302
  getKeys(): readonly TKey[];
405
303
  getKeySize(key: TKey): number;
@@ -427,39 +325,20 @@ declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMPk, TPk extends
427
325
  destroy(): void;
428
326
  }
429
327
 
430
- declare abstract class OIMReactiveIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> implements IOIMKeyedSubscription<TKey> {
431
- readonly index: TIndex;
432
- protected readonly updateEmitter: OIMUpdateEventEmitter<TKey>;
328
+ declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
329
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
330
+ getPksByKey(key: TKey): Set<TPk>;
331
+ getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
332
+ getSlotsByKey(key: TKey): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
333
+ getSlotsByKeys(keys: readonly TKey[]): Map<TKey, ReadonlySet<TOIMAnyEntitySlot<TPk>>>;
334
+ }
335
+
336
+ declare abstract class OIMReactiveIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
433
337
  constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
434
338
  getPksByKey(key: TKey): TPk[];
435
339
  getPksByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
436
340
  getSlotsByKey(key: TKey): readonly TOIMAnyEntitySlot<TPk>[];
437
341
  getSlotsByKeys(keys: readonly TKey[]): Map<TKey, readonly TOIMAnyEntitySlot<TPk>[]>;
438
- hasKey(key: TKey): boolean;
439
- getKeys(): readonly TKey[];
440
- getKeySize(key: TKey): number;
441
- get size(): number;
442
- get isEmpty(): boolean;
443
- getMetrics(): {
444
- totalKeys: number;
445
- totalPks: number;
446
- averagePksPerKey: number;
447
- maxBucketSize: number;
448
- minBucketSize: number;
449
- };
450
- subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
451
- subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
452
- unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
453
- unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
454
- hasSubscriptions(): boolean;
455
- getHandlerCount(key: TKey): number;
456
- getSubscriptionMetrics(): {
457
- totalKeys: number;
458
- totalHandlers: number;
459
- averageHandlersPerKey: number;
460
- queueLength: number;
461
- };
462
- destroy(): void;
463
342
  }
464
343
 
465
344
  declare abstract class OIMObjectStore<TKey extends string | number | symbol, TValue> {
@@ -504,9 +383,9 @@ declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
504
383
  getSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk> | undefined;
505
384
  getSlotsByPks(pks: readonly TPk[]): TOIMEntitySlot<TEntity, TPk>[];
506
385
  getAllSlots(): TOIMEntitySlot<TEntity, TPk>[];
507
- upsertOneByPk(pk: TPk, entity: Partial<TEntity>): void;
508
- upsertOne(entity: TEntity | Partial<TEntity>): void;
509
- upsertMany(entities: (TEntity | Partial<TEntity>)[]): void;
386
+ upsertOneByPk(pk: TPk, entity: Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
387
+ upsertOne(entity: TEntity | Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
388
+ upsertMany(entities: (TEntity | Partial<TEntity>)[]): TOIMEntitySlot<TEntity, TPk>[];
510
389
  removeOne(entity: TEntity): void;
511
390
  removeMany(entities: TEntity[]): void;
512
391
  removeOneByPk(pk: TPk): void;
@@ -515,8 +394,8 @@ declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
515
394
  countAll(): number;
516
395
  getAll(): TEntity[];
517
396
  getAllPks(): TPk[];
518
- protected upsertOneWithoutNotifications(entity: TEntity | Partial<TEntity>): TPk;
519
- protected upsertOneWithoutNotificationsByPk(pk: TPk, entity: Partial<TEntity> | TEntity): void;
397
+ protected upsertOneWithoutNotifications(entity: TEntity | Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
398
+ protected upsertOneWithoutNotificationsByPk(pk: TPk, entity: Partial<TEntity> | TEntity): TOIMEntitySlot<TEntity, TPk>;
520
399
  destroy(): void;
521
400
  }
522
401
 
@@ -543,9 +422,9 @@ declare class OIMReactiveCollection<TEntity extends object, TPk extends TOIMPk>
543
422
  queueLength: number;
544
423
  };
545
424
  subscribeOnAnyUpdate(handler: (pks: readonly TPk[]) => void): () => void;
546
- upsertOneByPk(pk: TPk, entity: Partial<TEntity>): void;
547
- upsertOne(entity: TEntity | Partial<TEntity>): void;
548
- upsertMany(entities: (TEntity | Partial<TEntity>)[]): void;
425
+ upsertOneByPk(pk: TPk, entity: Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
426
+ upsertOne(entity: TEntity | Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
427
+ upsertMany(entities: (TEntity | Partial<TEntity>)[]): TOIMEntitySlot<TEntity, TPk>[];
549
428
  removeOne(entity: TEntity): void;
550
429
  removeMany(entities: TEntity[]): void;
551
430
  removeOneByPk(pk: TPk): void;
@@ -559,52 +438,256 @@ declare class OIMReactiveCollection<TEntity extends object, TPk extends TOIMPk>
559
438
  destroy(): void;
560
439
  }
561
440
 
562
- /**
563
- * Payload type for update events that contain keys */
564
- type TOIMUpdatePayload<TKey> = {
565
- keys: readonly TKey[];
441
+ type TOIMCollectionIndexSetBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
442
+ indexOptions?: {
443
+ comparePks?: TOIMIndexComparator<TPk>;
444
+ store?: OIMIndexStoreSetBased<TKey, TPk>;
445
+ };
446
+ } & ({
447
+ collection: OIMReactiveCollection<TEntity, TPk>;
448
+ resolveSlot?: never;
449
+ } | {
450
+ collection?: never;
451
+ resolveSlot: TOIMEntitySlotResolver<TPk>;
452
+ });
453
+ type TOIMCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
454
+ indexOptions?: {
455
+ comparePks?: TOIMIndexComparator<TPk>;
456
+ store?: OIMIndexStoreArrayBased<TKey, TPk>;
457
+ };
458
+ } & ({
459
+ collection: OIMReactiveCollection<TEntity, TPk>;
460
+ resolveSlot?: never;
461
+ } | {
462
+ collection?: never;
463
+ resolveSlot: TOIMEntitySlotResolver<TPk>;
464
+ });
465
+ type TOIMCollectionOrderedIndexOptions<TEntity extends object, TPk extends TOIMPk> = {
466
+ collection: OIMReactiveCollection<TEntity, TPk>;
467
+ resolveSlot?: never;
468
+ } | {
469
+ collection?: never;
470
+ resolveSlot: TOIMEntitySlotResolver<TPk>;
471
+ };
472
+ type TOIMCollectionOrderedListCommandStreamOptions<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object> = {
473
+ index?: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
474
+ } & ({
475
+ collection: OIMReactiveCollection<TEntity, TPk>;
476
+ resolveSlot?: never;
477
+ } | {
478
+ collection?: never;
479
+ resolveSlot: TOIMEntitySlotResolver<TPk>;
480
+ });
481
+ type TOIMRelationsSetIndexOptions<TKey extends TOIMPk, TPk extends TOIMPk> = {
482
+ indexOptions?: {
483
+ comparePks?: TOIMIndexComparator<TPk>;
484
+ store?: OIMIndexStoreSetBased<TKey, TPk>;
485
+ };
486
+ };
487
+ type TOIMRelationsArrayIndexOptions<TKey extends TOIMPk, TPk extends TOIMPk> = {
488
+ indexOptions?: {
489
+ comparePks?: TOIMIndexComparator<TPk>;
490
+ store?: OIMIndexStoreArrayBased<TKey, TPk>;
491
+ };
492
+ };
493
+ type TOIMRelationsOrderedListOptions<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object> = {
494
+ index?: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
566
495
  };
496
+ type TOIMDerivedIndexKeySelector<TEntity extends object, TKey extends TOIMPk> = (entity: TEntity) => TKey | readonly TKey[] | undefined | null;
497
+ type TOIMDerivedCollectionIndexSetBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
498
+ selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>;
499
+ /**
500
+ * Build initial index state from existing collection slots.
501
+ * Defaults to true.
502
+ */
503
+ buildInitial?: boolean;
504
+ indexOptions?: TOIMCollectionIndexSetBasedOptions<TEntity, TKey, TPk>['indexOptions'];
505
+ };
506
+ type TOIMRelationsDerivedSetIndexOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = Omit<TOIMDerivedCollectionIndexSetBasedOptions<TEntity, TKey, TPk>, 'selectIndexKeys'>;
507
+ type TOIMDerivedEntityOrderValue = string | number | bigint | boolean;
508
+ type TOIMDerivedEntityOrderSelector<TEntity extends object> = (entity: TEntity) => TOIMDerivedEntityOrderValue;
509
+ type TOIMDerivedEntityComparator<TEntity extends object> = (a: TEntity, b: TEntity) => number;
510
+ type TOIMDerivedCollectionIndexArrayBasedOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = {
511
+ selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>;
512
+ /**
513
+ * Build initial index state from existing collection slots.
514
+ * Defaults to true.
515
+ */
516
+ buildInitial?: boolean;
517
+ /**
518
+ * Sort entities inside each derived index key. Takes priority over orderBy.
519
+ */
520
+ compareEntities?: TOIMDerivedEntityComparator<TEntity>;
521
+ /**
522
+ * Convenience ordering selector for common ordered-list cases.
523
+ */
524
+ orderBy?: TOIMDerivedEntityOrderSelector<TEntity>;
525
+ indexOptions?: TOIMCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>['indexOptions'];
526
+ };
527
+ type TOIMRelationsDerivedArrayIndexOptions<TEntity extends object, TKey extends TOIMPk, TPk extends TOIMPk> = Omit<TOIMDerivedCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>, 'selectIndexKeys'>;
567
528
 
568
- type TOIMObjectOptions<TKey extends string, TValue> = {
569
- store?: OIMObjectStore<TKey, TValue>;
529
+ /**
530
+ * Manual ordered Array-based index.
531
+ *
532
+ * Unlike generic Array-based indexes, this class is explicitly ordered:
533
+ * - preserves order
534
+ * - allows O(1) append (`push`)
535
+ * - supports `move` and `removeAt` without computing diffs
536
+ * - stores slots directly; collection-bound variants resolve PKs before writes
537
+ *
538
+ * It emits UPDATE events per key on every successful mutation.
539
+ */
540
+ declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TItemKey extends TOIMPk> extends OIMIndexArrayBased<TKey, TItemKey> {
541
+ clear(key?: TKey): void;
542
+ pushSlot(key: TKey, slot: TOIMAnyEntitySlot<TItemKey>): number;
543
+ insertSlotAt(key: TKey, index: number, slot: TOIMAnyEntitySlot<TItemKey>): number;
544
+ removeAt(key: TKey, index: number): TOIMAnyEntitySlot<TItemKey> | undefined;
545
+ move(key: TKey, fromIndex: number, toIndex: number): TOIMAnyEntitySlot<TItemKey> | undefined;
546
+ resetSlots(key: TKey, slots: readonly TOIMAnyEntitySlot<TItemKey>[]): void;
547
+ private getOrCreateList;
548
+ }
549
+
550
+ /**
551
+ * Collection-bound ordered Array-based index.
552
+ *
553
+ * Raw ordered indexes store slots. This variant provides PK writes and resolves
554
+ * them to canonical collection slots at construction-bound write time.
555
+ */
556
+ declare class OIMCollectionIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMIndexManualOrderedArrayBased<TKey, TPk> {
557
+ private readonly resolveSlot;
558
+ constructor(opts: TOIMCollectionOrderedIndexOptions<TEntity, TPk>);
559
+ push(key: TKey, pk: TPk): number;
560
+ insertAt(key: TKey, index: number, pk: TPk): number;
561
+ reset(key: TKey, pks: readonly TPk[]): void;
562
+ getEntitiesByKey<TItem extends object = TEntity>(key: TKey): TItem[];
563
+ getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TKey[]): Map<TKey, TItem[]>;
564
+ resolvePk(pk: TPk): TOIMAnyEntitySlot<TPk>;
565
+ private resolveSlots;
566
+ private resolveRequiredSlot;
567
+ }
568
+
569
+ type TOIMOrderedListCommand<TPk extends TOIMPk, TEntity extends object = object> = {
570
+ type: 'insert';
571
+ pk: TPk;
572
+ slot: TOIMEntitySlot<TEntity, TPk>;
573
+ index: number;
574
+ } | {
575
+ type: 'remove';
576
+ pk: TPk;
577
+ slot: TOIMEntitySlot<TEntity, TPk>;
578
+ index: number;
579
+ } | {
580
+ type: 'move';
581
+ pk: TPk;
582
+ slot: TOIMEntitySlot<TEntity, TPk>;
583
+ fromIndex: number;
584
+ toIndex: number;
585
+ } | {
586
+ /**
587
+ * Replace the whole list for this key (preferred name).
588
+ */
589
+ type: 'set';
590
+ pks: readonly TPk[];
591
+ slots: readonly TOIMEntitySlot<TEntity, TPk>[];
570
592
  };
571
593
 
572
- /** It's like a store - but with event emitter */
573
- declare class OIMObject<TKey extends string, TValue> {
574
- readonly emitter: OIMEventEmitter<{
575
- 0: TOIMUpdatePayload<TKey>;
576
- }>;
577
- protected readonly store: OIMObjectStore<TKey, TValue>;
578
- constructor(opts?: TOIMObjectOptions<TKey, TValue>);
579
- setProperty(key: TKey, value: TValue): void;
580
- merge(draft: Partial<Record<TKey, TValue>>): void;
581
- delete(key: TKey): void;
582
- get(key: TKey): TValue | undefined;
583
- getAll(): Record<TKey, TValue>;
584
- clear(): void;
585
- count(): number;
586
- keys(): TKey[];
587
- values(): TValue[];
588
- entries(): [TKey, TValue][];
594
+ /**
595
+ * Slot-first ordered-list command stream.
596
+ *
597
+ * Use this when you already have slots and want incremental commands for an
598
+ * imperative renderer. For PK writes bound to a collection, use
599
+ * `OIMCollectionOrderedListCommandStream`.
600
+ */
601
+ declare class OIMOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> {
602
+ readonly commandsEventEmitter: OIMUpdateEventEmitter<TKey>;
603
+ private readonly unsubscribeAfterFlush;
604
+ private readonly unsubscribeFromIndexEmitter;
605
+ protected isInWrite: boolean;
606
+ private readonly commandsByKey;
607
+ /** Underlying slot-first ordered index. */
608
+ readonly index: OIMIndexManualOrderedArrayBased<TKey, TPk>;
609
+ constructor(queue: OIMEventQueue, index?: OIMIndexManualOrderedArrayBased<TKey, TPk>);
610
+ getPksByKey(key: TKey): readonly TPk[];
611
+ getSlotsByKey(key: TKey): readonly TOIMEntitySlot<TEntity, TPk>[];
612
+ getEntitiesByKey(key: TKey): TEntity[];
613
+ hasKey(key: TKey): boolean;
614
+ getKeys(): readonly TKey[];
615
+ pushSlot(key: TKey, slot: TOIMEntitySlot<TEntity, TPk>): void;
616
+ insertSlotAt(key: TKey, index: number, slot: TOIMEntitySlot<TEntity, TPk>): void;
617
+ removeAt(key: TKey, index: number): void;
618
+ move(key: TKey, fromIndex: number, toIndex: number): void;
619
+ setSlots(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
620
+ getBufferedCommands(key: TKey): readonly TOIMOrderedListCommand<TPk, TEntity>[];
621
+ consumeCommands(key: TKey): TOIMOrderedListCommand<TPk, TEntity>[];
622
+ clear(key?: TKey): void;
589
623
  destroy(): void;
624
+ private readonly onAfterFlush;
625
+ private readonly onIndexUpdate;
626
+ protected withWrite(fn: () => void): void;
627
+ protected appendCommand(key: TKey, cmd: TOIMOrderedListCommand<TPk, TEntity>): void;
628
+ protected appendSetCommand(key: TKey, slots: readonly TOIMEntitySlot<TEntity, TPk>[]): void;
629
+ protected createSetCommand(slots: readonly TOIMEntitySlot<TEntity, TPk>[]): TOIMOrderedListCommand<TPk, TEntity>;
590
630
  }
591
631
 
592
- declare class OIMReactiveObject<TKey extends string, TValue> extends OIMObject<TKey, TValue> implements IOIMKeyedSubscription<TKey> {
593
- protected readonly updateEmitter: OIMUpdateEventEmitter<TKey>;
594
- constructor(queue: OIMEventQueue, opts?: TOIMObjectOptions<TKey, TValue>);
595
- subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
596
- subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
597
- unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
598
- unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
599
- hasSubscriptions(): boolean;
600
- getHandlerCount(key: TKey): number;
601
- getMetrics(): {
602
- totalKeys: number;
603
- totalHandlers: number;
604
- averageHandlersPerKey: number;
605
- queueLength: number;
606
- };
607
- destroy(): void;
632
+ /**
633
+ * Collection-bound ordered-list command stream.
634
+ *
635
+ * Public writes use PKs, internally they resolve to canonical collection slots.
636
+ */
637
+ declare class OIMCollectionOrderedListCommandStream<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMOrderedListCommandStream<TKey, TPk, TEntity> {
638
+ readonly index: OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
639
+ constructor(queue: OIMEventQueue, opts: TOIMCollectionOrderedListCommandStreamOptions<TKey, TPk, TEntity>);
640
+ push(key: TKey, pk: TPk): void;
641
+ insertAt(key: TKey, index: number, pk: TPk): void;
642
+ set(key: TKey, pks: readonly TPk[]): void;
643
+ getSlotsByKey(key: TKey): readonly TOIMEntitySlot<TEntity, TPk>[];
644
+ getEntitiesByKey(key: TKey): TEntity[];
645
+ private resolvePk;
646
+ }
647
+
648
+ /**
649
+ * Manual Array-based index that allows direct manipulation of key-to-primary-keys mappings.
650
+ * Extends the abstract OIMIndexArrayBased with manual control methods and optional comparison.
651
+ */
652
+ declare class OIMIndexManualArrayBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexArrayBased<TIndexKey, TPk> {
653
+ constructor(options?: {
654
+ comparePks?: TOIMIndexComparator<TPk>;
655
+ store?: OIMIndexStoreArrayBased<TIndexKey, TPk>;
656
+ });
657
+ setSlots(key: TIndexKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
658
+ /**
659
+ * Clear all primary keys for a specific index key, or all keys if no key specified
660
+ */
661
+ clear(key?: TIndexKey): void;
662
+ }
663
+
664
+ declare class OIMReactiveIndexManualArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMReactiveIndexArrayBased<TKey, TPk, OIMIndexManualArrayBased<TKey, TPk>> {
665
+ constructor(queue: OIMEventQueue, opts?: {
666
+ indexOptions?: {
667
+ comparePks?: TOIMIndexComparator<TPk>;
668
+ store?: OIMIndexStoreArrayBased<TKey, TPk>;
669
+ };
670
+ });
671
+ setSlots(key: TKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
672
+ clear(key?: TKey): void;
673
+ }
674
+
675
+ /**
676
+ * Collection-bound reactive Array-based index.
677
+ *
678
+ * PK writes (`setPks`/`addPks`/`removePks`) resolve canonical entity slots
679
+ * through the collection binding supplied at construction time.
680
+ */
681
+ declare class OIMReactiveCollectionIndexManualArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveIndexManualArrayBased<TKey, TPk> {
682
+ private readonly resolveSlot;
683
+ constructor(queue: OIMEventQueue, opts: TOIMCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>);
684
+ setPks(key: TKey, pks: readonly TPk[]): void;
685
+ addPks(key: TKey, pks: readonly TPk[]): void;
686
+ removePks(key: TKey, pks: readonly TPk[]): void;
687
+ getEntitiesByKey<TItem extends object = TEntity>(key: TKey): TItem[];
688
+ getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TKey[]): Map<TKey, TItem[]>;
689
+ private resolveSlots;
690
+ private resolveRequiredSlot;
608
691
  }
609
692
 
610
693
  /**
@@ -615,22 +698,8 @@ declare class OIMIndexManualSetBased<TIndexKey extends TOIMPk, TPk extends TOIMP
615
698
  constructor(options?: {
616
699
  comparePks?: TOIMIndexComparator<TPk>;
617
700
  store?: OIMIndexStoreSetBased<TIndexKey, TPk>;
618
- resolveSlot?: TOIMEntitySlotResolver<TPk>;
619
701
  });
620
- /**
621
- * Set primary keys for a specific index key, replacing any existing values.
622
- * Uses optional comparator to skip updates if PKs haven't actually changed.
623
- */
624
- setPks(key: TIndexKey, pks: TPk[]): void;
625
702
  setSlots(key: TIndexKey, slots: Iterable<TOIMAnyEntitySlot<TPk>>): void;
626
- /**
627
- * Add primary keys to a specific index key
628
- */
629
- addPks(key: TIndexKey, pks: readonly TPk[]): void;
630
- /**
631
- * Remove primary keys from a specific index key
632
- */
633
- removePks(key: TIndexKey, pks: readonly TPk[]): void;
634
703
  /**
635
704
  * Clear all primary keys for a specific index key, or all keys if no key specified
636
705
  */
@@ -642,74 +711,146 @@ declare class OIMReactiveIndexManualSetBased<TKey extends TOIMPk, TPk extends TO
642
711
  indexOptions?: {
643
712
  comparePks?: TOIMIndexComparator<TPk>;
644
713
  store?: OIMIndexStoreSetBased<TKey, TPk>;
645
- resolveSlot?: TOIMEntitySlotResolver<TPk>;
646
714
  };
647
715
  });
648
- setPks(key: TKey, pks: TPk[]): void;
649
716
  setSlots(key: TKey, slots: Iterable<TOIMAnyEntitySlot<TPk>>): void;
717
+ clear(key?: TKey): void;
718
+ }
719
+
720
+ /**
721
+ * Collection-bound reactive Set-based index.
722
+ *
723
+ * PK writes (`setPks`/`addPks`/`removePks`) resolve canonical entity slots
724
+ * through the collection binding supplied at construction time.
725
+ */
726
+ declare class OIMReactiveCollectionIndexManualSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveIndexManualSetBased<TKey, TPk> {
727
+ private readonly resolveSlot;
728
+ constructor(queue: OIMEventQueue, opts: TOIMCollectionIndexSetBasedOptions<TEntity, TKey, TPk>);
729
+ setPks(key: TKey, pks: readonly TPk[]): void;
650
730
  addPks(key: TKey, pks: readonly TPk[]): void;
651
731
  removePks(key: TKey, pks: readonly TPk[]): void;
732
+ getEntitiesByKey<TItem extends object = TEntity>(key: TKey): TItem[];
733
+ getEntitiesByKeys<TItem extends object = TEntity>(keys: readonly TKey[]): Map<TKey, TItem[]>;
734
+ private resolveSlots;
735
+ private resolveRequiredSlot;
736
+ }
737
+
738
+ /**
739
+ * Collection-bound Set-based index derived from entity data.
740
+ *
741
+ * The collection remains the source of truth. This index listens to collection
742
+ * updates and maintains key membership automatically.
743
+ */
744
+ declare class OIMDerivedCollectionIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionIndexManualSetBased<TKey, TPk, TEntity> {
745
+ private readonly collection;
746
+ private readonly selectIndexKeys;
747
+ private readonly unsubscribeFromCollection;
748
+ private readonly keysByPk;
749
+ constructor(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>, opts: TOIMDerivedCollectionIndexSetBasedOptions<TEntity, TKey, TPk>);
750
+ rebuildFromCollection(): void;
652
751
  clear(key?: TKey): void;
752
+ destroy(): void;
753
+ private readonly onCollectionUpdate;
754
+ private syncPk;
755
+ private normalizeKeys;
653
756
  }
654
757
 
655
758
  /**
656
- * Manual Array-based index that allows direct manipulation of key-to-primary-keys mappings.
657
- * Extends the abstract OIMIndexArrayBased with manual control methods and optional comparison.
759
+ * Collection-bound Array-based index derived from entity data.
760
+ *
761
+ * It maintains ordered per-key arrays automatically from collection updates.
762
+ * Use `orderBy` or `compareEntities` when list order matters.
658
763
  */
659
- declare class OIMIndexManualArrayBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexArrayBased<TIndexKey, TPk> {
660
- constructor(options?: {
661
- comparePks?: TOIMIndexComparator<TPk>;
662
- store?: OIMIndexStoreArrayBased<TIndexKey, TPk>;
663
- resolveSlot?: TOIMEntitySlotResolver<TPk>;
664
- });
665
- /**
666
- * Set primary keys for a specific index key, replacing any existing values.
667
- * Uses optional comparator to skip updates if PKs haven't actually changed.
668
- */
669
- setPks(key: TIndexKey, pks: TPk[]): void;
670
- setSlots(key: TIndexKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
671
- /**
672
- * Add primary keys to a specific index key
673
- */
674
- addPks(key: TIndexKey, pks: readonly TPk[]): void;
675
- /**
676
- * Remove primary keys from a specific index key
677
- */
678
- removePks(key: TIndexKey, pks: readonly TPk[]): void;
679
- /**
680
- * Clear all primary keys for a specific index key, or all keys if no key specified
681
- */
682
- clear(key?: TIndexKey): void;
764
+ declare class OIMDerivedCollectionIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TEntity extends object = object> extends OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity> {
765
+ private readonly collection;
766
+ private readonly selectIndexKeys;
767
+ private readonly compareEntities?;
768
+ private readonly orderBy?;
769
+ private readonly unsubscribeFromCollection;
770
+ private readonly keysByPk;
771
+ constructor(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>, opts: TOIMDerivedCollectionIndexArrayBasedOptions<TEntity, TKey, TPk>);
772
+ rebuildFromCollection(): void;
773
+ clear(key?: TKey): void;
774
+ destroy(): void;
775
+ private readonly onCollectionUpdate;
776
+ private trackPkKeys;
777
+ private rebuildKey;
778
+ private sortSlots;
779
+ private normalizeKeys;
683
780
  }
684
781
 
685
- declare class OIMReactiveIndexManualArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMReactiveIndexArrayBased<TKey, TPk, OIMIndexManualArrayBased<TKey, TPk>> {
686
- constructor(queue: OIMEventQueue, opts?: {
687
- indexOptions?: {
688
- comparePks?: TOIMIndexComparator<TPk>;
689
- store?: OIMIndexStoreArrayBased<TKey, TPk>;
690
- resolveSlot?: TOIMEntitySlotResolver<TPk>;
691
- };
692
- });
693
- setPks(key: TKey, pks: TPk[]): void;
694
- setSlots(key: TKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
695
- addPks(key: TKey, pks: readonly TPk[]): void;
696
- removePks(key: TKey, pks: readonly TPk[]): void;
697
- clear(key?: TKey): void;
782
+ /**
783
+ * Factory helper for collection-bound indexes.
784
+ *
785
+ * It does not store indexes inside the collection. It only keeps the common
786
+ * `queue + collection` binding in one place, so related structures can be
787
+ * created next to the collection with less generic noise.
788
+ */
789
+ declare class OIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMPk> {
790
+ readonly queue: OIMEventQueue;
791
+ readonly collection: OIMReactiveCollection<TEntity, TPk>;
792
+ constructor(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>);
793
+ setBasedIndex<TKey extends TOIMPk = string>(opts?: TOIMRelationsSetIndexOptions<TKey, TPk>): OIMReactiveCollectionIndexManualSetBased<TKey, TPk, TEntity>;
794
+ derivedSetIndex<TKey extends TOIMPk = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedSetIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexSetBased<TKey, TPk, TEntity>;
795
+ arrayBasedIndex<TKey extends TOIMPk = string>(opts?: TOIMRelationsArrayIndexOptions<TKey, TPk>): OIMReactiveCollectionIndexManualArrayBased<TKey, TPk, TEntity>;
796
+ derivedArrayIndex<TKey extends TOIMPk = string>(selectIndexKeys: TOIMDerivedIndexKeySelector<TEntity, TKey>, opts?: TOIMRelationsDerivedArrayIndexOptions<TEntity, TKey, TPk>): OIMDerivedCollectionIndexArrayBased<TKey, TPk, TEntity>;
797
+ orderedIndex<TKey extends TOIMPk = string>(): OIMCollectionIndexManualOrderedArrayBased<TKey, TPk, TEntity>;
798
+ orderedList<TKey extends TOIMPk = string>(opts?: TOIMRelationsOrderedListOptions<TKey, TPk, TEntity>): OIMCollectionOrderedListCommandStream<TKey, TPk, TEntity>;
698
799
  }
800
+ declare function createOIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMPk>(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>): OIMCollectionIndexFactory<TEntity, TPk>;
699
801
 
700
- type TOIMReactiveIndex<TIndexKey extends TOIMPk, TPk extends TOIMPk> = OIMReactiveIndexSetBased<TIndexKey, TPk, any> | OIMReactiveIndexArrayBased<TIndexKey, TPk, any>;
701
- declare class OIMRICollection<TEntity extends object, TPk extends TOIMPk, TIndexName extends string = string, TIndexMap extends Record<TIndexName, TOIMReactiveIndex<any, TPk>> = Record<TIndexName, TOIMReactiveIndex<any, TPk>>> extends OIMReactiveCollection<TEntity, TPk> {
702
- readonly indexes: TIndexMap;
703
- constructor(queue: OIMEventQueue, opts: {
704
- collectionOpts?: TOIMCollectionOptions<TEntity, TPk>;
705
- indexes?: TIndexMap;
706
- });
802
+ /**
803
+ * Payload type for update events that contain keys */
804
+ type TOIMUpdatePayload<TKey> = {
805
+ keys: readonly TKey[];
806
+ };
807
+
808
+ type TOIMObjectOptions<TKey extends string, TValue> = {
809
+ store?: OIMObjectStore<TKey, TValue>;
810
+ };
811
+
812
+ /** It's like a store - but with event emitter */
813
+ declare class OIMObject<TKey extends string, TValue> {
814
+ readonly emitter: OIMEventEmitter<{
815
+ 0: TOIMUpdatePayload<TKey>;
816
+ }>;
817
+ protected readonly store: OIMObjectStore<TKey, TValue>;
818
+ constructor(opts?: TOIMObjectOptions<TKey, TValue>);
819
+ setProperty(key: TKey, value: TValue): void;
820
+ merge(draft: Partial<Record<TKey, TValue>>): void;
821
+ delete(key: TKey): void;
822
+ get(key: TKey): TValue | undefined;
823
+ getAll(): Record<TKey, TValue>;
824
+ clear(): void;
825
+ count(): number;
826
+ keys(): TKey[];
827
+ values(): TValue[];
828
+ entries(): [TKey, TValue][];
829
+ destroy(): void;
830
+ }
831
+
832
+ declare class OIMReactiveObject<TKey extends string, TValue> extends OIMObject<TKey, TValue> implements IOIMKeyedSubscription<TKey> {
833
+ protected readonly updateEmitter: OIMUpdateEventEmitter<TKey>;
834
+ constructor(queue: OIMEventQueue, opts?: TOIMObjectOptions<TKey, TValue>);
835
+ subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
836
+ subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
837
+ unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
838
+ unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
839
+ hasSubscriptions(): boolean;
840
+ getHandlerCount(key: TKey): number;
841
+ getMetrics(): {
842
+ totalKeys: number;
843
+ totalHandlers: number;
844
+ averageHandlersPerKey: number;
845
+ queueLength: number;
846
+ };
847
+ destroy(): void;
707
848
  }
708
849
 
709
850
  declare class OIMCollectionStoreMapDriven<TEntity extends object, TPk extends TOIMPk> extends OIMCollectionStore<TEntity, TPk> {
710
851
  protected readonly slots: Map<TPk, TOIMEntitySlot<TEntity, TPk>>;
711
- setOneByPk(pk: TPk, entity: TEntity): void;
712
- setManyByPks(pks: readonly TPk[], entities: TEntity[]): void;
852
+ setOneByPk(pk: TPk, entity: TEntity): TOIMEntitySlot<TEntity, TPk>;
853
+ setManyByPks(pks: readonly TPk[], entities: TEntity[]): TOIMEntitySlot<TEntity, TPk>[];
713
854
  getSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk> | undefined;
714
855
  getSlotsByPks(pks: readonly TPk[]): TOIMEntitySlot<TEntity, TPk>[];
715
856
  getAllSlots(): TOIMEntitySlot<TEntity, TPk>[];
@@ -841,16 +982,107 @@ declare class OIMPkSelectorFactory<TEntity extends object, TPk extends TOIMPk> {
841
982
  }, TPk>;
842
983
  }
843
984
 
985
+ /**
986
+ * Computative runtime that schedules derived computations by levels and runs them
987
+ * on `queue.flush()` boundary (AFTER_FLUSH).
988
+ */
989
+ declare class OIMComputeRuntime {
990
+ readonly queue: OIMEventQueue;
991
+ private isFlushScheduled;
992
+ private isFlushing;
993
+ private minLevel;
994
+ private maxLevel;
995
+ private readonly dirtyByLevel;
996
+ private readonly afterFlushTasks;
997
+ constructor(queue: OIMEventQueue);
998
+ /**
999
+ * Schedule a one-shot task to run on the next `queue.flush()` (AFTER_FLUSH),
1000
+ * ordered by `level` ascending.
1001
+ */
1002
+ schedule(task: () => void, level?: number): () => void;
1003
+ /**
1004
+ * Run once at the start of the next runtime flush (i.e. after queue.flush()).
1005
+ * Useful for resubscribing dependencies exactly once per source flush.
1006
+ */
1007
+ scheduleAfterFlush(task: () => void): () => void;
1008
+ private flush;
1009
+ }
1010
+
1011
+ interface IOIMSelectorComputedDependency {
1012
+ subscribe(onUpdate: () => void): () => void;
1013
+ }
1014
+
1015
+ interface IOIMSelectorSourceDependency {
1016
+ subscribe(onUpdate: () => void): () => void;
1017
+ }
1018
+
1019
+ declare abstract class OIMSelector<TValue> {
1020
+ protected readonly runtime: OIMComputeRuntime;
1021
+ protected readonly sourceDeps: readonly IOIMSelectorSourceDependency[];
1022
+ protected readonly computedDeps: readonly IOIMSelectorComputedDependency[];
1023
+ private readonly listeners;
1024
+ private sourceUnsubscribers;
1025
+ private computedUnsubscribers;
1026
+ private dequeueResubscribe?;
1027
+ private isResubscribeEnqueued;
1028
+ private isTemporarilyUnsubscribedForFlush;
1029
+ private isDeliveryEnqueued;
1030
+ private dequeueDelivery?;
1031
+ private hasLastValue;
1032
+ private lastValue;
1033
+ protected get queue(): OIMEventQueue;
1034
+ protected constructor(runtime: OIMComputeRuntime, sourceDeps: readonly IOIMSelectorSourceDependency[], computedDeps?: readonly IOIMSelectorComputedDependency[]);
1035
+ abstract getValue(): TValue;
1036
+ /**
1037
+ * Start watching this selector. The callback is called immediately with the current value,
1038
+ * then coalesced and delivered on `queue.flush()` when the selector invalidates.
1039
+ */
1040
+ watch(onValue: (value: TValue) => void): () => void;
1041
+ protected areEqual(prev: TValue, next: TValue): boolean;
1042
+ private readonly onSourceInvalidate;
1043
+ private readonly onComputedInvalidate;
1044
+ private readonly deliver;
1045
+ private setLastValue;
1046
+ private subscribeToDeps;
1047
+ private unsubscribeFromSourceDeps;
1048
+ private unsubscribeFromAllDeps;
1049
+ private ensureResubscribeAfterFlush;
1050
+ private readonly onAfterFlush;
1051
+ }
1052
+
1053
+ type TOIMCollectionEntitySelector<TEntity extends object> = OIMSelector<TEntity | undefined>;
1054
+ type TOIMCollectionEntitiesSelector<TEntity extends object> = OIMSelector<readonly (TEntity | undefined)[]>;
1055
+
1056
+ declare class OIMCollectionSelectors<TEntity extends object, TPk extends TOIMPk> {
1057
+ private readonly collection;
1058
+ readonly runtime: OIMComputeRuntime;
1059
+ constructor(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>);
1060
+ byPk(pk: TPk): TOIMCollectionEntitySelector<TEntity>;
1061
+ byPks(pks: readonly TPk[]): TOIMCollectionEntitiesSelector<TEntity>;
1062
+ entitiesBySetIndexKey<TKey extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>>(index: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
1063
+ entitiesByArrayIndexKey<TKey extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>>(index: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey): TOIMCollectionEntitiesSelector<TEntity>;
1064
+ }
1065
+
1066
+ type TOIMReactiveCollectionFactoryOptions<TEntity extends object, TPk extends TOIMPk> = TOIMCollectionOptions<TEntity, TPk>;
1067
+ type TOIMCollectionContext<TEntity extends object, TPk extends TOIMPk> = {
1068
+ queue: OIMEventQueue;
1069
+ collection: OIMReactiveCollection<TEntity, TPk>;
1070
+ indexFactory: OIMCollectionIndexFactory<TEntity, TPk>;
1071
+ select: OIMCollectionSelectors<TEntity, TPk>;
1072
+ };
1073
+
1074
+ declare function createOIMCollectionContext<TEntity extends object, TPk extends TOIMPk>(queue: OIMEventQueue, opts?: TOIMReactiveCollectionFactoryOptions<TEntity, TPk>): TOIMCollectionContext<TEntity, TPk>;
1075
+
844
1076
  type TOIMFieldKey<TEntity extends object> = keyof TEntity & string;
845
1077
  /**
846
- * Wrapper around `OIMCollection` that tracks "changed fields" per entity PK.
1078
+ * Tracks changed fields per entity PK for an `OIMCollection`.
847
1079
  *
848
- * Important: to get field-level info, you must perform writes through this wrapper.
1080
+ * Important: to get field-level info, perform writes through this object.
849
1081
  *
850
- * DX: if the underlying collection is mutated directly (bypassing this wrapper), we detect it
851
- * via collection update events and infer changed fields by diffing the last observed entity snapshot.
1082
+ * DX: if the underlying collection is mutated directly, we detect it via collection
1083
+ * update events and infer changed fields by diffing the last observed entity snapshot.
852
1084
  */
853
- declare class OIMCollectionChangedFieldsWrapper<TEntity extends object, TPk extends TOIMPk> {
1085
+ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOIMPk> {
854
1086
  readonly collection: OIMCollection<TEntity, TPk>;
855
1087
  private readonly selectPk;
856
1088
  private readonly unsubscribeAfterFlush;
@@ -876,9 +1108,9 @@ declare class OIMCollectionChangedFieldsWrapper<TEntity extends object, TPk exte
876
1108
  */
877
1109
  selectPk?: (entity: TEntity | Partial<TEntity>) => TPk;
878
1110
  });
879
- upsertOneByPk(pk: TPk, patch: Partial<TEntity>): void;
880
- upsertOne(entity: TEntity | Partial<TEntity>): void;
881
- upsertMany(entities: (TEntity | Partial<TEntity>)[]): void;
1111
+ upsertOneByPk(pk: TPk, patch: Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
1112
+ upsertOne(entity: TEntity | Partial<TEntity>): TOIMEntitySlot<TEntity, TPk>;
1113
+ upsertMany(entities: (TEntity | Partial<TEntity>)[]): TOIMEntitySlot<TEntity, TPk>[];
882
1114
  getChangedFieldsByPk(pk: TPk): ReadonlySet<TOIMFieldKey<TEntity>>;
883
1115
  consumeChangedFieldsByPk(pk: TPk): Set<TOIMFieldKey<TEntity>>;
884
1116
  getChangedPksByField(field: TOIMFieldKey<TEntity>): ReadonlySet<TPk>;
@@ -895,91 +1127,6 @@ declare class OIMCollectionChangedFieldsWrapper<TEntity extends object, TPk exte
895
1127
  private trackPatch;
896
1128
  }
897
1129
 
898
- /**
899
- * Manual ordered Array-based index.
900
- *
901
- * Unlike `OIMIndexManualArrayBased.addPks/removePks`, this class is explicitly ordered:
902
- * - preserves order
903
- * - allows O(1) append (`push`)
904
- * - supports `move` and `removeAt` without computing diffs
905
- *
906
- * It emits UPDATE events per key on every successful mutation.
907
- */
908
- declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TItemKey extends TOIMPk> extends OIMIndexArrayBased<TKey, TItemKey> {
909
- clear(key?: TKey): void;
910
- push(key: TKey, itemKey: TItemKey): number;
911
- insertAt(key: TKey, index: number, itemKey: TItemKey): void;
912
- removeAt(key: TKey, index: number): TItemKey | undefined;
913
- move(key: TKey, fromIndex: number, toIndex: number): TItemKey | undefined;
914
- reset(key: TKey, itemKeys: readonly TItemKey[]): void;
915
- private getOrCreateList;
916
- }
917
-
918
- type TOIMOrderedListCommand<TPk extends TOIMPk> = {
919
- type: 'add';
920
- key: TPk;
921
- index: number;
922
- } | {
923
- type: 'remove';
924
- key: TPk;
925
- index: number;
926
- } | {
927
- type: 'move';
928
- key: TPk;
929
- fromIndex: number;
930
- toIndex: number;
931
- } | {
932
- /**
933
- * Replace the whole list for this key (preferred name).
934
- */
935
- type: 'set';
936
- keys: readonly TPk[];
937
- };
938
-
939
- /**
940
- * Ordered-list wrapper that stores arrays per key and emits a per-key command stream.
941
- *
942
- * This is designed for imperative renderers: instead of diffing the full list on each update,
943
- * you subscribe to `commandsEventEmitter` on a single list key and apply commands sequentially.
944
- *
945
- * Notes:
946
- * - Commands are buffered per key and delivered batched per queue flush.
947
- * - Order of commands is preserved.
948
- * - A future optimizer can collapse the command buffer into `set(...)` if needed.
949
- */
950
- declare class OIMOrderedListIndexCommandStreamWrapper<TKey extends TOIMPk, TItemKey extends TOIMPk> {
951
- readonly commandsEventEmitter: OIMUpdateEventEmitter<TKey>;
952
- private readonly unsubscribeAfterFlush;
953
- private readonly unsubscribeFromIndexEmitter;
954
- private isInWrite;
955
- private readonly commandsByKey;
956
- /** Underlying ordered index (source of truth for the list). */
957
- readonly index: OIMIndexManualOrderedArrayBased<TKey, TItemKey>;
958
- constructor(queue: OIMEventQueue, index?: OIMIndexManualOrderedArrayBased<TKey, TItemKey>);
959
- getPksByKey(key: TKey): readonly TItemKey[];
960
- hasKey(key: TKey): boolean;
961
- getKeys(): readonly TKey[];
962
- push(key: TKey, itemKey: TItemKey): void;
963
- removeAt(key: TKey, index: number): void;
964
- move(key: TKey, fromIndex: number, toIndex: number): void;
965
- set(key: TKey, keys: readonly TItemKey[]): void;
966
- /**
967
- * Read-only peek at buffered commands without clearing them.
968
- */
969
- getBufferedCommands(key: TKey): readonly TOIMOrderedListCommand<TItemKey>[];
970
- /**
971
- * Drain buffered commands for a key, preserving order.
972
- * Intended usage: call inside a `commandsEventEmitter.subscribeOnKey(key, ...)` handler.
973
- */
974
- consumeCommands(key: TKey): TOIMOrderedListCommand<TItemKey>[];
975
- clear(key?: TKey): void;
976
- destroy(): void;
977
- private readonly onAfterFlush;
978
- private readonly onIndexUpdate;
979
- private withWrite;
980
- private appendCommand;
981
- }
982
-
983
1130
  /**
984
1131
  * Animation frame-based scheduler that executes flushes synchronized with the browser's repaint cycle.
985
1132
  * Ideal for UI-related updates that need to be synchronized with rendering.
@@ -1034,13 +1181,14 @@ declare class OIMEventQueueSchedulerTimeout extends OIMEventQueueScheduler {
1034
1181
  cancel(): void;
1035
1182
  }
1036
1183
 
1184
+ type TOIMImmediateSchedulerHandle = ReturnType<typeof setImmediate> | ReturnType<typeof setTimeout> | 1;
1037
1185
  /**
1038
1186
  * Immediate-based scheduler that executes flushes using setImmediate or fallback mechanisms.
1039
1187
  * Provides faster execution than setTimeout(0) in Node.js environments.
1040
1188
  * Falls back to setTimeout(0) in browsers and MessageChannel in modern browsers for better performance.
1041
1189
  */
1042
1190
  declare class OIMEventQueueSchedulerImmediate extends OIMEventQueueScheduler {
1043
- protected immediateId?: number;
1191
+ protected immediateId?: TOIMImmediateSchedulerHandle;
1044
1192
  protected readonly useSetImmediate: boolean;
1045
1193
  protected readonly useMessageChannel: boolean;
1046
1194
  protected messageChannel?: MessageChannel;
@@ -1096,19 +1244,13 @@ type TOIMIndexKey = string | number | bigint;
1096
1244
  type TOIMIndexOptionsSetBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> = {
1097
1245
  comparePks?: TOIMIndexComparator<TPk>;
1098
1246
  store?: OIMIndexStoreSetBased<TIndexKey, TPk>;
1099
- resolveSlot?: TOIMEntitySlotResolver<TPk>;
1100
1247
  };
1101
1248
  /**
1102
1249
  * Configuration options for Array-based index instances */
1103
1250
  type TOIMIndexOptionsArrayBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> = {
1104
1251
  comparePks?: TOIMIndexComparator<TPk>;
1105
1252
  store?: OIMIndexStoreArrayBased<TIndexKey, TPk>;
1106
- resolveSlot?: TOIMEntitySlotResolver<TPk>;
1107
1253
  };
1108
- /**
1109
- * @deprecated Use TOIMIndexOptionsSetBased or TOIMIndexOptionsArrayBased instead
1110
- * Configuration options for index instances */
1111
- type TOIMIndexOptions<TIndexKey extends TOIMPk, TPk extends TOIMPk> = TOIMIndexOptionsSetBased<TIndexKey, TPk>;
1112
1254
 
1113
1255
  type TOIMIndexPksUpdatePayload<TKey extends TOIMPk, TPk extends TOIMPk> = {
1114
1256
  key: TKey;
@@ -1142,32 +1284,6 @@ type TOIMComputedUpdatePayload<TKey extends TOIMPk> = {
1142
1284
  keys: readonly TKey[];
1143
1285
  };
1144
1286
 
1145
- /**
1146
- * Computative runtime that schedules derived computations by levels and runs them
1147
- * on `queue.flush()` boundary (AFTER_FLUSH).
1148
- */
1149
- declare class OIMComputativeRuntime {
1150
- readonly queue: OIMEventQueue;
1151
- private isFlushScheduled;
1152
- private isFlushing;
1153
- private minLevel;
1154
- private maxLevel;
1155
- private readonly dirtyByLevel;
1156
- private readonly afterFlushTasks;
1157
- constructor(queue: OIMEventQueue);
1158
- /**
1159
- * Schedule a one-shot task to run on the next `queue.flush()` (AFTER_FLUSH),
1160
- * ordered by `level` ascending.
1161
- */
1162
- schedule(task: () => void, level?: number): () => void;
1163
- /**
1164
- * Run once at the start of the next runtime flush (i.e. after queue.flush()).
1165
- * Useful for resubscribing dependencies exactly once per source flush.
1166
- */
1167
- scheduleAfterFlush(task: () => void): () => void;
1168
- private flush;
1169
- }
1170
-
1171
1287
  type TOIMComputedKey$2 = 'value';
1172
1288
  declare class OIMComputed<TValue> {
1173
1289
  readonly emitter: OIMEventEmitter<{
@@ -1177,12 +1293,15 @@ declare class OIMComputed<TValue> {
1177
1293
  private readonly runtime;
1178
1294
  private readonly compute;
1179
1295
  private readonly compare;
1180
- private readonly deps;
1296
+ private readonly _deps;
1181
1297
  private value;
1182
1298
  private hasValue;
1183
1299
  private isDirty;
1184
1300
  private readonly effect;
1185
- constructor(runtime: OIMComputativeRuntime, opts: TOIMComputedOptions<TValue>);
1301
+ constructor(runtime: OIMComputeRuntime, opts: TOIMComputedOptions<TValue>);
1302
+ get needsRecompute(): boolean;
1303
+ get isReady(): boolean;
1304
+ get deps(): readonly IOIMEffectDependency[];
1186
1305
  get(): TValue;
1187
1306
  getIfReady(): TValue | undefined;
1188
1307
  destroy(): void;
@@ -1221,7 +1340,7 @@ declare class OIMEffect {
1221
1340
  private isScheduled;
1222
1341
  private dequeueScheduled?;
1223
1342
  private readonly runTask;
1224
- constructor(runtime: OIMComputativeRuntime, opts: TOIMEffectOptions);
1343
+ constructor(runtime: OIMComputeRuntime, opts: TOIMEffectOptions);
1225
1344
  destroy(): void;
1226
1345
  private onSourceInvalidate;
1227
1346
  private onComputedInvalidate;
@@ -1234,10 +1353,10 @@ declare class OIMEffect {
1234
1353
  }
1235
1354
 
1236
1355
  declare class OIMEffectDependencyKeyed<TKey extends TOIMPk> implements IOIMEffectDependency {
1237
- private readonly subscription;
1356
+ readonly source: IOIMKeyedSubscription<TKey>;
1238
1357
  private readonly key;
1239
1358
  private readonly keys;
1240
- constructor(subscription: IOIMKeyedSubscription<TKey>, keyOrKeys: TKey | readonly TKey[]);
1359
+ constructor(source: IOIMKeyedSubscription<TKey>, keyOrKeys: TKey | readonly TKey[]);
1241
1360
  subscribe(onUpdate: () => void): () => void;
1242
1361
  }
1243
1362
 
@@ -1245,6 +1364,7 @@ declare class OIMEffectDependencyKeyedObject<TKey extends string, TValue> implem
1245
1364
  private readonly dep;
1246
1365
  constructor(object: OIMReactiveObject<TKey, TValue>, key: TKey);
1247
1366
  constructor(object: OIMReactiveObject<TKey, TValue>, keys: readonly TKey[]);
1367
+ get source(): OIMReactiveObject<TKey, TValue>;
1248
1368
  subscribe(onUpdate: () => void): () => void;
1249
1369
  }
1250
1370
 
@@ -1252,6 +1372,7 @@ declare class OIMEffectDependencyKeyedCollection<TEntity extends object, TPk ext
1252
1372
  private readonly dep;
1253
1373
  constructor(collection: OIMReactiveCollection<TEntity, TPk>, pk: TPk);
1254
1374
  constructor(collection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]);
1375
+ get source(): OIMReactiveCollection<TEntity, TPk>;
1255
1376
  subscribe(onUpdate: () => void): () => void;
1256
1377
  }
1257
1378
 
@@ -1259,6 +1380,7 @@ declare class OIMEffectDependencyKeyedIndex<TKey extends TOIMPk> implements IOIM
1259
1380
  private readonly dep;
1260
1381
  constructor(index: IOIMKeyedSubscription<TKey>, key: TKey);
1261
1382
  constructor(index: IOIMKeyedSubscription<TKey>, keys: readonly TKey[]);
1383
+ get source(): IOIMKeyedSubscription<TKey>;
1262
1384
  subscribe(onUpdate: () => void): () => void;
1263
1385
  }
1264
1386
 
@@ -1273,64 +1395,22 @@ type TOIMComputedLike = {
1273
1395
  * Effect dependency on a computed.
1274
1396
  */
1275
1397
  declare class OIMEffectDependencyComputed implements IOIMEffectDependency {
1276
- private readonly computed;
1277
- constructor(computed: TOIMComputedLike);
1278
- subscribe(onUpdate: () => void): () => void;
1279
- }
1280
-
1281
- interface IOIMSelectorComputedDependency {
1282
- subscribe(onUpdate: () => void): () => void;
1283
- }
1284
-
1285
- interface IOIMSelectorSourceDependency {
1398
+ readonly source: TOIMComputedLike;
1399
+ constructor(source: TOIMComputedLike);
1286
1400
  subscribe(onUpdate: () => void): () => void;
1287
1401
  }
1288
1402
 
1289
- declare abstract class OIMSelector<TValue> {
1290
- protected readonly runtime: OIMComputativeRuntime;
1291
- protected readonly sourceDeps: readonly IOIMSelectorSourceDependency[];
1292
- protected readonly computedDeps: readonly IOIMSelectorComputedDependency[];
1293
- private readonly listeners;
1294
- private sourceUnsubscribers;
1295
- private computedUnsubscribers;
1296
- private dequeueResubscribe?;
1297
- private isResubscribeEnqueued;
1298
- private isTemporarilyUnsubscribedForFlush;
1299
- private isDeliveryEnqueued;
1300
- private dequeueDelivery?;
1301
- private hasLastValue;
1302
- private lastValue;
1303
- protected get queue(): OIMEventQueue;
1304
- protected constructor(runtime: OIMComputativeRuntime, sourceDeps: readonly IOIMSelectorSourceDependency[], computedDeps?: readonly IOIMSelectorComputedDependency[]);
1305
- abstract getValue(): TValue;
1306
- /**
1307
- * Start watching this selector. The callback is called immediately with the current value,
1308
- * then coalesced and delivered on `queue.flush()` when the selector invalidates.
1309
- */
1310
- watch(onValue: (value: TValue) => void): () => void;
1311
- protected areEqual(prev: TValue, next: TValue): boolean;
1312
- private readonly onSourceInvalidate;
1313
- private readonly onComputedInvalidate;
1314
- private readonly deliver;
1315
- private setLastValue;
1316
- private subscribeToDeps;
1317
- private unsubscribeFromSourceDeps;
1318
- private unsubscribeFromAllDeps;
1319
- private ensureResubscribeAfterFlush;
1320
- private readonly onAfterFlush;
1321
- }
1322
-
1323
1403
  declare class OIMCollectionByPkSelector<TEntity extends object, TPk extends TOIMPk> extends OIMSelector<TEntity | undefined> {
1324
1404
  private readonly collection;
1325
1405
  private readonly pk;
1326
- constructor(runtime: OIMComputativeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pk: TPk);
1406
+ constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pk: TPk);
1327
1407
  getValue(): TEntity | undefined;
1328
1408
  }
1329
1409
 
1330
1410
  declare class OIMCollectionByPksSelector<TEntity extends object, TPk extends TOIMPk> extends OIMSelector<readonly (TEntity | undefined)[]> {
1331
1411
  private readonly collection;
1332
1412
  private readonly pks;
1333
- constructor(runtime: OIMComputativeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]);
1413
+ constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]);
1334
1414
  getValue(): readonly (TEntity | undefined)[];
1335
1415
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1336
1416
  }
@@ -1338,14 +1418,14 @@ declare class OIMCollectionByPksSelector<TEntity extends object, TPk extends TOI
1338
1418
  declare class OIMObjectValueByKeySelector<TKey extends string, TValue> extends OIMSelector<TValue | undefined> {
1339
1419
  private readonly obj;
1340
1420
  private readonly key;
1341
- constructor(runtime: OIMComputativeRuntime, obj: OIMReactiveObject<TKey, TValue>, key: TKey);
1421
+ constructor(runtime: OIMComputeRuntime, obj: OIMReactiveObject<TKey, TValue>, key: TKey);
1342
1422
  getValue(): TValue | undefined;
1343
1423
  }
1344
1424
 
1345
1425
  declare class OIMObjectValuesByKeysSelector<TKey extends string, TValue> extends OIMSelector<readonly (TValue | undefined)[]> {
1346
1426
  private readonly obj;
1347
1427
  private readonly keys;
1348
- constructor(runtime: OIMComputativeRuntime, obj: OIMReactiveObject<TKey, TValue>, keys: readonly TKey[]);
1428
+ constructor(runtime: OIMComputeRuntime, obj: OIMReactiveObject<TKey, TValue>, keys: readonly TKey[]);
1349
1429
  getValue(): readonly (TValue | undefined)[];
1350
1430
  protected areEqual(prev: readonly (TValue | undefined)[], next: readonly (TValue | undefined)[]): boolean;
1351
1431
  }
@@ -1353,14 +1433,14 @@ declare class OIMObjectValuesByKeysSelector<TKey extends string, TValue> extends
1353
1433
  declare class OIMIndexPksByKeySetBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<Set<TPk>> {
1354
1434
  private readonly reactiveIndex;
1355
1435
  private readonly key;
1356
- constructor(runtime: OIMComputativeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey);
1436
+ constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey);
1357
1437
  getValue(): Set<TPk>;
1358
1438
  }
1359
1439
 
1360
1440
  declare class OIMIndexPksByKeyArrayBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
1361
1441
  private readonly reactiveIndex;
1362
1442
  private readonly key;
1363
- constructor(runtime: OIMComputativeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey);
1443
+ constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey);
1364
1444
  getValue(): readonly TPk[];
1365
1445
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
1366
1446
  }
@@ -1368,7 +1448,7 @@ declare class OIMIndexPksByKeyArrayBasedSelector<TKey extends TOIMPk, TPk extend
1368
1448
  declare class OIMIndexPksByKeysSetBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
1369
1449
  private readonly reactiveIndex;
1370
1450
  private readonly keys;
1371
- constructor(runtime: OIMComputativeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
1451
+ constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
1372
1452
  getValue(): readonly TPk[];
1373
1453
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
1374
1454
  }
@@ -1376,7 +1456,7 @@ declare class OIMIndexPksByKeysSetBasedSelector<TKey extends TOIMPk, TPk extends
1376
1456
  declare class OIMIndexPksByKeysArrayBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
1377
1457
  private readonly reactiveIndex;
1378
1458
  private readonly keys;
1379
- constructor(runtime: OIMComputativeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
1459
+ constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
1380
1460
  getValue(): readonly TPk[];
1381
1461
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
1382
1462
  }
@@ -1385,7 +1465,7 @@ declare class OIMEntitiesByIndexKeySetBasedSelector<TEntity extends object, TPk
1385
1465
  private readonly collection;
1386
1466
  private readonly reactiveIndex;
1387
1467
  private readonly key;
1388
- constructor(runtime: OIMComputativeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey);
1468
+ constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey);
1389
1469
  getValue(): readonly (TEntity | undefined)[];
1390
1470
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1391
1471
  }
@@ -1394,9 +1474,9 @@ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TP
1394
1474
  private readonly collection;
1395
1475
  private readonly reactiveIndex;
1396
1476
  private readonly key;
1397
- constructor(runtime: OIMComputativeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey);
1477
+ constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey);
1398
1478
  getValue(): readonly (TEntity | undefined)[];
1399
1479
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1400
1480
  }
1401
1481
 
1402
- export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFieldsWrapper, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputativeRuntime, OIMComputed, OIMDBSettings, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerTimeout, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListIndexCommandStreamWrapper, OIMPkSelectorFactory, OIMRICollection, OIMReactiveCollection, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMEffectOptions, type TOIMEntitySlot, type TOIMEntitySlotResolver, type TOIMEntityUpdater, type TOIMEventHandler, type TOIMEventQueueOptions, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptions, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMPk, type TOIMPkSelector, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload };
1482
+ export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexStore, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerTimeout, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandStream, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionContext, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexSetBasedOptions, type TOIMCollectionOptions, type TOIMCollectionOrderedIndexOptions, type TOIMCollectionOrderedListCommandStreamOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMDerivedCollectionIndexArrayBasedOptions, type TOIMDerivedCollectionIndexSetBasedOptions, type TOIMDerivedEntityComparator, type TOIMDerivedEntityOrderSelector, type TOIMDerivedEntityOrderValue, type TOIMDerivedIndexKeySelector, type TOIMEffectOptions, type TOIMEntitySlot, type TOIMEntitySlotResolver, type TOIMEntityUpdater, type TOIMEventHandler, type TOIMEventQueueOptions, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsDerivedArrayIndexOptions, type TOIMRelationsDerivedSetIndexOptions, type TOIMRelationsOrderedListOptions, type TOIMRelationsSetIndexOptions, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload, createOIMCollectionContext, createOIMCollectionIndexFactory };