@oimdb/core 1.4.1 → 2.0.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,7 +1,17 @@
1
1
  type TOIMPk = string | number;
2
2
 
3
+ type TOIMEntitySlot<TEntity extends object, TPk extends TOIMPk> = {
4
+ pk: TPk;
5
+ item: TEntity | undefined;
6
+ };
7
+ type TOIMAnyEntitySlot<TPk extends TOIMPk> = TOIMEntitySlot<object, TPk>;
8
+ type TOIMEntitySlotResolver<TPk extends TOIMPk> = (pk: TPk) => TOIMAnyEntitySlot<TPk> | undefined;
9
+
3
10
  declare abstract class OIMCollectionStore<TEntity extends object, TPk extends TOIMPk> {
4
- abstract setOneByPk(pk: TPk, entity: TEntity): void;
11
+ abstract setOneByPk(pk: TPk, entity: TEntity): TOIMEntitySlot<TEntity, TPk>;
12
+ abstract getSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk> | undefined;
13
+ abstract getSlotsByPks(pks: readonly TPk[]): TOIMEntitySlot<TEntity, TPk>[];
14
+ abstract getAllSlots(): TOIMEntitySlot<TEntity, TPk>[];
5
15
  abstract removeOneByPk(pk: TPk): void;
6
16
  abstract removeManyByPks(pks: readonly TPk[]): void;
7
17
  abstract getOneByPk(pk: TPk): TEntity | undefined;
@@ -13,30 +23,6 @@ declare abstract class OIMCollectionStore<TEntity extends object, TPk extends TO
13
23
  abstract destroy(): void;
14
24
  }
15
25
 
16
- declare abstract class OIMIndexStoreSetBased<TKey extends TOIMPk, TPk extends TOIMPk> {
17
- abstract setOneByKey(key: TKey, pks: Set<TPk>): void;
18
- abstract removeOneByKey(key: TKey): void;
19
- abstract removeManyByKeys(keys: readonly TKey[]): void;
20
- abstract getOneByKey(key: TKey): Set<TPk> | undefined;
21
- abstract getManyByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
22
- abstract getAllKeys(): TKey[];
23
- abstract getAll(): Map<TKey, Set<TPk>>;
24
- abstract countAll(): number;
25
- abstract clear(): void;
26
- }
27
-
28
- declare abstract class OIMIndexStoreArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> {
29
- abstract setOneByKey(key: TKey, pks: TPk[]): void;
30
- abstract removeOneByKey(key: TKey): void;
31
- abstract removeManyByKeys(keys: readonly TKey[]): void;
32
- abstract getOneByKey(key: TKey): TPk[] | undefined;
33
- abstract getManyByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
34
- abstract getAllKeys(): TKey[];
35
- abstract getAll(): Map<TKey, TPk[]>;
36
- abstract countAll(): number;
37
- abstract clear(): void;
38
- }
39
-
40
26
  type TOIMEventHandler<T> = (payload: T) => void;
41
27
 
