@oimdb/core 3.0.1 → 3.1.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
@@ -197,6 +197,33 @@ declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMP
197
197
  protected setSlotsWithComparison(key: TKey, newSlots: TOIMAnyEntitySlot<TPk>[]): boolean;
198
198
  }
199
199
 
200
+ /**
201
+ * The keyed pub/sub surface a reactive node needs from its update emitter:
202
+ * per-key subscribe/unsubscribe plus batched "mark updated" delivery.
203
+ *
204
+ * Both keyed emitters implement it — `OIMUpdateEventEmitter` (Map of handlers)
205
+ * and `OIMCarrierKeyedEmitter` (handlers on a per-key carrier). Typing the node
206
+ * against this interface lets either back the node without leaking the carrier
207
+ * generic into the node's signatures.
208
+ */
209
+ interface IOIMKeyedUpdateEmitter<TKey extends TOIMPk> {
210
+ subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
211
+ subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
212
+ unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
213
+ unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
214
+ markUpdatedKey(key: TKey): void;
215
+ markUpdatedKeys(keys: readonly TKey[]): void;
216
+ hasSubscriptions(): boolean;
217
+ getHandlerCount(key: TKey): number;
218
+ getMetrics(): {
219
+ totalKeys: number;
220
+ totalHandlers: number;
221
+ averageHandlersPerKey: number;
222
+ queueLength: number;
223
+ };
224
+ destroy(): void;
225
+ }
226
+
200
227
  /**
201
228
  * Configuration options for event queue initialization.
202
229
  */
@@ -260,68 +287,6 @@ declare class OIMEventQueue {
260
287
  destroy(): void;
261
288
  }
262
289
 
263
- type TOIMUpdateEventEmitterDeliveryMode = 'queue' | 'after_flush' | 'immediate';
264
- /**
265
- * Universal event emitter that handles subscriptions and notifications for any key type.
266
- * Optimized for performance with adaptive algorithms and memory management.
267
- */
268
- declare class OIMUpdateEventEmitter<TKey extends TOIMPk> {
269
- protected keyHandlers: Map<TKey, Set<TOIMEventHandler<void>>>;
270
- protected queue: OIMEventQueue;
271
- private readonly deliveryMode;
272
- private isFlushEnqueued;
273
- private dequeueFlush?;
274
- private updatedKeys;
275
- private isAfterFlushDeliveryScheduled;
276
- private unsubscribeAfterFlushDelivery?;
277
- constructor(queue: OIMEventQueue, deliveryMode?: TOIMUpdateEventEmitterDeliveryMode);
278
- /**
279
- * Mark keys as updated and schedule delivery.
280
- *
281
- * If there are no subscriptions, this is a no-op and does not allocate or retain keys.
282
- */
283
- markUpdatedKeys(keys: readonly TKey[]): void;
284
- markUpdatedKey(key: TKey): void;
285
- markAllUpdated(): void;
286
- protected readonly onFlush: () => void;
287
- private deliverImmediate;
288
- /**
289
- * Notifies all handlers for a key. The overwhelmingly common case is a
290
- * single subscriber per key (one component per pk), handled without any
291
- * allocation. For multiple subscribers a snapshot is taken so a handler may
292
- * (un)subscribe during iteration without corrupting the walk.
293
- */
294
- private notifyHandlers;
295
- private readonly onAfterFlush;
296
- /**
297
- * Deliver updated keys and notify handlers once.
298
- * Re-entrant updates during delivery are forbidden and will throw in markUpdatedKeys().
299
- */
300
- protected runSinglePass(): void;
301
- destroy(): void;
302
- /**
303
- * Get performance metrics for monitoring and debugging
304
- */
305
- getMetrics(): {
306
- totalKeys: number;
307
- totalHandlers: number;
308
- averageHandlersPerKey: number;
309
- queueLength: number;
310
- };
311
- /**
312
- * Check if there are any active subscriptions
313
- */
314
- hasSubscriptions(): boolean;
315
- /**
316
- * Get the number of handlers for a specific key
317
- */
318
- getHandlerCount(key: TKey): number;
319
- subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
320
- unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
321
- subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
322
- unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
323
- }
324
-
325
290
  interface IOIMKeyedSubscription<TKey extends TOIMPk> {
326
291
  subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
327
292
  subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
@@ -329,8 +294,8 @@ interface IOIMKeyedSubscription<TKey extends TOIMPk> {
329
294
 
330
295
  declare abstract class OIMReactiveIndex<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndex<TKey, TPk, Iterable<TOIMAnyEntitySlot<TPk>>>> implements IOIMKeyedSubscription<TKey> {
331
296
  readonly index: TIndex;
332
- protected readonly updateEmitter: OIMUpdateEventEmitter<TKey>;
333
- constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
297
+ protected readonly updateEmitter: IOIMKeyedUpdateEmitter<TKey>;
298
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex);
334
299
  getEntitiesByKey<TEntity extends object = object>(key: TKey): (TEntity | undefined)[];
335
300
  getEntitiesByKeys<TEntity extends object = object>(keys: readonly TKey[]): Map<TKey, (TEntity | undefined)[]>;
336
301
  hasKey(key: TKey): boolean;
@@ -361,7 +326,7 @@ declare abstract class OIMReactiveIndex<TKey extends TOIMPk, TPk extends TOIMPk,
361
326
  }
362
327
 
363
328
  declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
364
- constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
329
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex);
365
330
  getPksByKey(key: TKey): Set<TPk>;
