@oimdb/react 2.1.1 → 2.2.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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  React hooks and context helpers for OIMDB reactive collections, objects, and indexes.
4
4
 
5
- 📖 **[Full documentation](https://abaikov.github.io/oimdb/)**
5
+ 📖 **[Full documentation](https://oimdb.org/)**
6
6
 
7
7
  ## For AI Assistants
8
8
 
@@ -118,11 +118,50 @@ function TeamUsers({ teamId }: { teamId: string }) {
118
118
  - `useSelectEntitiesByIndexKeyArrayBased(collection, index, key)` watches entities referenced by one index key.
119
119
  - `useSelectEntitiesByIndexKeysArrayBased(collection, index, keys)` watches entities referenced by several index keys.
120
120
 
121
+ ### Composite (Key-Path) Indexes
122
+
123
+ For indexes keyed by a composite **key path** (an array, from `indexFactory.compositeSetIndex()` / `compositeArrayIndex()`). These stabilize the key path **by content**, so passing a freshly built `['p1', 'admin']` on every render does not re-subscribe.
124
+
125
+ - `useSelectPksByCompositeIndexKeySetBased(index, path)` / `…ArrayBased(index, path)` watch PKs for one key path.
126
+ - `useSelectEntitiesByCompositeIndexKeySetBased(collection, index, path)` / `…ArrayBased(collection, index, path)` watch entities for one key path.
127
+
121
128
  ### Reactive Objects
122
129
 
123
130
  - `useSelectValueByObjectKey(object, key)` watches one object key.
124
131
  - `useSelectValuesByObjectKeys(object, keys)` watches several object keys.
125
132
 
133
+ All entity/index hooks return holes as `undefined` (`(TEntity | undefined)[]`), aligned 1:1 with the requested pks/keys — render with a guard (`user ? … : null`).
134
+
135
+ ## Mutable mode + signal hooks (advanced)
136
+
137
+ The default hooks use `useSyncExternalStore`, which detects change by **reference** (`Object.is`). That requires the store to produce a new entity object per update — the default immutable merge (`{ ...prev, ...draft }`), whose copy is the biggest per-update data-layer cost.
138
+
139
+ For update-heavy, fine-grained UIs you can run a collection in **in-place / mutable** mode and bind it with the lighter **signal hooks**:
140
+
141
+ ```tsx
142
+ import { OIMReactiveCollection, createInPlaceEntityUpdater } from '@oimdb/core';
143
+ import {
144
+ useSelectEntityByPkSignal,
145
+ useSelectPksByIndexKeyArrayBasedSignal,
146
+ useSelectPksByIndexKeySetBasedSignal,
147
+ } from '@oimdb/react';
148
+
149
+ // Mutate entities in place — no per-update object allocation.
150
+ const cards = new OIMReactiveCollection<Card, string>(queue, {
151
+ selectPk: (c) => c.id,
152
+ updateEntity: createInPlaceEntityUpdater(),
153
+ });
154
+
155
+ // Signal hooks re-render on the keyed notification (no Object.is), so they see
156
+ // in-place mutations the default uSES hooks would miss.
157
+ const card = useSelectEntityByPkSignal(cards, id);
158
+ const ids = useSelectPksByIndexKeyArrayBasedSignal(cardsByDeck, deckId);
159
+ ```
160
+
161
+ Available signal hooks (same signatures as their default counterparts): `useSelectEntityByPkSignal`, `useSelectPksByIndexKeyArrayBasedSignal`, `useSelectPksByIndexKeySetBasedSignal`. Compose the fine-grained pattern from them: a parent reads pks by index key, each row reads its own entity by pk.
162
+
163
+ **Use only when every reader is subscription-driven.** Trade-offs: not Concurrent-Mode tearing-safe; the entity reference is stable across changes, so `React.memo` on entities, prev/next diffing, time-travel, and the default uSES hooks on the same collection won't see updates. Select each entity where you render it (by pk); don't pass mutable entities into `React.memo` children. See [Performance](https://oimdb.org/docs/guides/performance) for when this actually pays off (in plain React the per-component commit usually dominates).
164
+
126
165
  ## Context API
127
166
 
128
167
  ```typescript
package/dist/index.cjs CHANGED
@@ -24,6 +24,10 @@ __export(index_exports, {
24
24
  OIMCollectionsProvider: () => OIMCollectionsProvider,
25
25
  createOIMCollectionsContext: () => createOIMCollectionsContext,
26
26
  useOIMCollectionsContext: () => useOIMCollectionsContext,
27
+ useSelectEntitiesByCompositeIndexKeyArrayBased: () => useSelectEntitiesByCompositeIndexKeyArrayBased,
28
+ useSelectEntitiesByCompositeIndexKeySetBased: () => useSelectEntitiesByCompositeIndexKeySetBased,
29
+ useSelectEntitiesByGlobalIndexArrayBased: () => useSelectEntitiesByGlobalIndexArrayBased,
30
+ useSelectEntitiesByGlobalIndexSetBased: () => useSelectEntitiesByGlobalIndexSetBased,
27
31
  useSelectEntitiesByIndexKeyArrayBased: () => useSelectEntitiesByIndexKeyArrayBased,
28
32
  useSelectEntitiesByIndexKeySetBased: () => useSelectEntitiesByIndexKeySetBased,
29
33
  useSelectEntitiesByIndexKeysArrayBased: () => useSelectEntitiesByIndexKeysArrayBased,
@@ -31,6 +35,12 @@ __export(index_exports, {
31
35
  useSelectEntitiesByPks: () => useSelectEntitiesByPks,
32
36
  useSelectEntityByPk: () => useSelectEntityByPk,
33
37
  useSelectEntityByPkSignal: () => useSelectEntityByPkSignal,
38
+ useSelectPksByCompositeIndexKeyArrayBased: () => useSelectPksByCompositeIndexKeyArrayBased,
39
+ useSelectPksByCompositeIndexKeySetBased: () => useSelectPksByCompositeIndexKeySetBased,
40
+ useSelectPksByGlobalIndexArrayBased: () => useSelectPksByGlobalIndexArrayBased,
41
+ useSelectPksByGlobalIndexArrayBasedSignal: () => useSelectPksByGlobalIndexArrayBasedSignal,
42
+ useSelectPksByGlobalIndexSetBased: () => useSelectPksByGlobalIndexSetBased,
43
+ useSelectPksByGlobalIndexSetBasedSignal: () => useSelectPksByGlobalIndexSetBasedSignal,
34
44
  useSelectPksByIndexKeyArrayBased: () => useSelectPksByIndexKeyArrayBased,
35
45
  useSelectPksByIndexKeyArrayBasedSignal: () => useSelectPksByIndexKeyArrayBasedSignal,
36
46
  useSelectPksByIndexKeySetBased: () => useSelectPksByIndexKeySetBased,
@@ -43,14 +53,121 @@ __export(index_exports, {
43
53
  module.exports = __toCommonJS(index_exports);
44
54
 
45
55
  // src/hooks/index.ts
46
- var import_react2 = require("react");
47
56
  var import_react3 = require("react");
57
+ var import_react4 = require("react");
48
58
 
49
- // src/hooks/signal.ts
59
+ // src/hooks/global.ts
50
60
  var import_react = require("react");
51
- var useIsomorphicLayoutEffect = typeof window !== "undefined" ? import_react.useLayoutEffect : import_react.useEffect;
61
+ var useSelectPksByGlobalIndexArrayBased = (reactiveIndex) => {
62
+ const snapshotValueRef = (0, import_react.useRef)();
63
+ const subscribe = (0, import_react.useMemo)(() => {
64
+ snapshotValueRef.current = reactiveIndex.getPks();
65
+ return (onStoreChange) => {
66
+ return reactiveIndex.subscribe(() => {
67
+ snapshotValueRef.current = reactiveIndex.getPks();
68
+ onStoreChange();
69
+ });
70
+ };
71
+ }, [reactiveIndex]);
72
+ const getSnapshot = (0, import_react.useMemo)(() => () => snapshotValueRef.current, []);
73
+ return (0, import_react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
74
+ };
75
+ var useSelectPksByGlobalIndexSetBased = (reactiveIndex) => {
76
+ const snapshotValueRef = (0, import_react.useRef)();
77
+ const subscribe = (0, import_react.useMemo)(() => {
78
+ snapshotValueRef.current = reactiveIndex.getPks();
79
+ return (onStoreChange) => {
80
+ return reactiveIndex.subscribe(() => {
81
+ snapshotValueRef.current = reactiveIndex.getPks();
82
+ onStoreChange();
83
+ });
84
+ };
85
+ }, [reactiveIndex]);
86
+ const getSnapshot = (0, import_react.useMemo)(() => () => snapshotValueRef.current, []);
87
+ return (0, import_react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
88
+ };
89
+ var useSelectEntitiesByGlobalIndexArrayBased = (reactiveCollection, reactiveIndex) => {
90
+ const snapshotRef = (0, import_react.useRef)();
91
+ const subscribe = (0, import_react.useMemo)(() => {
92
+ const readPks = () => reactiveIndex.getPks();
93
+ const readSnapshot = () => readPks().map((pk) => reactiveCollection.getOneByPk(pk));
94
+ snapshotRef.current = readSnapshot();
95
+ return (onStoreChange) => {
96
+ let unsubscribeFromCollection = reactiveCollection.subscribeOnKeys(
97
+ readPks(),
98
+ () => {
99
+ snapshotRef.current = readSnapshot();
100
+ onStoreChange();
101
+ }
102
+ );
103
+ const resubscribeCollection = () => {
104
+ unsubscribeFromCollection();
105
+ unsubscribeFromCollection = reactiveCollection.subscribeOnKeys(
106
+ readPks(),
107
+ () => {
108
+ snapshotRef.current = readSnapshot();
109
+ onStoreChange();
110
+ }
111
+ );
112
+ };
113
+ const unsubscribeFromIndex = reactiveIndex.subscribe(() => {
114
+ resubscribeCollection();
115
+ snapshotRef.current = readSnapshot();
116
+ onStoreChange();
117
+ });
118
+ return () => {
119
+ unsubscribeFromIndex();
120
+ unsubscribeFromCollection();
121
+ };
122
+ };
123
+ }, [reactiveCollection, reactiveIndex]);
124
+ const getSnapshot = (0, import_react.useMemo)(() => () => snapshotRef.current, []);
125
+ return (0, import_react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
126
+ };
127
+ var useSelectEntitiesByGlobalIndexSetBased = (reactiveCollection, reactiveIndex) => {
128
+ const snapshotRef = (0, import_react.useRef)();
129
+ const subscribe = (0, import_react.useMemo)(() => {
130
+ const readPks = () => Array.from(reactiveIndex.getPks());
131
+ const readSnapshot = () => readPks().map((pk) => reactiveCollection.getOneByPk(pk));
132
+ snapshotRef.current = readSnapshot();
133
+ return (onStoreChange) => {
134
+ let unsubscribeFromCollection = reactiveCollection.subscribeOnKeys(
135
+ readPks(),
136
+ () => {
137
+ snapshotRef.current = readSnapshot();
138
+ onStoreChange();
139
+ }
140
+ );
141
+ const resubscribeCollection = () => {
142
+ unsubscribeFromCollection();
143
+ unsubscribeFromCollection = reactiveCollection.subscribeOnKeys(
144
+ readPks(),
145
+ () => {
146
+ snapshotRef.current = readSnapshot();
147
+ onStoreChange();
148
+ }
149
+ );
150
+ };
151
+ const unsubscribeFromIndex = reactiveIndex.subscribe(() => {
152
+ resubscribeCollection();
153
+ snapshotRef.current = readSnapshot();
154
+ onStoreChange();
155
+ });
156
+ return () => {
157
+ unsubscribeFromIndex();
158
+ unsubscribeFromCollection();
159
+ };
160
+ };
161
+ }, [reactiveCollection, reactiveIndex]);
162
+ const getSnapshot = (0, import_react.useMemo)(() => () => snapshotRef.current, []);
163
+ return (0, import_react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
164
+ };
165
+
166
+ // src/hooks/signal.ts
167
+ var import_react2 = require("react");
168
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? import_react2.useLayoutEffect : import_react2.useEffect;
52
169
  function useForceUpdate() {
53
- const [, force] = (0, import_react.useReducer)((c) => c + 1 | 0, 0);
170
+ const [, force] = (0, import_react2.useReducer)((c) => c + 1 | 0, 0);
54
171
  return force;
55
172
  }
56
173
  var useSelectEntityByPkSignal = (reactiveCollection, pk) => {
@@ -77,18 +194,34 @@ var useSelectPksByIndexKeySetBasedSignal = (reactiveIndex, key) => {
77
194
  );
78
195
  return reactiveIndex.getPksByKey(key);
79
196
  };
197
+ var useSelectPksByGlobalIndexArrayBasedSignal = (reactiveIndex) => {
198
+ const force = useForceUpdate();
199
+ useIsomorphicLayoutEffect(
200
+ () => reactiveIndex.subscribe(force),
201
+ [reactiveIndex]
202
+ );
203
+ return reactiveIndex.getPks();
204
+ };
205
+ var useSelectPksByGlobalIndexSetBasedSignal = (reactiveIndex) => {
206
+ const force = useForceUpdate();
207
+ useIsomorphicLayoutEffect(
208
+ () => reactiveIndex.subscribe(force),
209
+ [reactiveIndex]
210
+ );
211
+ return reactiveIndex.getPks();
212
+ };
80
213
 
81
214
  // src/hooks/index.ts
82
215
  var EMPTY_ARRAY = [];
83
216
  var useSelectPksByIndexKeysSetBased = (reactiveIndex, keys) => {
84
- const prevKeysRef = (0, import_react2.useRef)();
217
+ const prevKeysRef = (0, import_react3.useRef)();
85
218
  const keysAreEqual = arraysEqual(prevKeysRef.current || EMPTY_ARRAY, keys);
86
219
  if (!keysAreEqual) {
87
220
  prevKeysRef.current = keys;
88
221
  }
89
222
  const stableKeys = keysAreEqual ? prevKeysRef.current ?? keys : keys;
90
- const snapshotValueRef = (0, import_react2.useRef)();
91
- const subscribe = (0, import_react2.useMemo)(() => {
223
+ const snapshotValueRef = (0, import_react3.useRef)();
224
+ const subscribe = (0, import_react3.useMemo)(() => {
92
225
  snapshotValueRef.current = stableKeys.map((key) => Array.from(reactiveIndex.getPksByKey(key))).flat();
93
226
  return (onStoreChange) => {
94
227
  const updateSnapshot = () => {
@@ -104,17 +237,17 @@ var useSelectPksByIndexKeysSetBased = (reactiveIndex, keys) => {
104
237
  };
105
238
  };
106
239
  }, [reactiveIndex, stableKeys]);
107
- const getSnapshot = (0, import_react2.useMemo)(() => {
240
+ const getSnapshot = (0, import_react3.useMemo)(() => {
108
241
  return () => {
109
242
  return snapshotValueRef.current;
110
243
  };
111
244
  }, []);
112
- const snapshot = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
245
+ const snapshot = (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
113
246
  return snapshot;
114
247
  };
115
248
  var useSelectPksByIndexKeySetBased = (reactiveIndex, key) => {
116
- const snapshotValueRef = (0, import_react2.useRef)();
117
- const subscribe = (0, import_react2.useMemo)(() => {
249
+ const snapshotValueRef = (0, import_react3.useRef)();
250
+ const subscribe = (0, import_react3.useMemo)(() => {
118
251
  snapshotValueRef.current = reactiveIndex.getPksByKey(key);
119
252
  return (onStoreChange) => {
120
253
  const updateSnapshot = () => {
@@ -124,23 +257,23 @@ var useSelectPksByIndexKeySetBased = (reactiveIndex, key) => {
124
257
  return reactiveIndex.subscribeOnKey(key, updateSnapshot);
125
258
  };
126
259
  }, [key, reactiveIndex]);
127
- const getSnapshot = (0, import_react2.useMemo)(() => {
260
+ const getSnapshot = (0, import_react3.useMemo)(() => {
128
261
  return () => {
129
262
  return snapshotValueRef.current;
130
263
  };
131
264
  }, []);
132
- const snapshot = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
265
+ const snapshot = (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
133
266
  return snapshot;
134
267
  };
135
268
  var useSelectPksByIndexKeysArrayBased = (reactiveIndex, keys) => {
136
- const prevKeysRef = (0, import_react2.useRef)();
269
+ const prevKeysRef = (0, import_react3.useRef)();
137
270
  const keysAreEqual = arraysEqual(prevKeysRef.current || EMPTY_ARRAY, keys);
138
271
  if (!keysAreEqual) {
139
272
  prevKeysRef.current = keys;
140
273
  }
141
274
  const stableKeys = keysAreEqual ? prevKeysRef.current ?? keys : keys;
142
- const snapshotValueRef = (0, import_react2.useRef)();
143
- const subscribe = (0, import_react2.useMemo)(() => {
275
+ const snapshotValueRef = (0, import_react3.useRef)();
276
+ const subscribe = (0, import_react3.useMemo)(() => {
144
277
  snapshotValueRef.current = stableKeys.map((key) => reactiveIndex.getPksByKey(key)).flat();
145
278
  return (onStoreChange) => {
146
279
  const updateSnapshot = () => {
@@ -156,22 +289,22 @@ var useSelectPksByIndexKeysArrayBased = (reactiveIndex, keys) => {
156
289
  };
157
290
  };
158
291
  }, [reactiveIndex, stableKeys]);
159
- const getSnapshot = (0, import_react2.useMemo)(() => {
292
+ const getSnapshot = (0, import_react3.useMemo)(() => {
160
293
  return () => {
161
294
  return snapshotValueRef.current;
162
295
  };
163
296
  }, []);
164
- const snapshot = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
297
+ const snapshot = (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
165
298
  return snapshot;
166
299
  };
167
300
  var useSelectPksByIndexKeyArrayBased = (reactiveIndex, key) => {
168
- const prevKeyRef = (0, import_react2.useRef)();
301
+ const prevKeyRef = (0, import_react3.useRef)();
169
302
  const keyAreEqual = prevKeyRef.current === key;
170
303
  if (!keyAreEqual) {
171
304
  prevKeyRef.current = key;
172
305
  }
173
- const snapshotValueRef = (0, import_react2.useRef)();
174
- const subscribe = (0, import_react2.useMemo)(() => {
306
+ const snapshotValueRef = (0, import_react3.useRef)();
307
+ const subscribe = (0, import_react3.useMemo)(() => {
175
308
  snapshotValueRef.current = reactiveIndex.getPksByKey(key);
176
309
  return (onStoreChange) => {
177
310
  const prevKey = prevKeyRef.current;
@@ -192,49 +325,49 @@ var useSelectPksByIndexKeyArrayBased = (reactiveIndex, key) => {
192
325
  };
193
326
  };
194
327
  }, [key, reactiveIndex]);
195
- const getSnapshot = (0, import_react2.useMemo)(() => {
328
+ const getSnapshot = (0, import_react3.useMemo)(() => {
196
329
  return () => {
197
330
  return snapshotValueRef.current;
198
331
  };
199
332
  }, []);
200
- const snapshot = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
333
+ const snapshot = (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
201
334
  return snapshot;
202
335
  };
203
336
  var useSelectEntityByPk = (reactiveCollection, pk) => {
204
- const getSnapshot = (0, import_react2.useMemo)(
337
+ const getSnapshot = (0, import_react3.useMemo)(
205
338
  () => () => reactiveCollection.getOneByPk(pk),
206
339
  [pk, reactiveCollection]
207
340
  );
208
- const subscribe = (0, import_react2.useMemo)(() => {
341
+ const subscribe = (0, import_react3.useMemo)(() => {
209
342
  return (onStoreChange) => {
210
343
  return reactiveCollection.subscribeOnKey(pk, onStoreChange);
211
344
  };
212
345
  }, [pk, reactiveCollection]);
213
- const snapshot = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
346
+ const snapshot = (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
214
347
  return snapshot;
215
348
  };
216
349
  var useSelectValueByObjectKey = (reactiveObject, key) => {
217
- const getSnapshot = (0, import_react2.useMemo)(
350
+ const getSnapshot = (0, import_react3.useMemo)(
218
351
  () => () => reactiveObject.get(key),
219
352
  [key, reactiveObject]
220
353
  );
221
- const subscribe = (0, import_react2.useMemo)(() => {
354
+ const subscribe = (0, import_react3.useMemo)(() => {
222
355
  return (onStoreChange) => {
223
356
  return reactiveObject.subscribeOnKey(key, onStoreChange);
224
357
  };
225
358
  }, [key, reactiveObject]);
226
- const snapshot = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
359
+ const snapshot = (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
227
360
  return snapshot;
228
361
  };
229
362
  var useSelectValuesByObjectKeys = (reactiveObject, keys) => {
230
- const prevKeysRef = (0, import_react2.useRef)();
363
+ const prevKeysRef = (0, import_react3.useRef)();
231
364
  const keysAreEqual = arraysEqual(prevKeysRef.current || EMPTY_ARRAY, keys);
232
365
  if (!keysAreEqual) {
233
366
  prevKeysRef.current = keys;
234
367
  }
235
368
  const stableKeys = keysAreEqual ? prevKeysRef.current ?? keys : keys;
236
- const snapshotRef = (0, import_react2.useRef)();
237
- const subscribe = (0, import_react2.useMemo)(() => {
369
+ const snapshotRef = (0, import_react3.useRef)();
370
+ const subscribe = (0, import_react3.useMemo)(() => {
238
371
  snapshotRef.current = stableKeys.map((key) => reactiveObject.get(key));
239
372
  return (onStoreChange) => {
240
373
  const updateSnapshot = () => {
@@ -252,12 +385,12 @@ var useSelectValuesByObjectKeys = (reactiveObject, keys) => {
252
385
  };
253
386
  };
254
387
  }, [reactiveObject, stableKeys]);
255
- const getSnapshot = (0, import_react2.useMemo)(() => {
388
+ const getSnapshot = (0, import_react3.useMemo)(() => {
256
389
  return () => {
257
390
  return snapshotRef.current;
258
391
  };
259
392
  }, []);
260
- const snapshot = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
393
+ const snapshot = (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
261
394
  return snapshot;
262
395
  };
263
396
  function arraysEqual(a, b) {
@@ -269,14 +402,14 @@ function arraysEqual(a, b) {
269
402
  return true;
270
403
  }
271
404
  var useSelectEntitiesByPks = (reactiveCollection, pks) => {
272
- const prevPksRef = (0, import_react2.useRef)();
405
+ const prevPksRef = (0, import_react3.useRef)();
273
406
  const pksAreEqual = arraysEqual(prevPksRef.current || EMPTY_ARRAY, pks);
274
407
  if (!pksAreEqual) {
275
408
  prevPksRef.current = pks;
276
409
  }
277
410
  const stablePks = pksAreEqual ? prevPksRef.current ?? pks : pks;
278
- const snapshotRef = (0, import_react2.useRef)();
279
- const subscribe = (0, import_react2.useMemo)(() => {
411
+ const snapshotRef = (0, import_react3.useRef)();
412
+ const subscribe = (0, import_react3.useMemo)(() => {
280
413
  snapshotRef.current = stablePks.map(
281
414
  (pk) => reactiveCollection.getOneByPk(pk)
282
415
  );
@@ -296,17 +429,17 @@ var useSelectEntitiesByPks = (reactiveCollection, pks) => {
296
429
  };
297
430
  };
298
431
  }, [reactiveCollection, stablePks]);
299
- const getSnapshot = (0, import_react2.useMemo)(() => {
432
+ const getSnapshot = (0, import_react3.useMemo)(() => {
300
433
  return () => {
301
434
  return snapshotRef.current;
302
435
  };
303
436
  }, []);
304
- const snapshot = (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
437
+ const snapshot = (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
305
438
  return snapshot;
306
439
  };
307
440
  var useSelectEntitiesByIndexKeySetBased = (reactiveCollection, reactiveIndex, key) => {
308
- const snapshotRef = (0, import_react2.useRef)();
309
- const subscribe = (0, import_react2.useMemo)(() => {
441
+ const snapshotRef = (0, import_react3.useRef)();
442
+ const subscribe = (0, import_react3.useMemo)(() => {
310
443
  const readSnapshot = () => Array.from(
311
444
  reactiveIndex.getPksByKey(key),
312
445
  (pk) => reactiveCollection.getOneByPk(pk)
@@ -339,18 +472,18 @@ var useSelectEntitiesByIndexKeySetBased = (reactiveCollection, reactiveIndex, ke
339
472
  };
340
473
  };
341
474
  }, [key, reactiveCollection, reactiveIndex]);
342
- const getSnapshot = (0, import_react2.useMemo)(() => () => snapshotRef.current, []);
343
- return (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
475
+ const getSnapshot = (0, import_react3.useMemo)(() => () => snapshotRef.current, []);
476
+ return (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
344
477
  };
345
478
  var useSelectEntitiesByIndexKeysSetBased = (reactiveCollection, reactiveIndex, keys) => {
346
- const prevKeysRef = (0, import_react2.useRef)();
479
+ const prevKeysRef = (0, import_react3.useRef)();
347
480
  const keysAreEqual = arraysEqual(prevKeysRef.current || EMPTY_ARRAY, keys);
348
481
  if (!keysAreEqual) {
349
482
  prevKeysRef.current = keys;
350
483
  }
351
484
  const stableKeys = keysAreEqual ? prevKeysRef.current ?? keys : keys;
352
- const snapshotRef = (0, import_react2.useRef)();
353
- const subscribe = (0, import_react2.useMemo)(() => {
485
+ const snapshotRef = (0, import_react3.useRef)();
486
+ const subscribe = (0, import_react3.useMemo)(() => {
354
487
  const readPks = () => stableKeys.flatMap(
355
488
  (key) => Array.from(reactiveIndex.getPksByKey(key))
356
489
  );
@@ -385,12 +518,12 @@ var useSelectEntitiesByIndexKeysSetBased = (reactiveCollection, reactiveIndex, k
385
518
  };
386
519
  };
387
520
  }, [reactiveCollection, reactiveIndex, stableKeys]);
388
- const getSnapshot = (0, import_react2.useMemo)(() => () => snapshotRef.current, []);
389
- return (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
521
+ const getSnapshot = (0, import_react3.useMemo)(() => () => snapshotRef.current, []);
522
+ return (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
390
523
  };
391
524
  var useSelectEntitiesByIndexKeyArrayBased = (reactiveCollection, reactiveIndex, key) => {
392
- const snapshotRef = (0, import_react2.useRef)();
393
- const subscribe = (0, import_react2.useMemo)(() => {
525
+ const snapshotRef = (0, import_react3.useRef)();
526
+ const subscribe = (0, import_react3.useMemo)(() => {
394
527
  const readSnapshot = () => reactiveIndex.getPksByKey(key).map((pk) => reactiveCollection.getOneByPk(pk));
395
528
  const readPks = () => reactiveIndex.getPksByKey(key);
396
529
  snapshotRef.current = readSnapshot();
@@ -420,18 +553,18 @@ var useSelectEntitiesByIndexKeyArrayBased = (reactiveCollection, reactiveIndex,
420
553
  };
421
554
  };
422
555
  }, [key, reactiveCollection, reactiveIndex]);
423
- const getSnapshot = (0, import_react2.useMemo)(() => () => snapshotRef.current, []);
424
- return (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
556
+ const getSnapshot = (0, import_react3.useMemo)(() => () => snapshotRef.current, []);
557
+ return (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
425
558
  };
426
559
  var useSelectEntitiesByIndexKeysArrayBased = (reactiveCollection, reactiveIndex, keys) => {
427
- const prevKeysRef = (0, import_react2.useRef)();
560
+ const prevKeysRef = (0, import_react3.useRef)();
428
561
  const keysAreEqual = arraysEqual(prevKeysRef.current || EMPTY_ARRAY, keys);
429
562
  if (!keysAreEqual) {
430
563
  prevKeysRef.current = keys;
431
564
  }
432
565
  const stableKeys = keysAreEqual ? prevKeysRef.current ?? keys : keys;
433
- const snapshotRef = (0, import_react2.useRef)();
434
- const subscribe = (0, import_react2.useMemo)(() => {
566
+ const snapshotRef = (0, import_react3.useRef)();
567
+ const subscribe = (0, import_react3.useMemo)(() => {
435
568
  const readPks = () => stableKeys.flatMap((key) => reactiveIndex.getPksByKey(key));
436
569
  const readSnapshot = () => readPks().map((pk) => reactiveCollection.getOneByPk(pk));
437
570
  snapshotRef.current = readSnapshot();
@@ -464,18 +597,139 @@ var useSelectEntitiesByIndexKeysArrayBased = (reactiveCollection, reactiveIndex,
464
597
  };
465
598
  };
466
599
  }, [reactiveCollection, reactiveIndex, stableKeys]);
467
- const getSnapshot = (0, import_react2.useMemo)(() => () => snapshotRef.current, []);
468
- return (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
600
+ const getSnapshot = (0, import_react3.useMemo)(() => () => snapshotRef.current, []);
601
+ return (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
602
+ };
603
+ function useStableKeyPath(key) {
604
+ const prevRef = (0, import_react3.useRef)();
605
+ const equal = prevRef.current !== void 0 && arraysEqual(prevRef.current, key);
606
+ if (!equal) {
607
+ prevRef.current = key;
608
+ }
609
+ return equal ? prevRef.current : key;
610
+ }
611
+ var useSelectPksByCompositeIndexKeySetBased = (reactiveIndex, key) => {
612
+ const stableKey = useStableKeyPath(key);
613
+ const snapshotValueRef = (0, import_react3.useRef)();
614
+ const subscribe = (0, import_react3.useMemo)(() => {
615
+ snapshotValueRef.current = reactiveIndex.getPksByKey(stableKey);
616
+ return (onStoreChange) => {
617
+ const updateSnapshot = () => {
618
+ snapshotValueRef.current = reactiveIndex.getPksByKey(stableKey);
619
+ onStoreChange();
620
+ };
621
+ return reactiveIndex.subscribeOnKey(stableKey, updateSnapshot);
622
+ };
623
+ }, [stableKey, reactiveIndex]);
624
+ const getSnapshot = (0, import_react3.useMemo)(() => () => snapshotValueRef.current, []);
625
+ return (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
626
+ };
627
+ var useSelectPksByCompositeIndexKeyArrayBased = (reactiveIndex, key) => {
628
+ const stableKey = useStableKeyPath(key);
629
+ const snapshotValueRef = (0, import_react3.useRef)();
630
+ const subscribe = (0, import_react3.useMemo)(() => {
631
+ snapshotValueRef.current = reactiveIndex.getPksByKey(stableKey);
632
+ return (onStoreChange) => {
633
+ const updateSnapshot = () => {
634
+ snapshotValueRef.current = reactiveIndex.getPksByKey(stableKey);
635
+ onStoreChange();
636
+ };
637
+ return reactiveIndex.subscribeOnKey(stableKey, updateSnapshot);
638
+ };
639
+ }, [stableKey, reactiveIndex]);
640
+ const getSnapshot = (0, import_react3.useMemo)(() => () => snapshotValueRef.current, []);
641
+ return (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
642
+ };
643
+ var useSelectEntitiesByCompositeIndexKeySetBased = (reactiveCollection, reactiveIndex, key) => {
644
+ const stableKey = useStableKeyPath(key);
645
+ const snapshotRef = (0, import_react3.useRef)();
646
+ const subscribe = (0, import_react3.useMemo)(() => {
647
+ const readSnapshot = () => Array.from(
648
+ reactiveIndex.getPksByKey(stableKey),
649
+ (pk) => reactiveCollection.getOneByPk(pk)
650
+ );
651
+ const readPks = () => Array.from(reactiveIndex.getPksByKey(stableKey));
652
+ snapshotRef.current = readSnapshot();
653
+ return (onStoreChange) => {
654
+ let unsubscribeFromCollection = reactiveCollection.subscribeOnKeys(readPks(), () => {
655
+ snapshotRef.current = readSnapshot();
656
+ onStoreChange();
657
+ });
658
+ const resubscribeCollection = () => {
659
+ unsubscribeFromCollection();
660
+ unsubscribeFromCollection = reactiveCollection.subscribeOnKeys(
661
+ readPks(),
662
+ () => {
663
+ snapshotRef.current = readSnapshot();
664
+ onStoreChange();
665
+ }
666
+ );
667
+ };
668
+ const unsubscribeFromIndex = reactiveIndex.subscribeOnKey(
669
+ stableKey,
670
+ () => {
671
+ resubscribeCollection();
672
+ snapshotRef.current = readSnapshot();
673
+ onStoreChange();
674
+ }
675
+ );
676
+ return () => {
677
+ unsubscribeFromIndex();
678
+ unsubscribeFromCollection();
679
+ };
680
+ };
681
+ }, [stableKey, reactiveCollection, reactiveIndex]);
682
+ const getSnapshot = (0, import_react3.useMemo)(() => () => snapshotRef.current, []);
683
+ return (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
684
+ };
685
+ var useSelectEntitiesByCompositeIndexKeyArrayBased = (reactiveCollection, reactiveIndex, key) => {
686
+ const stableKey = useStableKeyPath(key);
687
+ const snapshotRef = (0, import_react3.useRef)();
688
+ const subscribe = (0, import_react3.useMemo)(() => {
689
+ const readSnapshot = () => reactiveIndex.getPksByKey(stableKey).map((pk) => reactiveCollection.getOneByPk(pk));
690
+ const readPks = () => reactiveIndex.getPksByKey(stableKey);
691
+ snapshotRef.current = readSnapshot();
692
+ return (onStoreChange) => {
693
+ let unsubscribeFromCollection = reactiveCollection.subscribeOnKeys(readPks(), () => {
694
+ snapshotRef.current = readSnapshot();
695
+ onStoreChange();
696
+ });
697
+ const resubscribeCollection = () => {
698
+ unsubscribeFromCollection();
699
+ unsubscribeFromCollection = reactiveCollection.subscribeOnKeys(
700
+ readPks(),
701
+ () => {
702
+ snapshotRef.current = readSnapshot();
703
+ onStoreChange();
704
+ }
705
+ );
706
+ };
707
+ const unsubscribeFromIndex = reactiveIndex.subscribeOnKey(
708
+ stableKey,
709
+ () => {
710
+ resubscribeCollection();
711
+ snapshotRef.current = readSnapshot();
712
+ onStoreChange();
713
+ }
714
+ );
715
+ return () => {
716
+ unsubscribeFromIndex();
717
+ unsubscribeFromCollection();
718
+ };
719
+ };
720
+ }, [stableKey, reactiveCollection, reactiveIndex]);
721
+ const getSnapshot = (0, import_react3.useMemo)(() => () => snapshotRef.current, []);
722
+ return (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
469
723
  };
470
724
 
471
725
  // src/context/index.tsx
472
- var import_react4 = require("react");
726
+ var import_react5 = require("react");
473
727
  var import_jsx_runtime = require("react/jsx-runtime");
474
- var OIMCollectionsContext = (0, import_react4.createContext)(
728
+ var OIMCollectionsContext = (0, import_react5.createContext)(
475
729
  {}
476
730
  );
477
731
  function createOIMCollectionsContext() {
478
- return (0, import_react4.createContext)({});
732
+ return (0, import_react5.createContext)({});
479
733
  }
480
734
  function OIMCollectionsProvider({ collections, children, context }) {
481
735
  const ContextToUse = context || OIMCollectionsContext;
@@ -483,7 +737,7 @@ function OIMCollectionsProvider({ collections, children, context }) {
483
737
  }
484
738
  function useOIMCollectionsContext(context) {
485
739
  const contextToUse = context || OIMCollectionsContext;
486
- const collections = (0, import_react4.useContext)(contextToUse);
740
+ const collections = (0, import_react5.useContext)(contextToUse);
487
741
  if (!collections || Object.keys(collections).length === 0) {
488
742
  throw new Error(
489
743
  "useOIMCollectionsContext must be used within an OIMCollectionsProvider"
@@ -497,6 +751,10 @@ function useOIMCollectionsContext(context) {
497
751
  OIMCollectionsProvider,
498
752
  createOIMCollectionsContext,
499
753
  useOIMCollectionsContext,
754
+ useSelectEntitiesByCompositeIndexKeyArrayBased,
755
+ useSelectEntitiesByCompositeIndexKeySetBased,
756
+ useSelectEntitiesByGlobalIndexArrayBased,
757
+ useSelectEntitiesByGlobalIndexSetBased,
500
758
  useSelectEntitiesByIndexKeyArrayBased,
501
759
  useSelectEntitiesByIndexKeySetBased,
502
760
  useSelectEntitiesByIndexKeysArrayBased,
@@ -504,6 +762,12 @@ function useOIMCollectionsContext(context) {
504
762
  useSelectEntitiesByPks,
505
763
  useSelectEntityByPk,
506
764
  useSelectEntityByPkSignal,
765
+ useSelectPksByCompositeIndexKeyArrayBased,
766
+ useSelectPksByCompositeIndexKeySetBased,
767
+ useSelectPksByGlobalIndexArrayBased,
768
+ useSelectPksByGlobalIndexArrayBasedSignal,
769
+ useSelectPksByGlobalIndexSetBased,
770
+ useSelectPksByGlobalIndexSetBasedSignal,
507
771
  useSelectPksByIndexKeyArrayBased,
508
772
  useSelectPksByIndexKeyArrayBasedSignal,
509
773
  useSelectPksByIndexKeySetBased,