42
28
  declare class OIMEventEmitter<T extends Record<string, unknown>> {
@@ -55,32 +41,6 @@ declare class OIMEventEmitter<T extends Record<string, unknown>> {
55
41
  offAll<K extends keyof T>(event?: K): void;
56
42
  }
57
43
 
58
- declare enum EOIMEventQueueSchedulerEventType {
59
- FLUSH = 0
60
- }
61
-
62
- /**
63
- * Events that can be emitted by the scheduler. */
64
- interface IOIMEventQueueSchedulerEvents extends Record<string, unknown> {
65
- [EOIMEventQueueSchedulerEventType.FLUSH]: void;
66
- }
67
-
68
- /**
69
- * Abstract base class for event queue schedulers.
70
- * Provides common event emission functionality while leaving scheduling strategy to subclasses.
71
- */
72
- declare abstract class OIMEventQueueScheduler {
73
- protected readonly emitter: OIMEventEmitter<IOIMEventQueueSchedulerEvents>;
74
- abstract schedule(): void;
75
- abstract cancel(): void;
76
- on<K extends keyof IOIMEventQueueSchedulerEvents>(event: K, handler: TOIMEventHandler<IOIMEventQueueSchedulerEvents[K]>): void;
77
- off<K extends keyof IOIMEventQueueSchedulerEvents>(event: K, handler: TOIMEventHandler<IOIMEventQueueSchedulerEvents[K]>): void;
78
- /**
79
- * Trigger a flush event. Should be called by subclasses when they execute the scheduled flush.
80
- */
81
- protected flush(): void;
82
- }
83
-
84
44
  /**
85
45
  * Payload for index update events containing the keys that were modified */
86
46
  interface TOIMIndexUpdatePayload<TKey> {
@@ -92,56 +52,32 @@ interface TOIMIndexUpdatePayload<TKey> {
92
52
  * Returns true if the arrays are considered equal, false if they differ. */
93
53
  type TOIMIndexComparator<TPk extends TOIMPk> = (existingPks: readonly TPk[], newPks: readonly TPk[]) => boolean;
94
54
 
95
- /**
96
- * Abstract base class for Set-based index types.
97
- * Provides common functionality and event system for key-to-PKs mappings using Set storage.
98
- */
99
- declare abstract class OIMIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk> {
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>>> {
100
67
  protected readonly comparePks?: TOIMIndexComparator<TPk>;
101
- protected readonly store: OIMIndexStoreSetBased<TKey, TPk>;
68
+ protected readonly store: IOIMIndexStore<TKey, TBucket>;
102
69
  readonly emitter: OIMEventEmitter<{
103
70
  0: TOIMIndexUpdatePayload<TKey>;
104
71
  }>;
105
- constructor(options?: {
106
- comparePks?: TOIMIndexComparator<TPk>;
107
- store?: OIMIndexStoreSetBased<TKey, TPk>;
108
- });
109
- /**
110
- * Get primary keys for multiple index keys
111
- */
112
- getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
113
- /**
114
- * @deprecated Use getPksByKey instead
115
- * Get primary keys for a specific index key
116
- */
117
- getPks(key: TKey): Set<TPk>;
118
- /**
119
- * Get primary keys for a specific index key
120
- */
121
- getPksByKey(key: TKey): Set<TPk>;
122
- /**
123
- * Check if an index key exists
124
- */
72
+ constructor(store: IOIMIndexStore<TKey, TBucket>, comparePks?: TOIMIndexComparator<TPk>);
73
+ protected abstract getBucketSize(bucket: TBucket): number;
125
74
  hasKey(key: TKey): boolean;
126
- /**
127
- * Get all index keys
128
- */
129
75
  getKeys(): readonly TKey[];
130
- /**
131
- * Get the number of primary keys for a specific index key
132
- */
133
76
  getKeySize(key: TKey): number;
134
- /**
135
- * Get total number of index keys
136
- */
137
77
  get size(): number;
138
- /**
139
- * Check if the index is empty
140
- */
141
78
  get isEmpty(): boolean;
142
- /**
143
- * Get performance metrics for monitoring and debugging
144
- */
79
+ getEntitiesByKey<TEntity extends object = object>(key: TKey): TEntity[];
80
+ getEntitiesByKeys<TEntity extends object = object>(keys: readonly TKey[]): Map<TKey, TEntity[]>;
145
81
  getMetrics(): {
146
82
  totalKeys: number;
147
83
  totalPks: number;
@@ -149,94 +85,88 @@ declare abstract class OIMIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk>
149
85
  maxBucketSize: number;
150
86
  minBucketSize: number;
151
87
  };
152
- /**
153
- * Clean up event listeners when index is no longer needed
154
- */
155
88
  destroy(): void;
156
- /**
157
- * Set primary keys for a specific index key with optional comparison.
158
- * If comparator is provided and returns true (no changes), skip the update.
159
- */
160
- protected setPksWithComparison(key: TKey, newPks: Set<TPk>): boolean;
161
- /**
162
- * Emit update event with changed keys
163
- */
164
89
  protected emitUpdate(keys: TKey[]): void;
165
- /**
166
- * Emit update event for a single key (fast-path override point).
167
- */
168
90
  protected emitUpdateOne(key: TKey): void;
91
+ protected slotsToEntities<TEntity extends object>(slots: Iterable<TOIMAnyEntitySlot<TPk>>): TEntity[];
92
+ }
93
+
94
+ declare abstract class OIMIndexStoreSetBased<TKey extends TOIMPk, TPk extends TOIMPk> {
95
+ abstract setOneByKey(key: TKey, slots: Set<TOIMAnyEntitySlot<TPk>>): void;
96
+ abstract removeOneByKey(key: TKey): void;
97
+ abstract removeManyByKeys(keys: readonly TKey[]): void;
98
+ abstract getOneByKey(key: TKey): Set<TOIMAnyEntitySlot<TPk>> | undefined;
99
+ abstract getManyByKeys(keys: readonly TKey[]): Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
100
+ abstract getAllKeys(): TKey[];
101
+ abstract getAll(): Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
102
+ abstract countAll(): number;
103
+ abstract clear(): void;
104
+ }
105
+
106
+ declare abstract class OIMIndexStoreArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> {
107
+ abstract setOneByKey(key: TKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
108
+ abstract removeOneByKey(key: TKey): void;
109
+ abstract removeManyByKeys(keys: readonly TKey[]): void;
110
+ abstract getOneByKey(key: TKey): TOIMAnyEntitySlot<TPk>[] | undefined;
111
+ abstract getManyByKeys(keys: readonly TKey[]): Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
112
+ abstract getAllKeys(): TKey[];
113
+ abstract getAll(): Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
114
+ abstract countAll(): number;
115
+ abstract clear(): void;
116
+ }
117
+
118
+ declare enum EOIMEventQueueSchedulerEventType {
119
+ FLUSH = 0
169
120
  }
170
121
 
171
122
  /**
172
- * Abstract base class for Array-based index types.
173
- * Provides common functionality and event system for key-to-PKs mappings using Array storage.
123
+ * Events that can be emitted by the scheduler. */
124
+ interface IOIMEventQueueSchedulerEvents extends Record<string, unknown> {
125
+ [EOIMEventQueueSchedulerEventType.FLUSH]: void;
126
+ }
127
+
128
+ /**
129
+ * Abstract base class for event queue schedulers.
130
+ * Provides common event emission functionality while leaving scheduling strategy to subclasses.
174
131
  */
175
- declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> {
176
- protected readonly comparePks?: TOIMIndexComparator<TPk>;
177
- protected readonly store: OIMIndexStoreArrayBased<TKey, TPk>;
178
- readonly emitter: OIMEventEmitter<{
179
- 0: TOIMIndexUpdatePayload<TKey>;
180
- }>;
132
+ declare abstract class OIMEventQueueScheduler {
133
+ protected readonly emitter: OIMEventEmitter<IOIMEventQueueSchedulerEvents>;
134
+ abstract schedule(): void;
135
+ abstract cancel(): void;
136
+ on<K extends keyof IOIMEventQueueSchedulerEvents>(event: K, handler: TOIMEventHandler<IOIMEventQueueSchedulerEvents[K]>): void;
137
+ off<K extends keyof IOIMEventQueueSchedulerEvents>(event: K, handler: TOIMEventHandler<IOIMEventQueueSchedulerEvents[K]>): void;
138
+ /**
139
+ * Trigger a flush event. Should be called by subclasses when they execute the scheduled flush.
140
+ */
141
+ protected flush(): void;
142
+ }
143
+
144
+ declare abstract class OIMIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndex<TKey, TPk, Set<TOIMAnyEntitySlot<TPk>>> {
145
+ constructor(options?: {
146
+ comparePks?: TOIMIndexComparator<TPk>;
147
+ store?: OIMIndexStoreSetBased<TKey, TPk>;
148
+ });
149
+ protected getBucketSize(bucket: Set<TOIMAnyEntitySlot<TPk>>): number;
150
+ getPksByKey(key: TKey): Set<TPk>;
151
+ getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
152
+ getSlotsByKey(key: TKey): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
153
+ getSlotsByKeys(keys: readonly TKey[]): Map<TKey, ReadonlySet<TOIMAnyEntitySlot<TPk>>>;
154
+ protected slotsToPks(slots: Iterable<TOIMAnyEntitySlot<TPk>>): Set<TPk>;
155
+ protected setSlotsWithComparison(key: TKey, newSlots: Set<TOIMAnyEntitySlot<TPk>>): boolean;
156
+ }
157
+
158
+ declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndex<TKey, TPk, TOIMAnyEntitySlot<TPk>[]> {
181
159
  constructor(options?: {
182
160
  comparePks?: TOIMIndexComparator<TPk>;
183
161
  store?: OIMIndexStoreArrayBased<TKey, TPk>;
184
162
  });
185
- /**
186
- * Get primary keys for multiple index keys
187
- */
188
- getPksByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
189
- /**
190
- * Get primary keys for a specific index key
191
- */
163
+ protected getBucketSize(bucket: TOIMAnyEntitySlot<TPk>[]): number;
192
164
  getPksByKey(key: TKey): TPk[];
193
- /**
194
- * Check if an index key exists
195
- */
196
- hasKey(key: TKey): boolean;
197
- /**
198
- * Get all index keys
199
- */
200
- getKeys(): readonly TKey[];
201
- /**
202
- * Get the number of primary keys for a specific index key
203
- */
204
- getKeySize(key: TKey): number;
205
- /**
206
- * Get total number of index keys
207
- */
208
- get size(): number;
209
- /**
210
- * Check if the index is empty
211
- */
212
- get isEmpty(): boolean;
213
- /**
214
- * Get performance metrics for monitoring and debugging
215
- */
216
- getMetrics(): {
217
- totalKeys: number;
218
- totalPks: number;
219
- averagePksPerKey: number;
220
- maxBucketSize: number;
221
- minBucketSize: number;
222
- };
223
- /**
224
- * Clean up event listeners when index is no longer needed
225
- */
226
- destroy(): void;
227
- /**
228
- * Set primary keys for a specific index key with optional comparison.
229
- * If comparator is provided and returns true (no changes), skip the update.
230
- */
231
- protected setPksWithComparison(key: TKey, newPks: TPk[]): boolean;
232
- /**
233
- * Emit update event with changed keys
234
- */
235
- protected emitUpdate(keys: TKey[]): void;
236
- /**
237
- * Emit update event for a single key (fast-path override point).
238
- */
239
- protected emitUpdateOne(key: TKey): void;
165
+ getPksByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
166
+ getSlotsByKey(key: TKey): readonly TOIMAnyEntitySlot<TPk>[];
167
+ getSlotsByKeys(keys: readonly TKey[]): Map<TKey, readonly TOIMAnyEntitySlot<TPk>[]>;
168
+ protected slotsToPks(slots: readonly TOIMAnyEntitySlot<TPk>[]): TPk[];
169
+ protected setSlotsWithComparison(key: TKey, newSlots: TOIMAnyEntitySlot<TPk>[]): boolean;
240
170
  }
241
171
 
242
172
  /**
@@ -362,12 +292,12 @@ interface IOIMKeyedSubscription<TKey extends TOIMPk> {
362
292
  subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
363
293
  }
364
294
 
365
- 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> {
366
296
  readonly index: TIndex;
367
297
  protected readonly updateEmitter: OIMUpdateEventEmitter<TKey>;
368
298
  constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
369
- getPksByKey(key: TKey): Set<TPk>;
370
- getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
299
+ getEntitiesByKey<TEntity extends object = object>(key: TKey): TEntity[];
300
+ getEntitiesByKeys<TEntity extends object = object>(keys: readonly TKey[]): Map<TKey, TEntity[]>;
371
301
  hasKey(key: TKey): boolean;
372
302
  getKeys(): readonly TKey[];
373
303
  getKeySize(key: TKey): number;
@@ -395,37 +325,20 @@ declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMPk, TPk extends
395
325
  destroy(): void;
396
326
  }
397
327
 
398
- declare abstract class OIMReactiveIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> implements IOIMKeyedSubscription<TKey> {
399
- readonly index: TIndex;
400
- 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> {
401
337
  constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
402
338
  getPksByKey(key: TKey): TPk[];
403
339
  getPksByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
404
- hasKey(key: TKey): boolean;
405
- getKeys(): readonly TKey[];
406
- getKeySize(key: TKey): number;
407
- get size(): number;
408
- get isEmpty(): boolean;
409
- getMetrics(): {
410
- totalKeys: number;
411
- totalPks: number;
412
- averagePksPerKey: number;
413
- maxBucketSize: number;
414
- minBucketSize: number;
415
- };
416
- subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
417
- subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
418
- unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
419
- unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
420
- hasSubscriptions(): boolean;
421
- getHandlerCount(key: TKey): number;
422
- getSubscriptionMetrics(): {
423
- totalKeys: number;
424
- totalHandlers: number;
425
- averageHandlersPerKey: number;
426
- queueLength: number;
427
- };
428
- destroy(): void;
340
+ getSlotsByKey(key: TKey): readonly TOIMAnyEntitySlot<TPk>[];
341
+ getSlotsByKeys(keys: readonly TKey[]): Map<TKey, readonly TOIMAnyEntitySlot<TPk>[]>;
429
342
  }
430
343
 
431
344
  declare abstract class OIMObjectStore<TKey extends string | number | symbol, TValue> {
@@ -467,9 +380,12 @@ declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
467
380
  constructor(opts?: TOIMCollectionOptions<TEntity, TPk>);
468
381
  getOneByPk(pk: TPk): TEntity | undefined;
469
382
  getManyByPks(pks: readonly TPk[]): TEntity[];
470
- upsertOneByPk(pk: TPk, entity: Partial<TEntity>): void;
471
- upsertOne(entity: TEntity | Partial<TEntity>): void;
472
- upsertMany(entities: (TEntity | Partial<TEntity>)[]): void;
383
+ getSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk> | undefined;
384
+ getSlotsByPks(pks: readonly TPk[]): TOIMEntitySlot<TEntity, TPk>[];
385
+ getAllSlots(): TOIMEntitySlot<TEntity, TPk>[];
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>[];
473
389
  removeOne(entity: TEntity): void;
474
390
  removeMany(entities: TEntity[]): void;
475
391
  removeOneByPk(pk: TPk): void;
@@ -478,8 +394,8 @@ declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
478
394
  countAll(): number;
479
395
  getAll(): TEntity[];
480
396
  getAllPks(): TPk[];
481
- protected upsertOneWithoutNotifications(entity: TEntity | Partial<TEntity>): TPk;
482
- 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>;
483
399
  destroy(): void;
484
400
  }
485
401
 
@@ -506,9 +422,9 @@ declare class OIMReactiveCollection<TEntity extends object, TPk extends TOIMPk>
506
422
  queueLength: number;
507
423
  };
508
424
  subscribeOnAnyUpdate(handler: (pks: readonly TPk[]) => void): () => void;
509
- upsertOneByPk(pk: TPk, entity: Partial<TEntity>): void;
510
- upsertOne(entity: TEntity | Partial<TEntity>): void;
511
- 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>[];
512
428
  removeOne(entity: TEntity): void;
513
429
  removeMany(entities: TEntity[]): void;
514
430
  removeOneByPk(pk: TPk): void;
@@ -522,149 +438,422 @@ declare class OIMReactiveCollection<TEntity extends object, TPk extends TOIMPk>
522
438
  destroy(): void;
523
439
  }
524
440
 
525
- /**
526
- * Payload type for update events that contain keys */
527
- type TOIMUpdatePayload<TKey> = {
528
- 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
+ };
529
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>;
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'>;
530
528
 
531
- type TOIMObjectOptions<TKey extends string, TValue> = {
532
- 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>[];
533
592
  };
534
593
 
535
- /** It's like a store - but with event emitter */
536
- declare class OIMObject<TKey extends string, TValue> {
537
- readonly emitter: OIMEventEmitter<{
538
- 0: TOIMUpdatePayload<TKey>;
539
- }>;
540
- protected readonly store: OIMObjectStore<TKey, TValue>;
541
- constructor(opts?: TOIMObjectOptions<TKey, TValue>);
542
- setProperty(key: TKey, value: TValue): void;
543
- merge(draft: Partial<Record<TKey, TValue>>): void;
544
- delete(key: TKey): void;
545
- get(key: TKey): TValue | undefined;
546
- getAll(): Record<TKey, TValue>;
547
- clear(): void;
548
- count(): number;
549
- keys(): TKey[];
550
- values(): TValue[];
551
- 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;
552
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>;
553
630
  }
554
631
 
555
- declare class OIMReactiveObject<TKey extends string, TValue> extends OIMObject<TKey, TValue> implements IOIMKeyedSubscription<TKey> {
556
- protected readonly updateEmitter: OIMUpdateEventEmitter<TKey>;
557
- constructor(queue: OIMEventQueue, opts?: TOIMObjectOptions<TKey, TValue>);
558
- subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
559
- subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
560
- unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
561
- unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
562
- hasSubscriptions(): boolean;
563
- getHandlerCount(key: TKey): number;
564
- getMetrics(): {
565
- totalKeys: number;
566
- totalHandlers: number;
567
- averageHandlersPerKey: number;
568
- queueLength: number;
569
- };
570
- 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;
571
646
  }
572
647
 
573
648
  /**
574
- * Manual Set-based index that allows direct manipulation of key-to-primary-keys mappings.
575
- * Extends the abstract OIMIndexSetBased with manual control methods and optional comparison.
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.
576
651
  */
577
- declare class OIMIndexManualSetBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexSetBased<TIndexKey, TPk> {
652
+ declare class OIMIndexManualArrayBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexArrayBased<TIndexKey, TPk> {
578
653
  constructor(options?: {
579
654
  comparePks?: TOIMIndexComparator<TPk>;
580
- store?: OIMIndexStoreSetBased<TIndexKey, TPk>;
655
+ store?: OIMIndexStoreArrayBased<TIndexKey, TPk>;
581
656
  });
582
- /**
583
- * Set primary keys for a specific index key, replacing any existing values.
584
- * Uses optional comparator to skip updates if PKs haven't actually changed.
585
- */
586
- setPks(key: TIndexKey, pks: TPk[]): void;
587
- /**
588
- * Add primary keys to a specific index key
589
- */
590
- addPks(key: TIndexKey, pks: readonly TPk[]): void;
591
- /**
592
- * Remove primary keys from a specific index key
593
- */
594
- removePks(key: TIndexKey, pks: readonly TPk[]): void;
657
+ setSlots(key: TIndexKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
595
658
  /**
596
659
  * Clear all primary keys for a specific index key, or all keys if no key specified
597
660
  */
598
661
  clear(key?: TIndexKey): void;
599
662
  }
600
663
 
601
- declare class OIMReactiveIndexManualSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMReactiveIndexSetBased<TKey, TPk, OIMIndexManualSetBased<TKey, TPk>> {
664
+ declare class OIMReactiveIndexManualArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMReactiveIndexArrayBased<TKey, TPk, OIMIndexManualArrayBased<TKey, TPk>> {
602
665
  constructor(queue: OIMEventQueue, opts?: {
603
666
  indexOptions?: {
604
667
  comparePks?: TOIMIndexComparator<TPk>;
605
- store?: OIMIndexStoreSetBased<TKey, TPk>;
668
+ store?: OIMIndexStoreArrayBased<TKey, TPk>;
606
669
  };
607
670
  });
608
- setPks(key: TKey, pks: TPk[]): void;
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;
609
685
  addPks(key: TKey, pks: readonly TPk[]): void;
610
686
  removePks(key: TKey, pks: readonly TPk[]): void;
611
- clear(key?: TKey): 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;
612
691
  }
613
692
 
614
693
  /**
615
- * Manual Array-based index that allows direct manipulation of key-to-primary-keys mappings.
616
- * Extends the abstract OIMIndexArrayBased with manual control methods and optional comparison.
694
+ * Manual Set-based index that allows direct manipulation of key-to-primary-keys mappings.
695
+ * Extends the abstract OIMIndexSetBased with manual control methods and optional comparison.
617
696
  */
618
- declare class OIMIndexManualArrayBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexArrayBased<TIndexKey, TPk> {
697
+ declare class OIMIndexManualSetBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexSetBased<TIndexKey, TPk> {
619
698
  constructor(options?: {
620
699
  comparePks?: TOIMIndexComparator<TPk>;
621
- store?: OIMIndexStoreArrayBased<TIndexKey, TPk>;
700
+ store?: OIMIndexStoreSetBased<TIndexKey, TPk>;
622
701
  });
623
- /**
624
- * Set primary keys for a specific index key, replacing any existing values.
625
- * Uses optional comparator to skip updates if PKs haven't actually changed.
626
- */
627
- setPks(key: TIndexKey, pks: TPk[]): void;
628
- /**
629
- * Add primary keys to a specific index key
630
- */
631
- addPks(key: TIndexKey, pks: readonly TPk[]): void;
632
- /**
633
- * Remove primary keys from a specific index key
634
- */
635
- removePks(key: TIndexKey, pks: readonly TPk[]): void;
702
+ setSlots(key: TIndexKey, slots: Iterable<TOIMAnyEntitySlot<TPk>>): void;
636
703
  /**
637
704
  * Clear all primary keys for a specific index key, or all keys if no key specified
638
705
  */
639
706
  clear(key?: TIndexKey): void;
640
707
  }
641
708
 
642
- declare class OIMReactiveIndexManualArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMReactiveIndexArrayBased<TKey, TPk, OIMIndexManualArrayBased<TKey, TPk>> {
643
- constructor(queue: OIMEventQueue, opts?: {
644
- indexOptions?: {
645
- comparePks?: TOIMIndexComparator<TPk>;
646
- store?: OIMIndexStoreArrayBased<TKey, TPk>;
647
- };
648
- });
649
- setPks(key: TKey, pks: TPk[]): void;
650
- addPks(key: TKey, pks: readonly TPk[]): void;
651
- removePks(key: TKey, pks: readonly TPk[]): void;
652
- clear(key?: TKey): void;
709
+ declare class OIMReactiveIndexManualSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMReactiveIndexSetBased<TKey, TPk, OIMIndexManualSetBased<TKey, TPk>> {
710
+ constructor(queue: OIMEventQueue, opts?: {
711
+ indexOptions?: {
712
+ comparePks?: TOIMIndexComparator<TPk>;
713
+ store?: OIMIndexStoreSetBased<TKey, TPk>;
714
+ };
715
+ });
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;
730
+ addPks(key: TKey, pks: readonly TPk[]): void;
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;
751
+ clear(key?: TKey): void;
752
+ destroy(): void;
753
+ private readonly onCollectionUpdate;
754
+ private syncPk;
755
+ private normalizeKeys;
756
+ }
757
+
758
+ /**
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.
763
+ */
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;
780
+ }
781
+
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>;
653
799
  }
800
+ declare function createOIMCollectionIndexFactory<TEntity extends object, TPk extends TOIMPk>(queue: OIMEventQueue, collection: OIMReactiveCollection<TEntity, TPk>): OIMCollectionIndexFactory<TEntity, TPk>;
654
801
 
655
- type TOIMReactiveIndex<TIndexKey extends TOIMPk, TPk extends TOIMPk> = OIMReactiveIndexSetBased<TIndexKey, TPk, any> | OIMReactiveIndexArrayBased<TIndexKey, TPk, any>;
656
- 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> {
657
- readonly indexes: TIndexMap;
658
- constructor(queue: OIMEventQueue, opts: {
659
- collectionOpts?: TOIMCollectionOptions<TEntity, TPk>;
660
- indexes?: TIndexMap;
661
- });
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;
662
848
  }
663
849
 
664
850
  declare class OIMCollectionStoreMapDriven<TEntity extends object, TPk extends TOIMPk> extends OIMCollectionStore<TEntity, TPk> {
665
- protected readonly entities: Map<TPk, TEntity>;
666
- setOneByPk(pk: TPk, entity: TEntity): void;
667
- setManyByPks(pks: readonly TPk[], entities: TEntity[]): void;
851
+ protected readonly slots: Map<TPk, TOIMEntitySlot<TEntity, TPk>>;
852
+ setOneByPk(pk: TPk, entity: TEntity): TOIMEntitySlot<TEntity, TPk>;
853
+ setManyByPks(pks: readonly TPk[], entities: TEntity[]): TOIMEntitySlot<TEntity, TPk>[];
854
+ getSlotByPk(pk: TPk): TOIMEntitySlot<TEntity, TPk> | undefined;
855
+ getSlotsByPks(pks: readonly TPk[]): TOIMEntitySlot<TEntity, TPk>[];
856
+ getAllSlots(): TOIMEntitySlot<TEntity, TPk>[];
668
857
  removeOneByPk(pk: TPk): void;
669
858
  removeManyByPks(pks: readonly TPk[]): void;
670
859
  getOneByPk(pk: TPk): TEntity | undefined;
@@ -714,27 +903,27 @@ declare class OIMObjectStoreRecordDriven<TKey extends string, TValue> extends OI
714
903
  }
715
904
 
716
905
  declare class OIMIndexStoreMapDrivenSetBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexStoreSetBased<TKey, TPk> {
717
- protected readonly pks: Map<TKey, Set<TPk>>;
718
- setOneByKey(key: TKey, pks: Set<TPk>): void;
906
+ protected readonly slots: Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
907
+ setOneByKey(key: TKey, slots: Set<TOIMAnyEntitySlot<TPk>>): void;
719
908
  removeOneByKey(key: TKey): void;
720
909
  removeManyByKeys(keys: readonly TKey[]): void;
721
- getOneByKey(key: TKey): Set<TPk> | undefined;
722
- getManyByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
910
+ getOneByKey(key: TKey): Set<TOIMAnyEntitySlot<TPk>> | undefined;
911
+ getManyByKeys(keys: readonly TKey[]): Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
723
912
  getAllKeys(): TKey[];
724
- getAll(): Map<TKey, Set<TPk>>;
913
+ getAll(): Map<TKey, Set<TOIMAnyEntitySlot<TPk>>>;
725
914
  countAll(): number;
726
915
  clear(): void;
727
916
  }
728
917
 
729
918
  declare class OIMIndexStoreMapDrivenArrayBased<TKey extends TOIMPk, TPk extends TOIMPk> extends OIMIndexStoreArrayBased<TKey, TPk> {
730
- protected readonly pks: Map<TKey, TPk[]>;
731
- setOneByKey(key: TKey, pks: TPk[]): void;
919
+ protected readonly slots: Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
920
+ setOneByKey(key: TKey, slots: TOIMAnyEntitySlot<TPk>[]): void;
732
921
  removeOneByKey(key: TKey): void;
733
922
  removeManyByKeys(keys: readonly TKey[]): void;
734
- getOneByKey(key: TKey): TPk[] | undefined;
735
- getManyByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
923
+ getOneByKey(key: TKey): TOIMAnyEntitySlot<TPk>[] | undefined;
924
+ getManyByKeys(keys: readonly TKey[]): Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
736
925
  getAllKeys(): TKey[];
737
- getAll(): Map<TKey, TPk[]>;
926
+ getAll(): Map<TKey, TOIMAnyEntitySlot<TPk>[]>;
738
927
  countAll(): number;
739
928
  clear(): void;
740
929
  }
@@ -793,16 +982,107 @@ declare class OIMPkSelectorFactory<TEntity extends object, TPk extends TOIMPk> {
793
982
  }, TPk>;
794
983
  }
795
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
+
796
1076
  type TOIMFieldKey<TEntity extends object> = keyof TEntity & string;
797
1077
  /**
798
- * Wrapper around `OIMCollection` that tracks "changed fields" per entity PK.
1078
+ * Tracks changed fields per entity PK for an `OIMCollection`.
799
1079
  *
800
- * 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.
801
1081
  *
802
- * DX: if the underlying collection is mutated directly (bypassing this wrapper), we detect it
803
- * 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.
804
1084
  */
805
- declare class OIMCollectionChangedFieldsWrapper<TEntity extends object, TPk extends TOIMPk> {
1085
+ declare class OIMCollectionChangedFields<TEntity extends object, TPk extends TOIMPk> {
806
1086
  readonly collection: OIMCollection<TEntity, TPk>;
807
1087
  private readonly selectPk;
808
1088
  private readonly unsubscribeAfterFlush;
@@ -828,9 +1108,9 @@ declare class OIMCollectionChangedFieldsWrapper<TEntity extends object, TPk exte
828
1108
  */
829
1109
  selectPk?: (entity: TEntity | Partial<TEntity>) => TPk;
830
1110
  });
831
- upsertOneByPk(pk: TPk, patch: Partial<TEntity>): void;
832
- upsertOne(entity: TEntity | Partial<TEntity>): void;
833
- 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>[];
834
1114
  getChangedFieldsByPk(pk: TPk): ReadonlySet<TOIMFieldKey<TEntity>>;
835
1115
  consumeChangedFieldsByPk(pk: TPk): Set<TOIMFieldKey<TEntity>>;
836
1116
  getChangedPksByField(field: TOIMFieldKey<TEntity>): ReadonlySet<TPk>;
@@ -847,91 +1127,6 @@ declare class OIMCollectionChangedFieldsWrapper<TEntity extends object, TPk exte
847
1127
  private trackPatch;
848
1128
  }
849
1129
 
850
- /**
851
- * Manual ordered Array-based index.
852
- *
853
- * Unlike `OIMIndexManualArrayBased.addPks/removePks`, this class is explicitly ordered:
854
- * - preserves order
855
- * - allows O(1) append (`push`)
856
- * - supports `move` and `removeAt` without computing diffs
857
- *
858
- * It emits UPDATE events per key on every successful mutation.
859
- */
860
- declare class OIMIndexManualOrderedArrayBased<TKey extends TOIMPk, TItemKey extends TOIMPk> extends OIMIndexArrayBased<TKey, TItemKey> {
861
- clear(key?: TKey): void;
862
- push(key: TKey, itemKey: TItemKey): number;
863
- insertAt(key: TKey, index: number, itemKey: TItemKey): void;
864
- removeAt(key: TKey, index: number): TItemKey | undefined;
865
- move(key: TKey, fromIndex: number, toIndex: number): TItemKey | undefined;
866
- reset(key: TKey, itemKeys: readonly TItemKey[]): void;
867
- private getOrCreateList;
868
- }
869
-
870
- type TOIMOrderedListCommand<TPk extends TOIMPk> = {
871
- type: 'add';
872
- key: TPk;
873
- index: number;
874
- } | {
875
- type: 'remove';
876
- key: TPk;
877
- index: number;
878
- } | {
879
- type: 'move';
880
- key: TPk;
881
- fromIndex: number;
882
- toIndex: number;
883
- } | {
884
- /**
885
- * Replace the whole list for this key (preferred name).
886
- */
887
- type: 'set';
888
- keys: readonly TPk[];
889
- };
890
-
891
- /**
892
- * Ordered-list wrapper that stores arrays per key and emits a per-key command stream.
893
- *
894
- * This is designed for imperative renderers: instead of diffing the full list on each update,
895
- * you subscribe to `commandsEventEmitter` on a single list key and apply commands sequentially.
896
- *
897
- * Notes:
898
- * - Commands are buffered per key and delivered batched per queue flush.
899
- * - Order of commands is preserved.
900
- * - A future optimizer can collapse the command buffer into `set(...)` if needed.
901
- */
902
- declare class OIMOrderedListIndexCommandStreamWrapper<TKey extends TOIMPk, TItemKey extends TOIMPk> {
903
- readonly commandsEventEmitter: OIMUpdateEventEmitter<TKey>;
904
- private readonly unsubscribeAfterFlush;
905
- private readonly unsubscribeFromIndexEmitter;
906
- private isInWrite;
907
- private readonly commandsByKey;
908
- /** Underlying ordered index (source of truth for the list). */
909
- readonly index: OIMIndexManualOrderedArrayBased<TKey, TItemKey>;
910
- constructor(queue: OIMEventQueue, index?: OIMIndexManualOrderedArrayBased<TKey, TItemKey>);
911
- getPksByKey(key: TKey): readonly TItemKey[];
912
- hasKey(key: TKey): boolean;
913
- getKeys(): readonly TKey[];
914
- push(key: TKey, itemKey: TItemKey): void;
915
- removeAt(key: TKey, index: number): void;
916
- move(key: TKey, fromIndex: number, toIndex: number): void;
917
- set(key: TKey, keys: readonly TItemKey[]): void;
918
- /**
919
- * Read-only peek at buffered commands without clearing them.
920
- */
921
- getBufferedCommands(key: TKey): readonly TOIMOrderedListCommand<TItemKey>[];
922
- /**
923
- * Drain buffered commands for a key, preserving order.
924
- * Intended usage: call inside a `commandsEventEmitter.subscribeOnKey(key, ...)` handler.
925
- */
926
- consumeCommands(key: TKey): TOIMOrderedListCommand<TItemKey>[];
927
- clear(key?: TKey): void;
928
- destroy(): void;
929
- private readonly onAfterFlush;
930
- private readonly onIndexUpdate;
931
- private withWrite;
932
- private appendCommand;
933
- }
934
-
935
1130
  /**
936
1131
  * Animation frame-based scheduler that executes flushes synchronized with the browser's repaint cycle.
937
1132
  * Ideal for UI-related updates that need to be synchronized with rendering.
@@ -986,13 +1181,14 @@ declare class OIMEventQueueSchedulerTimeout extends OIMEventQueueScheduler {
986
1181
  cancel(): void;
987
1182
  }
988
1183
 
1184
+ type TOIMImmediateSchedulerHandle = ReturnType<typeof setImmediate> | ReturnType<typeof setTimeout> | 1;
989
1185
  /**
990
1186
  * Immediate-based scheduler that executes flushes using setImmediate or fallback mechanisms.
991
1187
  * Provides faster execution than setTimeout(0) in Node.js environments.
992
1188
  * Falls back to setTimeout(0) in browsers and MessageChannel in modern browsers for better performance.
993
1189
  */
994
1190
  declare class OIMEventQueueSchedulerImmediate extends OIMEventQueueScheduler {
995
- protected immediateId?: number;
1191
+ protected immediateId?: TOIMImmediateSchedulerHandle;
996
1192
  protected readonly useSetImmediate: boolean;
997
1193
  protected readonly useMessageChannel: boolean;
998
1194
  protected messageChannel?: MessageChannel;
@@ -1055,10 +1251,6 @@ type TOIMIndexOptionsArrayBased<TIndexKey extends TOIMPk, TPk extends TOIMPk> =
1055
1251
  comparePks?: TOIMIndexComparator<TPk>;
1056
1252
  store?: OIMIndexStoreArrayBased<TIndexKey, TPk>;
1057
1253
  };
1058
- /**
1059
- * @deprecated Use TOIMIndexOptionsSetBased or TOIMIndexOptionsArrayBased instead
1060
- * Configuration options for index instances */
1061
- type TOIMIndexOptions<TIndexKey extends TOIMPk, TPk extends TOIMPk> = TOIMIndexOptionsSetBased<TIndexKey, TPk>;
1062
1254
 
1063
1255
  type TOIMIndexPksUpdatePayload<TKey extends TOIMPk, TPk extends TOIMPk> = {
1064
1256
  key: TKey;
@@ -1092,32 +1284,6 @@ type TOIMComputedUpdatePayload<TKey extends TOIMPk> = {
1092
1284
  keys: readonly TKey[];
1093
1285
  };
1094
1286
 
1095
- /**
1096
- * Computative runtime that schedules derived computations by levels and runs them
1097
- * on `queue.flush()` boundary (AFTER_FLUSH).
1098
- */
1099
- declare class OIMComputativeRuntime {
1100
- readonly queue: OIMEventQueue;
1101
- private isFlushScheduled;
1102
- private isFlushing;
1103
- private minLevel;
1104
- private maxLevel;
1105
- private readonly dirtyByLevel;
1106
- private readonly afterFlushTasks;
1107
- constructor(queue: OIMEventQueue);
1108
- /**
1109
- * Schedule a one-shot task to run on the next `queue.flush()` (AFTER_FLUSH),
1110
- * ordered by `level` ascending.
1111
- */
1112
- schedule(task: () => void, level?: number): () => void;
1113
- /**
1114
- * Run once at the start of the next runtime flush (i.e. after queue.flush()).
1115
- * Useful for resubscribing dependencies exactly once per source flush.
1116
- */
1117
- scheduleAfterFlush(task: () => void): () => void;
1118
- private flush;
1119
- }
1120
-
1121
1287
  type TOIMComputedKey$2 = 'value';
1122
1288
  declare class OIMComputed<TValue> {
1123
1289
  readonly emitter: OIMEventEmitter<{
@@ -1127,12 +1293,15 @@ declare class OIMComputed<TValue> {
1127
1293
  private readonly runtime;
1128
1294
  private readonly compute;
1129
1295
  private readonly compare;
1130
- private readonly deps;
1296
+ private readonly _deps;
1131
1297
  private value;
1132
1298
  private hasValue;
1133
1299
  private isDirty;
1134
1300
  private readonly effect;
1135
- 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[];
1136
1305
  get(): TValue;
1137
1306
  getIfReady(): TValue | undefined;
1138
1307
  destroy(): void;
@@ -1171,7 +1340,7 @@ declare class OIMEffect {
1171
1340
  private isScheduled;
1172
1341
  private dequeueScheduled?;
1173
1342
  private readonly runTask;
1174
- constructor(runtime: OIMComputativeRuntime, opts: TOIMEffectOptions);
1343
+ constructor(runtime: OIMComputeRuntime, opts: TOIMEffectOptions);
1175
1344
  destroy(): void;
1176
1345
  private onSourceInvalidate;
1177
1346
  private onComputedInvalidate;
@@ -1184,10 +1353,10 @@ declare class OIMEffect {
1184
1353
  }
1185
1354
 
1186
1355
  declare class OIMEffectDependencyKeyed<TKey extends TOIMPk> implements IOIMEffectDependency {
1187
- private readonly subscription;
1356
+ readonly source: IOIMKeyedSubscription<TKey>;
1188
1357
  private readonly key;
1189
1358
  private readonly keys;
1190
- constructor(subscription: IOIMKeyedSubscription<TKey>, keyOrKeys: TKey | readonly TKey[]);
1359
+ constructor(source: IOIMKeyedSubscription<TKey>, keyOrKeys: TKey | readonly TKey[]);
1191
1360
  subscribe(onUpdate: () => void): () => void;
1192
1361
  }
1193
1362
 
@@ -1195,6 +1364,7 @@ declare class OIMEffectDependencyKeyedObject<TKey extends string, TValue> implem
1195
1364
  private readonly dep;
1196
1365
  constructor(object: OIMReactiveObject<TKey, TValue>, key: TKey);
1197
1366
  constructor(object: OIMReactiveObject<TKey, TValue>, keys: readonly TKey[]);
1367
+ get source(): OIMReactiveObject<TKey, TValue>;
1198
1368
  subscribe(onUpdate: () => void): () => void;
1199
1369
  }
1200
1370
 
@@ -1202,6 +1372,7 @@ declare class OIMEffectDependencyKeyedCollection<TEntity extends object, TPk ext
1202
1372
  private readonly dep;
1203
1373
  constructor(collection: OIMReactiveCollection<TEntity, TPk>, pk: TPk);
1204
1374
  constructor(collection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]);
1375
+ get source(): OIMReactiveCollection<TEntity, TPk>;
1205
1376
  subscribe(onUpdate: () => void): () => void;
1206
1377
  }
1207
1378
 
@@ -1209,6 +1380,7 @@ declare class OIMEffectDependencyKeyedIndex<TKey extends TOIMPk> implements IOIM
1209
1380
  private readonly dep;
1210
1381
  constructor(index: IOIMKeyedSubscription<TKey>, key: TKey);
1211
1382
  constructor(index: IOIMKeyedSubscription<TKey>, keys: readonly TKey[]);
1383
+ get source(): IOIMKeyedSubscription<TKey>;
1212
1384
  subscribe(onUpdate: () => void): () => void;
1213
1385
  }
1214
1386
 
@@ -1223,64 +1395,22 @@ type TOIMComputedLike = {
1223
1395
  * Effect dependency on a computed.
1224
1396
  */
1225
1397
  declare class OIMEffectDependencyComputed implements IOIMEffectDependency {
1226
- private readonly computed;
1227
- constructor(computed: TOIMComputedLike);
1228
- subscribe(onUpdate: () => void): () => void;
1229
- }
1230
-
1231
- interface IOIMSelectorComputedDependency {
1232
- subscribe(onUpdate: () => void): () => void;
1233
- }
1234
-
1235
- interface IOIMSelectorSourceDependency {
1398
+ readonly source: TOIMComputedLike;
1399
+ constructor(source: TOIMComputedLike);
1236
1400
  subscribe(onUpdate: () => void): () => void;
1237
1401
  }
1238
1402
 
1239
- declare abstract class OIMSelector<TValue> {
1240
- protected readonly runtime: OIMComputativeRuntime;
1241
- protected readonly sourceDeps: readonly IOIMSelectorSourceDependency[];
1242
- protected readonly computedDeps: readonly IOIMSelectorComputedDependency[];
1243
- private readonly listeners;
1244
- private sourceUnsubscribers;
1245
- private computedUnsubscribers;
1246
- private dequeueResubscribe?;
1247
- private isResubscribeEnqueued;
1248
- private isTemporarilyUnsubscribedForFlush;
1249
- private isDeliveryEnqueued;
1250
- private dequeueDelivery?;
1251
- private hasLastValue;
1252
- private lastValue;
1253
- protected get queue(): OIMEventQueue;
1254
- protected constructor(runtime: OIMComputativeRuntime, sourceDeps: readonly IOIMSelectorSourceDependency[], computedDeps?: readonly IOIMSelectorComputedDependency[]);
1255
- abstract getValue(): TValue;
1256
- /**
1257
- * Start watching this selector. The callback is called immediately with the current value,
1258
- * then coalesced and delivered on `queue.flush()` when the selector invalidates.
1259
- */
1260
- watch(onValue: (value: TValue) => void): () => void;
1261
- protected areEqual(prev: TValue, next: TValue): boolean;
1262
- private readonly onSourceInvalidate;
1263
- private readonly onComputedInvalidate;
1264
- private readonly deliver;
1265
- private setLastValue;
1266
- private subscribeToDeps;
1267
- private unsubscribeFromSourceDeps;
1268
- private unsubscribeFromAllDeps;
1269
- private ensureResubscribeAfterFlush;
1270
- private readonly onAfterFlush;
1271
- }
1272
-
1273
1403
  declare class OIMCollectionByPkSelector<TEntity extends object, TPk extends TOIMPk> extends OIMSelector<TEntity | undefined> {
1274
1404
  private readonly collection;
1275
1405
  private readonly pk;
1276
- constructor(runtime: OIMComputativeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pk: TPk);
1406
+ constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pk: TPk);
1277
1407
  getValue(): TEntity | undefined;
1278
1408
  }
1279
1409
 
1280
1410
  declare class OIMCollectionByPksSelector<TEntity extends object, TPk extends TOIMPk> extends OIMSelector<readonly (TEntity | undefined)[]> {
1281
1411
  private readonly collection;
1282
1412
  private readonly pks;
1283
- constructor(runtime: OIMComputativeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]);
1413
+ constructor(runtime: OIMComputeRuntime, collection: OIMReactiveCollection<TEntity, TPk>, pks: readonly TPk[]);
1284
1414
  getValue(): readonly (TEntity | undefined)[];
1285
1415
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1286
1416
  }
@@ -1288,14 +1418,14 @@ declare class OIMCollectionByPksSelector<TEntity extends object, TPk extends TOI
1288
1418
  declare class OIMObjectValueByKeySelector<TKey extends string, TValue> extends OIMSelector<TValue | undefined> {
1289
1419
  private readonly obj;
1290
1420
  private readonly key;
1291
- constructor(runtime: OIMComputativeRuntime, obj: OIMReactiveObject<TKey, TValue>, key: TKey);
1421
+ constructor(runtime: OIMComputeRuntime, obj: OIMReactiveObject<TKey, TValue>, key: TKey);
1292
1422
  getValue(): TValue | undefined;
1293
1423
  }
1294
1424
 
1295
1425
  declare class OIMObjectValuesByKeysSelector<TKey extends string, TValue> extends OIMSelector<readonly (TValue | undefined)[]> {
1296
1426
  private readonly obj;
1297
1427
  private readonly keys;
1298
- constructor(runtime: OIMComputativeRuntime, obj: OIMReactiveObject<TKey, TValue>, keys: readonly TKey[]);
1428
+ constructor(runtime: OIMComputeRuntime, obj: OIMReactiveObject<TKey, TValue>, keys: readonly TKey[]);
1299
1429
  getValue(): readonly (TValue | undefined)[];
1300
1430
  protected areEqual(prev: readonly (TValue | undefined)[], next: readonly (TValue | undefined)[]): boolean;
1301
1431
  }
@@ -1303,14 +1433,14 @@ declare class OIMObjectValuesByKeysSelector<TKey extends string, TValue> extends
1303
1433
  declare class OIMIndexPksByKeySetBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<Set<TPk>> {
1304
1434
  private readonly reactiveIndex;
1305
1435
  private readonly key;
1306
- constructor(runtime: OIMComputativeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey);
1436
+ constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, key: TKey);
1307
1437
  getValue(): Set<TPk>;
1308
1438
  }
1309
1439
 
1310
1440
  declare class OIMIndexPksByKeyArrayBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
1311
1441
  private readonly reactiveIndex;
1312
1442
  private readonly key;
1313
- constructor(runtime: OIMComputativeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey);
1443
+ constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, key: TKey);
1314
1444
  getValue(): readonly TPk[];
1315
1445
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
1316
1446
  }
@@ -1318,7 +1448,7 @@ declare class OIMIndexPksByKeyArrayBasedSelector<TKey extends TOIMPk, TPk extend
1318
1448
  declare class OIMIndexPksByKeysSetBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
1319
1449
  private readonly reactiveIndex;
1320
1450
  private readonly keys;
1321
- constructor(runtime: OIMComputativeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
1451
+ constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexSetBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
1322
1452
  getValue(): readonly TPk[];
1323
1453
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
1324
1454
  }
@@ -1326,7 +1456,7 @@ declare class OIMIndexPksByKeysSetBasedSelector<TKey extends TOIMPk, TPk extends
1326
1456
  declare class OIMIndexPksByKeysArrayBasedSelector<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMSelector<readonly TPk[]> {
1327
1457
  private readonly reactiveIndex;
1328
1458
  private readonly keys;
1329
- constructor(runtime: OIMComputativeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
1459
+ constructor(runtime: OIMComputeRuntime, reactiveIndex: OIMReactiveIndexArrayBased<TKey, TPk, TIndex>, keys: readonly TKey[]);
1330
1460
  getValue(): readonly TPk[];
1331
1461
  protected areEqual(prev: readonly TPk[], next: readonly TPk[]): boolean;
1332
1462
  }
@@ -1335,7 +1465,7 @@ declare class OIMEntitiesByIndexKeySetBasedSelector<TEntity extends object, TPk
1335
1465
  private readonly collection;
1336
1466
  private readonly reactiveIndex;
1337
1467
  private readonly key;
1338
- 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);
1339
1469
  getValue(): readonly (TEntity | undefined)[];
1340
1470
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1341
1471
  }
@@ -1344,9 +1474,9 @@ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TP
1344
1474
  private readonly collection;
1345
1475
  private readonly reactiveIndex;
1346
1476
  private readonly key;
1347
- 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);
1348
1478
  getValue(): readonly (TEntity | undefined)[];
1349
1479
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1350
1480
  }
1351
1481
 
1352
- 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 TOIMCollectionOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMEffectOptions, 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 };