366
331
  getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
367
332
  getSlotsByKey(key: TKey): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
@@ -369,7 +334,7 @@ declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMPk, TPk extends
369
334
  }
370
335
 
371
336
  declare abstract class OIMReactiveIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
372
- constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
337
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex);
373
338
  getPksByKey(key: TKey): TPk[];
374
339
  getPksByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
375
340
  getSlotsByKey(key: TKey): readonly TOIMAnyEntitySlot<TPk>[];
@@ -442,6 +407,14 @@ declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
442
407
  */
443
408
  interface IOIMSubscribable {
444
409
  subscribers?: Set<() => void>;
410
+ /**
411
+ * Dirty-batch membership flag, owned by the keyed emitter. `true` while the
412
+ * carrier sits in the pending flush batch — lets the emitter dedup marks with
413
+ * an O(1) boolean check instead of a `Set` identity-hash lookup. Reset to
414
+ * `false` as the carrier is delivered (or on flush teardown). Do not read or
415
+ * write outside the emitter.
416
+ */
417
+ dirty?: boolean;
445
418
  }
446
419
 
447
420
  /**
@@ -456,6 +429,13 @@ interface IOIMSubscribable {
456
429
  interface IOIMCarrierResolver<TKey extends TOIMPk, TCarrier> {
457
430
  getOrReserveCarrier(key: TKey): TCarrier;
458
431
  findCarrier(key: TKey): TCarrier | undefined;
432
+ /**
433
+ * Optional: called when a carrier loses its last subscriber, so a resolver
434
+ * that owns standalone carriers (e.g. the index's key→carrier map) can prune
435
+ * it and not leak the key space. Resolvers whose carriers are owned
436
+ * elsewhere (e.g. the collection's slots) leave this unset.
437
+ */
438
+ onCarrierEmptied?(carrier: TCarrier): void;
459
439
  }
460
440
  /**
461
441
  * Keyed (per-key) pub/sub that stores handlers ON the carrier object
@@ -468,7 +448,7 @@ interface IOIMCarrierResolver<TKey extends TOIMPk, TCarrier> {
468
448
  * index's keyed emitter. Reused with carrier = slot (collection) or carrier =
469
449
  * bucket (index).
470
450
  */
471
- declare class OIMCarrierKeyedEmitter<TKey extends TOIMPk, TCarrier extends IOIMSubscribable> {
451
+ declare class OIMCarrierKeyedEmitter<TKey extends TOIMPk, TCarrier extends IOIMSubscribable> implements IOIMKeyedUpdateEmitter<TKey> {
472
452
  private readonly queue;
473
453
  private readonly resolver;
474
454
  private readonly subscribedCarriers;
@@ -671,6 +651,68 @@ declare class OIMCollectionIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk
671
651
  private resolveRequiredSlot;
672
652
  }
673
653
 
654
+ type TOIMUpdateEventEmitterDeliveryMode = 'queue' | 'after_flush' | 'immediate';
655
+ /**
656
+ * Universal event emitter that handles subscriptions and notifications for any key type.
657
+ * Optimized for performance with adaptive algorithms and memory management.
658
+ */
659
+ declare class OIMUpdateEventEmitter<TKey extends TOIMPk> {
660
+ protected keyHandlers: Map<TKey, Set<TOIMEventHandler<void>>>;
661
+ protected queue: OIMEventQueue;
662
+ private readonly deliveryMode;
663
+ private isFlushEnqueued;
664
+ private dequeueFlush?;
665
+ private updatedKeys;
666
+ private isAfterFlushDeliveryScheduled;
667
+ private unsubscribeAfterFlushDelivery?;
668
+ constructor(queue: OIMEventQueue, deliveryMode?: TOIMUpdateEventEmitterDeliveryMode);
669
+ /**
670
+ * Mark keys as updated and schedule delivery.
671
+ *
672
+ * If there are no subscriptions, this is a no-op and does not allocate or retain keys.
673
+ */
674
+ markUpdatedKeys(keys: readonly TKey[]): void;
675
+ markUpdatedKey(key: TKey): void;
676
+ markAllUpdated(): void;
677
+ protected readonly onFlush: () => void;
678
+ private deliverImmediate;
679
+ /**
680
+ * Notifies all handlers for a key. The overwhelmingly common case is a
681
+ * single subscriber per key (one component per pk), handled without any
682
+ * allocation. For multiple subscribers a snapshot is taken so a handler may
683
+ * (un)subscribe during iteration without corrupting the walk.
684
+ */
685
+ private notifyHandlers;
686
+ private readonly onAfterFlush;
687
+ /**
688
+ * Deliver updated keys and notify handlers once.
689
+ * Re-entrant updates during delivery are forbidden and will throw in markUpdatedKeys().
690
+ */
691
+ protected runSinglePass(): void;
692
+ destroy(): void;
693
+ /**
694
+ * Get performance metrics for monitoring and debugging
695
+ */
696
+ getMetrics(): {
697
+ totalKeys: number;
698
+ totalHandlers: number;
699
+ averageHandlersPerKey: number;
700
+ queueLength: number;
701
+ };
702
+ /**
703
+ * Check if there are any active subscriptions
704
+ */
705
+ hasSubscriptions(): boolean;
706
+ /**
707
+ * Get the number of handlers for a specific key
708
+ */
709
+ getHandlerCount(key: TKey): number;
710
+ subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
711
+ unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
712
+ subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
713
+ unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
714
+ }
715
+
674
716
  type TOIMOrderedListCommand<TPk extends TOIMPk, TEntity extends object = object> = {
675
717
  type: 'insert';
676
718
  pk: TPk;
@@ -1633,4 +1675,4 @@ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TP
1633
1675
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1634
1676
  }
1635
1677
 
1636
- export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexStore, type IOIMSubscribable, OIMCarrierKeyedEmitter, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerTimeout, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandStream, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexSetBasedOptions, type TOIMCollectionKit, type TOIMCollectionOptions, type TOIMCollectionOrderedIndexOptions, type TOIMCollectionOrderedListCommandStreamOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMDerivedCollectionIndexArrayBasedOptions, type TOIMDerivedCollectionIndexSetBasedOptions, type TOIMDerivedEntityComparator, type TOIMDerivedEntityOrderSelector, type TOIMDerivedEntityOrderValue, type TOIMDerivedIndexKeySelector, type TOIMEffectOptions, type TOIMEntitySlot, type TOIMEntitySlotResolver, type TOIMEntityUpdater, type TOIMEventHandler, type TOIMEventQueueOptions, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsDerivedArrayIndexOptions, type TOIMRelationsDerivedSetIndexOptions, type TOIMRelationsOrderedListOptions, type TOIMRelationsSetIndexOptions, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload, createInPlaceEntityUpdater, createOIMCollectionIndexFactory, createOIMCollectionKit };
1678
+ export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexStore, type IOIMKeyedUpdateEmitter, type IOIMSubscribable, OIMCarrierKeyedEmitter, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerTimeout, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandStream, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexSetBasedOptions, type TOIMCollectionKit, type TOIMCollectionOptions, type TOIMCollectionOrderedIndexOptions, type TOIMCollectionOrderedListCommandStreamOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMDerivedCollectionIndexArrayBasedOptions, type TOIMDerivedCollectionIndexSetBasedOptions, type TOIMDerivedEntityComparator, type TOIMDerivedEntityOrderSelector, type TOIMDerivedEntityOrderValue, type TOIMDerivedIndexKeySelector, type TOIMEffectOptions, type TOIMEntitySlot, type TOIMEntitySlotResolver, type TOIMEntityUpdater, type TOIMEventHandler, type TOIMEventQueueOptions, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsDerivedArrayIndexOptions, type TOIMRelationsDerivedSetIndexOptions, type TOIMRelationsOrderedListOptions, type TOIMRelationsSetIndexOptions, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload, createInPlaceEntityUpdater, createOIMCollectionIndexFactory, createOIMCollectionKit };
package/dist/index.d.ts CHANGED
@@ -197,6 +197,33 @@ declare abstract class OIMIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMP
197
197
  protected setSlotsWithComparison(key: TKey, newSlots: TOIMAnyEntitySlot<TPk>[]): boolean;
198
198
  }
199
199
 
200
+ /**
201
+ * The keyed pub/sub surface a reactive node needs from its update emitter:
202
+ * per-key subscribe/unsubscribe plus batched "mark updated" delivery.
203
+ *
204
+ * Both keyed emitters implement it — `OIMUpdateEventEmitter` (Map of handlers)
205
+ * and `OIMCarrierKeyedEmitter` (handlers on a per-key carrier). Typing the node
206
+ * against this interface lets either back the node without leaking the carrier
207
+ * generic into the node's signatures.
208
+ */
209
+ interface IOIMKeyedUpdateEmitter<TKey extends TOIMPk> {
210
+ subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
211
+ subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
212
+ unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
213
+ unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
214
+ markUpdatedKey(key: TKey): void;
215
+ markUpdatedKeys(keys: readonly TKey[]): void;
216
+ hasSubscriptions(): boolean;
217
+ getHandlerCount(key: TKey): number;
218
+ getMetrics(): {
219
+ totalKeys: number;
220
+ totalHandlers: number;
221
+ averageHandlersPerKey: number;
222
+ queueLength: number;
223
+ };
224
+ destroy(): void;
225
+ }
226
+
200
227
  /**
201
228
  * Configuration options for event queue initialization.
202
229
  */
@@ -260,68 +287,6 @@ declare class OIMEventQueue {
260
287
  destroy(): void;
261
288
  }
262
289
 
263
- type TOIMUpdateEventEmitterDeliveryMode = 'queue' | 'after_flush' | 'immediate';
264
- /**
265
- * Universal event emitter that handles subscriptions and notifications for any key type.
266
- * Optimized for performance with adaptive algorithms and memory management.
267
- */
268
- declare class OIMUpdateEventEmitter<TKey extends TOIMPk> {
269
- protected keyHandlers: Map<TKey, Set<TOIMEventHandler<void>>>;
270
- protected queue: OIMEventQueue;
271
- private readonly deliveryMode;
272
- private isFlushEnqueued;
273
- private dequeueFlush?;
274
- private updatedKeys;
275
- private isAfterFlushDeliveryScheduled;
276
- private unsubscribeAfterFlushDelivery?;
277
- constructor(queue: OIMEventQueue, deliveryMode?: TOIMUpdateEventEmitterDeliveryMode);
278
- /**
279
- * Mark keys as updated and schedule delivery.
280
- *
281
- * If there are no subscriptions, this is a no-op and does not allocate or retain keys.
282
- */
283
- markUpdatedKeys(keys: readonly TKey[]): void;
284
- markUpdatedKey(key: TKey): void;
285
- markAllUpdated(): void;
286
- protected readonly onFlush: () => void;
287
- private deliverImmediate;
288
- /**
289
- * Notifies all handlers for a key. The overwhelmingly common case is a
290
- * single subscriber per key (one component per pk), handled without any
291
- * allocation. For multiple subscribers a snapshot is taken so a handler may
292
- * (un)subscribe during iteration without corrupting the walk.
293
- */
294
- private notifyHandlers;
295
- private readonly onAfterFlush;
296
- /**
297
- * Deliver updated keys and notify handlers once.
298
- * Re-entrant updates during delivery are forbidden and will throw in markUpdatedKeys().
299
- */
300
- protected runSinglePass(): void;
301
- destroy(): void;
302
- /**
303
- * Get performance metrics for monitoring and debugging
304
- */
305
- getMetrics(): {
306
- totalKeys: number;
307
- totalHandlers: number;
308
- averageHandlersPerKey: number;
309
- queueLength: number;
310
- };
311
- /**
312
- * Check if there are any active subscriptions
313
- */
314
- hasSubscriptions(): boolean;
315
- /**
316
- * Get the number of handlers for a specific key
317
- */
318
- getHandlerCount(key: TKey): number;
319
- subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
320
- unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
321
- subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
322
- unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
323
- }
324
-
325
290
  interface IOIMKeyedSubscription<TKey extends TOIMPk> {
326
291
  subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
327
292
  subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
@@ -329,8 +294,8 @@ interface IOIMKeyedSubscription<TKey extends TOIMPk> {
329
294
 
330
295
  declare abstract class OIMReactiveIndex<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndex<TKey, TPk, Iterable<TOIMAnyEntitySlot<TPk>>>> implements IOIMKeyedSubscription<TKey> {
331
296
  readonly index: TIndex;
332
- protected readonly updateEmitter: OIMUpdateEventEmitter<TKey>;
333
- constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
297
+ protected readonly updateEmitter: IOIMKeyedUpdateEmitter<TKey>;
298
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex);
334
299
  getEntitiesByKey<TEntity extends object = object>(key: TKey): (TEntity | undefined)[];
335
300
  getEntitiesByKeys<TEntity extends object = object>(keys: readonly TKey[]): Map<TKey, (TEntity | undefined)[]>;
336
301
  hasKey(key: TKey): boolean;
@@ -361,7 +326,7 @@ declare abstract class OIMReactiveIndex<TKey extends TOIMPk, TPk extends TOIMPk,
361
326
  }
362
327
 
363
328
  declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexSetBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
364
- constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
329
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex);
365
330
  getPksByKey(key: TKey): Set<TPk>;
366
331
  getPksByKeys(keys: readonly TKey[]): Map<TKey, Set<TPk>>;
367
332
  getSlotsByKey(key: TKey): ReadonlySet<TOIMAnyEntitySlot<TPk>>;
@@ -369,7 +334,7 @@ declare abstract class OIMReactiveIndexSetBased<TKey extends TOIMPk, TPk extends
369
334
  }
370
335
 
371
336
  declare abstract class OIMReactiveIndexArrayBased<TKey extends TOIMPk, TPk extends TOIMPk, TIndex extends OIMIndexArrayBased<TKey, TPk>> extends OIMReactiveIndex<TKey, TPk, TIndex> {
372
- constructor(queue: OIMEventQueue, createIndex: (updateEmitter: OIMUpdateEventEmitter<TKey>) => TIndex);
337
+ constructor(queue: OIMEventQueue, createIndex: (updateEmitter: IOIMKeyedUpdateEmitter<TKey>) => TIndex);
373
338
  getPksByKey(key: TKey): TPk[];
374
339
  getPksByKeys(keys: readonly TKey[]): Map<TKey, TPk[]>;
375
340
  getSlotsByKey(key: TKey): readonly TOIMAnyEntitySlot<TPk>[];
@@ -442,6 +407,14 @@ declare class OIMCollection<TEntity extends object, TPk extends TOIMPk> {
442
407
  */
443
408
  interface IOIMSubscribable {
444
409
  subscribers?: Set<() => void>;
410
+ /**
411
+ * Dirty-batch membership flag, owned by the keyed emitter. `true` while the
412
+ * carrier sits in the pending flush batch — lets the emitter dedup marks with
413
+ * an O(1) boolean check instead of a `Set` identity-hash lookup. Reset to
414
+ * `false` as the carrier is delivered (or on flush teardown). Do not read or
415
+ * write outside the emitter.
416
+ */
417
+ dirty?: boolean;
445
418
  }
446
419
 
447
420
  /**
@@ -456,6 +429,13 @@ interface IOIMSubscribable {
456
429
  interface IOIMCarrierResolver<TKey extends TOIMPk, TCarrier> {
457
430
  getOrReserveCarrier(key: TKey): TCarrier;
458
431
  findCarrier(key: TKey): TCarrier | undefined;
432
+ /**
433
+ * Optional: called when a carrier loses its last subscriber, so a resolver
434
+ * that owns standalone carriers (e.g. the index's key→carrier map) can prune
435
+ * it and not leak the key space. Resolvers whose carriers are owned
436
+ * elsewhere (e.g. the collection's slots) leave this unset.
437
+ */
438
+ onCarrierEmptied?(carrier: TCarrier): void;
459
439
  }
460
440
  /**
461
441
  * Keyed (per-key) pub/sub that stores handlers ON the carrier object
@@ -468,7 +448,7 @@ interface IOIMCarrierResolver<TKey extends TOIMPk, TCarrier> {
468
448
  * index's keyed emitter. Reused with carrier = slot (collection) or carrier =
469
449
  * bucket (index).
470
450
  */
471
- declare class OIMCarrierKeyedEmitter<TKey extends TOIMPk, TCarrier extends IOIMSubscribable> {
451
+ declare class OIMCarrierKeyedEmitter<TKey extends TOIMPk, TCarrier extends IOIMSubscribable> implements IOIMKeyedUpdateEmitter<TKey> {
472
452
  private readonly queue;
473
453
  private readonly resolver;
474
454
  private readonly subscribedCarriers;
@@ -671,6 +651,68 @@ declare class OIMCollectionIndexManualOrderedArrayBased<TKey extends TOIMPk, TPk
671
651
  private resolveRequiredSlot;
672
652
  }
673
653
 
654
+ type TOIMUpdateEventEmitterDeliveryMode = 'queue' | 'after_flush' | 'immediate';
655
+ /**
656
+ * Universal event emitter that handles subscriptions and notifications for any key type.
657
+ * Optimized for performance with adaptive algorithms and memory management.
658
+ */
659
+ declare class OIMUpdateEventEmitter<TKey extends TOIMPk> {
660
+ protected keyHandlers: Map<TKey, Set<TOIMEventHandler<void>>>;
661
+ protected queue: OIMEventQueue;
662
+ private readonly deliveryMode;
663
+ private isFlushEnqueued;
664
+ private dequeueFlush?;
665
+ private updatedKeys;
666
+ private isAfterFlushDeliveryScheduled;
667
+ private unsubscribeAfterFlushDelivery?;
668
+ constructor(queue: OIMEventQueue, deliveryMode?: TOIMUpdateEventEmitterDeliveryMode);
669
+ /**
670
+ * Mark keys as updated and schedule delivery.
671
+ *
672
+ * If there are no subscriptions, this is a no-op and does not allocate or retain keys.
673
+ */
674
+ markUpdatedKeys(keys: readonly TKey[]): void;
675
+ markUpdatedKey(key: TKey): void;
676
+ markAllUpdated(): void;
677
+ protected readonly onFlush: () => void;
678
+ private deliverImmediate;
679
+ /**
680
+ * Notifies all handlers for a key. The overwhelmingly common case is a
681
+ * single subscriber per key (one component per pk), handled without any
682
+ * allocation. For multiple subscribers a snapshot is taken so a handler may
683
+ * (un)subscribe during iteration without corrupting the walk.
684
+ */
685
+ private notifyHandlers;
686
+ private readonly onAfterFlush;
687
+ /**
688
+ * Deliver updated keys and notify handlers once.
689
+ * Re-entrant updates during delivery are forbidden and will throw in markUpdatedKeys().
690
+ */
691
+ protected runSinglePass(): void;
692
+ destroy(): void;
693
+ /**
694
+ * Get performance metrics for monitoring and debugging
695
+ */
696
+ getMetrics(): {
697
+ totalKeys: number;
698
+ totalHandlers: number;
699
+ averageHandlersPerKey: number;
700
+ queueLength: number;
701
+ };
702
+ /**
703
+ * Check if there are any active subscriptions
704
+ */
705
+ hasSubscriptions(): boolean;
706
+ /**
707
+ * Get the number of handlers for a specific key
708
+ */
709
+ getHandlerCount(key: TKey): number;
710
+ subscribeOnKey(key: TKey, handler: TOIMEventHandler<void>): () => void;
711
+ unsubscribeFromKey(key: TKey, handler: TOIMEventHandler<void>): void;
712
+ subscribeOnKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): () => void;
713
+ unsubscribeFromKeys(keys: readonly TKey[], handler: TOIMEventHandler<void>): void;
714
+ }
715
+
674
716
  type TOIMOrderedListCommand<TPk extends TOIMPk, TEntity extends object = object> = {
675
717
  type: 'insert';
676
718
  pk: TPk;
@@ -1633,4 +1675,4 @@ declare class OIMEntitiesByIndexKeyArrayBasedSelector<TEntity extends object, TP
1633
1675
  protected areEqual(prev: readonly (TEntity | undefined)[], next: readonly (TEntity | undefined)[]): boolean;
1634
1676
  }
1635
1677
 
1636
- export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexStore, type IOIMSubscribable, OIMCarrierKeyedEmitter, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerTimeout, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandStream, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexSetBasedOptions, type TOIMCollectionKit, type TOIMCollectionOptions, type TOIMCollectionOrderedIndexOptions, type TOIMCollectionOrderedListCommandStreamOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMDerivedCollectionIndexArrayBasedOptions, type TOIMDerivedCollectionIndexSetBasedOptions, type TOIMDerivedEntityComparator, type TOIMDerivedEntityOrderSelector, type TOIMDerivedEntityOrderValue, type TOIMDerivedIndexKeySelector, type TOIMEffectOptions, type TOIMEntitySlot, type TOIMEntitySlotResolver, type TOIMEntityUpdater, type TOIMEventHandler, type TOIMEventQueueOptions, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsDerivedArrayIndexOptions, type TOIMRelationsDerivedSetIndexOptions, type TOIMRelationsOrderedListOptions, type TOIMRelationsSetIndexOptions, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload, createInPlaceEntityUpdater, createOIMCollectionIndexFactory, createOIMCollectionKit };
1678
+ export { EOIMCollectionEventType, EOIMComputedEventType, EOIMEventQueueEventType, EOIMEventQueueSchedulerEventType, EOIMIndexEventType, EOIMObjectEventType, type IOIMCarrierResolver, type IOIMComputedEventSource, type IOIMEffectDependency, type IOIMEventQueueSchedulerEvents, type IOIMIndexStore, type IOIMKeyedUpdateEmitter, type IOIMSubscribable, OIMCarrierKeyedEmitter, OIMCollection, OIMCollectionByPkSelector, OIMCollectionByPksSelector, OIMCollectionChangedFields, OIMCollectionIndexFactory, OIMCollectionIndexManualOrderedArrayBased, OIMCollectionOrderedListCommandStream, OIMCollectionSelectors, OIMCollectionStore, OIMCollectionStoreMapDriven, OIMComparatorFactory, OIMComputeRuntime, OIMComputed, OIMDBSettings, OIMDerivedCollectionIndexArrayBased, OIMDerivedCollectionIndexSetBased, OIMEffect, OIMEffectDependencyComputed, OIMEffectDependencyKeyed, OIMEffectDependencyKeyedCollection, OIMEffectDependencyKeyedIndex, OIMEffectDependencyKeyedObject, OIMEntitiesByIndexKeyArrayBasedSelector, OIMEntitiesByIndexKeySetBasedSelector, OIMEntityUpdaterFactory, OIMEventEmitter, OIMEventQueue, OIMEventQueueScheduler, OIMEventQueueSchedulerAnimationFrame, OIMEventQueueSchedulerFactory, OIMEventQueueSchedulerImmediate, OIMEventQueueSchedulerMicrotask, OIMEventQueueSchedulerTimeout, OIMIndex, OIMIndexArrayBased, OIMIndexComparatorFactory, OIMIndexManualArrayBased, OIMIndexManualOrderedArrayBased, OIMIndexManualSetBased, OIMIndexPksByKeyArrayBasedSelector, OIMIndexPksByKeySetBasedSelector, OIMIndexPksByKeysArrayBasedSelector, OIMIndexPksByKeysSetBasedSelector, OIMIndexSetBased, OIMIndexStoreArrayBased, OIMIndexStoreMapDrivenArrayBased, OIMIndexStoreMapDrivenSetBased, OIMIndexStoreSetBased, OIMMap2Keys, OIMObject, OIMObjectStore, OIMObjectStoreMapDriven, OIMObjectStoreRecordDriven, OIMObjectValueByKeySelector, OIMObjectValuesByKeysSelector, OIMOrderedListCommandStream, OIMPkSelectorFactory, OIMReactiveCollection, OIMReactiveCollectionIndexManualArrayBased, OIMReactiveCollectionIndexManualSetBased, OIMReactiveIndex, OIMReactiveIndexArrayBased, OIMReactiveIndexManualArrayBased, OIMReactiveIndexManualSetBased, OIMReactiveIndexSetBased, OIMReactiveObject, OIMSelector, type TOIMAnyEntitySlot, type TOIMCollectionEntitiesSelector, type TOIMCollectionEntitySelector, type TOIMCollectionIndexArrayBasedOptions, type TOIMCollectionIndexSetBasedOptions, type TOIMCollectionKit, type TOIMCollectionOptions, type TOIMCollectionOrderedIndexOptions, type TOIMCollectionOrderedListCommandStreamOptions, type TOIMCollectionUpdatePayload, type TOIMComparator, type TOIMComputedOptions, type TOIMComputedUpdatePayload, type TOIMDerivedCollectionIndexArrayBasedOptions, type TOIMDerivedCollectionIndexSetBasedOptions, type TOIMDerivedEntityComparator, type TOIMDerivedEntityOrderSelector, type TOIMDerivedEntityOrderValue, type TOIMDerivedIndexKeySelector, type TOIMEffectOptions, type TOIMEntitySlot, type TOIMEntitySlotResolver, type TOIMEntityUpdater, type TOIMEventHandler, type TOIMEventQueueOptions, type TOIMIndexComparator, type TOIMIndexKey, type TOIMIndexOptionsArrayBased, type TOIMIndexOptionsSetBased, type TOIMIndexPksUpdatePayload, type TOIMIndexUpdatePayload, type TOIMObjectOptions, type TOIMOrderedListCommand, type TOIMPk, type TOIMPkSelector, type TOIMReactiveCollectionFactoryOptions, type TOIMRelationsArrayIndexOptions, type TOIMRelationsDerivedArrayIndexOptions, type TOIMRelationsDerivedSetIndexOptions, type TOIMRelationsOrderedListOptions, type TOIMRelationsSetIndexOptions, type TOIMSchedulerOptions, type TOIMSchedulerType, type TOIMUpdatePayload, createInPlaceEntityUpdater, createOIMCollectionIndexFactory, createOIMCollectionKit };