@oimdb/core 4.0.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -90,11 +90,11 @@ What each consumer ships, bundled with esbuild (minified, tree-shaken, ESM).
90
90
  <!-- bundle-size:begin -->
91
91
  | Consumer | Minified | Minified + gzip |
92
92
  |---|---:|---:|
93
- | Everything `@oimdb/core` exports | 102689 B | 25093 B |
94
- | One entity store slot: `OIMDB`, `createOIMEntityService`, `upsertEntity`, `getSlotByKey` | 41128 B | 10585 B |
95
- | The same, plus one effect and `db.flush()` | 49617 B | 12713 B |
96
- | The same, plus one index: `createOIMIndexService` | 71095 B | 17506 B |
97
- | An ordered bucket with commands: `createOIMBucketService`, `OIMSlotContentBucketServiceArrayDriven`, `OIMBucketCommands` | 55713 B | 13767 B |
93
+ | Everything `@oimdb/core` exports | 103361 B | 25288 B |
94
+ | One entity store slot: `OIMDB`, `createOIMEntityService`, `upsertEntity`, `getSlotByKey` | 41485 B | 10710 B |
95
+ | The same, plus one effect and `db.flush()` | 50131 B | 12876 B |
96
+ | The same, plus one index: `createOIMIndexService` | 71765 B | 17728 B |
97
+ | An ordered bucket with commands: `createOIMBucketService`, `OIMSlotContentBucketServiceArrayDriven`, `OIMBucketCommands` | 56072 B | 13880 B |
98
98
  <!-- bundle-size:end -->
99
99
 
100
100
  ---
package/dist/index.cjs CHANGED
@@ -822,14 +822,15 @@ var OIMColumnOwner = class extends OIMSlotOwner {
822
822
  return columnSlotStore === void 0 ? void 0 : this.columnSlotStoreService.get(columnSlotStore, key);
823
823
  }
824
824
  mintColumnGroupSlot(carrierSlot, columnGroup) {
825
- if (columnGroup.key !== oimColumnGroupKeyOfColumnNames(columnGroup.columnNames) || columnGroup.key === OIM_ANY_COLUMN_KEY) {
825
+ const storeSlot = carrierSlot.storeSlot;
826
+ const columnGroupsByKey = storeSlot.columnGroupsByKey ?? (storeSlot.columnGroupsByKey = /* @__PURE__ */ new Map());
827
+ const registeredColumnGroup = columnGroupsByKey.get(columnGroup.key);
828
+ if (registeredColumnGroup !== columnGroup && (columnGroup.key !== oimColumnGroupKeyOfColumnNames(columnGroup.columnNames) || columnGroup.key === OIM_ANY_COLUMN_KEY)) {
826
829
  throw new Error(
827
830
  `OIMColumnOwner.holdColumnGroup: "${columnGroup.key}" is not the key of its columns. A column group comes from getColumnGroup, which builds the key from the names.`
828
831
  );
829
832
  }
830
- const storeSlot = carrierSlot.storeSlot;
831
- const columnGroupsByKey = storeSlot.columnGroupsByKey ?? (storeSlot.columnGroupsByKey = /* @__PURE__ */ new Map());
832
- if (!columnGroupsByKey.has(columnGroup.key)) {
833
+ if (registeredColumnGroup === void 0) {
833
834
  columnGroupsByKey.set(columnGroup.key, columnGroup);
834
835
  const columnNames = columnGroup.columnNames;
835
836
  for (let i = 0; i < columnNames.length; i++) getColumnReaders(storeSlot, columnNames[i]).columnGroups.push(columnGroup);
@@ -1233,17 +1234,34 @@ var OIMEffectSourceList = class {
1233
1234
  };
1234
1235
 
1235
1236
  // src/engine/computed/utils/oimMergeRootSlots.ts
1237
+ var scannedRootSlotLimit = 16;
1236
1238
  function oimMergeRootSlots(sourceSlots, sourceComputeds) {
1237
1239
  if (sourceComputeds.length === 0) return sourceSlots;
1238
1240
  if (sourceComputeds.length === 1 && sourceSlots.length === 0) return oimGetAllRootSlots(sourceComputeds[0]);
1239
1241
  const mergedRootSlots = [];
1240
- for (let i = 0; i < sourceSlots.length; i++) mergedRootSlots.push(sourceSlots[i]);
1242
+ let distinctRootSlots;
1243
+ for (let i = 0; i < sourceSlots.length; i++) {
1244
+ distinctRootSlots = pushIfAbsent(mergedRootSlots, distinctRootSlots, sourceSlots[i]);
1245
+ }
1241
1246
  for (let i = 0; i < sourceComputeds.length; i++) {
1242
1247
  const computedRootSlots = oimGetAllRootSlots(sourceComputeds[i]);
1243
- for (let j = 0; j < computedRootSlots.length; j++) mergedRootSlots.push(computedRootSlots[j]);
1248
+ for (let j = 0; j < computedRootSlots.length; j++) {
1249
+ distinctRootSlots = pushIfAbsent(mergedRootSlots, distinctRootSlots, computedRootSlots[j]);
1250
+ }
1244
1251
  }
1245
1252
  return mergedRootSlots;
1246
1253
  }
1254
+ function pushIfAbsent(mergedRootSlots, distinctRootSlots, rootSlot) {
1255
+ if (distinctRootSlots !== void 0) {
1256
+ if (distinctRootSlots.has(rootSlot)) return distinctRootSlots;
1257
+ distinctRootSlots.add(rootSlot);
1258
+ mergedRootSlots.push(rootSlot);
1259
+ return distinctRootSlots;
1260
+ }
1261
+ if (mergedRootSlots.indexOf(rootSlot) !== -1) return void 0;
1262
+ mergedRootSlots.push(rootSlot);
1263
+ return mergedRootSlots.length > scannedRootSlotLimit ? new Set(mergedRootSlots) : void 0;
1264
+ }
1247
1265
 
1248
1266
  // src/engine/computed/utils/oimGetAllRootSlots.ts
1249
1267
  function oimGetAllRootSlots(computedSlot) {
@@ -2010,7 +2028,7 @@ var OIMSlotOwnerService = class extends OIMSlotOwner {
2010
2028
  isAnyColumnReferenced(slot, changedColumns) {
2011
2029
  const storeSlot = slot.storeSlot;
2012
2030
  if (storeSlot === void 0) return false;
2013
- return this.columnOwner.isAnyColumnReferenced(storeSlot, changedColumns) || this.isAnyColumnRead(storeSlot, changedColumns);
2031
+ return slot.columnSlotStore !== void 0 && this.columnOwner.isAnyColumnReferenced(storeSlot, changedColumns) || this.isAnyColumnRead(storeSlot, changedColumns);
2014
2032
  }
2015
2033
  isAnyColumnRead(storeSlot, changedColumns) {
2016
2034
  if (storeSlot.allColumnsListenerCount !== 0) return true;
@@ -2263,16 +2281,25 @@ var OIMSlotContentEntityService = class {
2263
2281
  const slotStoreService = this.slotStoreService;
2264
2282
  const slotOwnerService = this.slotOwnerService;
2265
2283
  const store = storeSlot.store;
2284
+ const isStoreEmptyAtStart = slotStoreService.getSlotCount(store) === 0;
2285
+ const filedEntitySlots = isStoreEmptyAtStart ? [] : void 0;
2266
2286
  let i = 0;
2267
2287
  let filingEntitySlot;
2268
2288
  try {
2269
2289
  for (; i < entities.length; i++) {
2270
2290
  filingEntitySlot = void 0;
2271
2291
  const key = keys === void 0 ? this.keyOf(entities[i]) : keys[i];
2272
- if (slotStoreService.get(store, key) !== void 0) return i;
2292
+ if (filedEntitySlots === void 0 && slotStoreService.get(store, key) !== void 0) return i;
2273
2293
  const entitySlot = slotOwnerService.createSlot(slotStoreService.ownKey(key), storeSlot);
2274
2294
  slotOwnerService.assertWritable(entitySlot);
2275
2295
  slotOwnerService.fileSlot(storeSlot, entitySlot);
2296
+ if (filedEntitySlots !== void 0) {
2297
+ if (slotStoreService.getSlotCount(store) === filedEntitySlots.length) {
2298
+ this.refileRepeatedKey(storeSlot, filedEntitySlots, entitySlot);
2299
+ return i;
2300
+ }
2301
+ filedEntitySlots.push(entitySlot);
2302
+ }
2276
2303
  filingEntitySlot = entitySlot;
2277
2304
  this.fillSlotContent(entitySlot, entities[i]);
2278
2305
  if (oimIsSlotEmpty(entitySlot)) slotOwnerService.releaseSlotIfUnheld(entitySlot);
@@ -2288,6 +2315,15 @@ var OIMSlotContentEntityService = class {
2288
2315
  }
2289
2316
  return entities.length;
2290
2317
  }
2318
+ refileRepeatedKey(storeSlot, filedEntitySlots, repeatingEntitySlot) {
2319
+ const slotStoreService = this.slotStoreService;
2320
+ for (let j = 0; j < filedEntitySlots.length; j++) {
2321
+ const filedEntitySlot = filedEntitySlots[j];
2322
+ if (!slotStoreService.isSameKey(filedEntitySlot.key, repeatingEntitySlot.key)) continue;
2323
+ this.slotOwnerService.fileSlot(storeSlot, filedEntitySlot);
2324
+ return;
2325
+ }
2326
+ }
2291
2327
  insertEntityOnFastPath(storeSlot, entitySlot, entity, changedEntitySlots) {
2292
2328
  const slotOwnerService = this.slotOwnerService;
2293
2329
  try {
@@ -4612,6 +4648,7 @@ var OIMIndexService = class extends OIMSlotCollectionService {
4612
4648
  const indexKeysPosition = indexStoreSlot.indexKeysPosition;
4613
4649
  let arrivingByKey;
4614
4650
  let leavingByKey;
4651
+ const bucketSlotsByKey = /* @__PURE__ */ new Map();
4615
4652
  let isRefused = false;
4616
4653
  let refusal;
4617
4654
  for (let i = 0; i < entitySlotChannelQueue.getEntryCount(); i++) {
@@ -4625,24 +4662,41 @@ var OIMIndexService = class extends OIMSlotCollectionService {
4625
4662
  }
4626
4663
  const nextKey = indexKeysService.get(entitySlot, indexKeysPosition);
4627
4664
  if (nextKey === prevKey) continue;
4628
- if (nextKey !== void 0) groupUnderKey(arrivingByKey ?? (arrivingByKey = /* @__PURE__ */ new Map()), nextKey, entitySlot);
4629
- if (prevKey !== void 0) groupUnderKey(leavingByKey ?? (leavingByKey = /* @__PURE__ */ new Map()), prevKey, entitySlot);
4665
+ if (nextKey !== void 0) {
4666
+ this.groupUnderMintedBucketKey(indexStoreSlot, bucketSlotsByKey, arrivingByKey ?? (arrivingByKey = /* @__PURE__ */ new Map()), nextKey, entitySlot);
4667
+ }
4668
+ if (prevKey !== void 0) {
4669
+ this.groupUnderMintedBucketKey(indexStoreSlot, bucketSlotsByKey, leavingByKey ?? (leavingByKey = /* @__PURE__ */ new Map()), prevKey, entitySlot);
4670
+ }
4630
4671
  }
4631
4672
  const slotContentService = this.slotContentBucketService;
4632
4673
  if (arrivingByKey !== void 0) {
4633
4674
  for (const [key, arriving] of arrivingByKey) {
4634
- const bucketSlot = this.findSlotByKey(indexStoreSlot, key);
4635
- if (bucketSlot !== void 0) slotContentService.addBucketMemberSlots(bucketSlot, arriving);
4675
+ if (arriving !== null) slotContentService.addBucketMemberSlots(bucketSlotsByKey.get(key), arriving);
4636
4676
  }
4637
4677
  }
4638
4678
  if (leavingByKey !== void 0) {
4639
4679
  for (const [key, leaving] of leavingByKey) {
4640
- const bucketSlot = this.findSlotByKey(indexStoreSlot, key);
4641
- if (bucketSlot !== void 0) slotContentService.removeBucketMemberSlots(bucketSlot, leaving);
4680
+ if (leaving !== null) slotContentService.removeBucketMemberSlots(bucketSlotsByKey.get(key), leaving);
4642
4681
  }
4643
4682
  }
4644
4683
  if (isRefused) throw refusal;
4645
4684
  }
4685
+ groupUnderMintedBucketKey(indexStoreSlot, bucketSlotsByKey, entitySlotsByKey, key, entitySlot) {
4686
+ const grouped = entitySlotsByKey.get(key);
4687
+ if (grouped === null) return;
4688
+ if (grouped !== void 0) {
4689
+ grouped.push(entitySlot);
4690
+ return;
4691
+ }
4692
+ const bucketSlot = bucketSlotsByKey.get(key) ?? this.findSlotByKey(indexStoreSlot, key);
4693
+ if (bucketSlot === void 0) {
4694
+ entitySlotsByKey.set(key, null);
4695
+ return;
4696
+ }
4697
+ bucketSlotsByKey.set(key, bucketSlot);
4698
+ entitySlotsByKey.set(key, [entitySlot]);
4699
+ }
4646
4700
  decideIndexKeyForSlot(indexStoreSlot, entitySlot, patch, changedColumns) {
4647
4701
  if (oimIsSlotReleased(entitySlot)) return;
4648
4702
  const isKeyColumnChanged = this.isKeyColumnChanged(changedColumns);
@@ -4704,11 +4758,6 @@ var OIMIndexService = class extends OIMSlotCollectionService {
4704
4758
  function takeNothing() {
4705
4759
  return;
4706
4760
  }
4707
- function groupUnderKey(entitySlotsByKey, key, entitySlot) {
4708
- const grouped = entitySlotsByKey.get(key);
4709
- if (grouped === void 0) entitySlotsByKey.set(key, [entitySlot]);
4710
- else grouped.push(entitySlot);
4711
- }
4712
4761
 
4713
4762
  // src/facade/index/OIMIndexServiceSortedArrayDriven.ts
4714
4763
  var OIMIndexServiceSortedArrayDriven = class extends OIMIndexService {
package/dist/index.d.cts CHANGED
@@ -698,6 +698,7 @@ declare class OIMSlotContentEntityService<TEntity extends object, TKey, TStore =
698
698
  private fillEntitiesUnderKeys;
699
699
  clearAllEntities(storeSlot: TOIMStoreSlot<TStore, TOIMEntitySlot<TEntity, TKey>>): void;
700
700
  private fillEachEntity;
701
+ private refileRepeatedKey;
701
702
  private insertEntityOnFastPath;
702
703
  private insertEntityInSubframe;
703
704
  writeEntity(entitySlot: TOIMEntitySlot<TEntity, TKey>, entity: TEntity): boolean;
@@ -1071,6 +1072,7 @@ declare class OIMIndexService<TKey, TEntity extends object, TSlots, TSourceKey =
1071
1072
  private isBucketColumnChanged;
1072
1073
  private updateIndexKeyForSlot;
1073
1074
  private updateIndexKeysForSlots;
1075
+ private groupUnderMintedBucketKey;
1074
1076
  private decideIndexKeyForSlot;
1075
1077
  private collectSourceSlotsForKey;
1076
1078
  private setIndexKeyForSlots;
package/dist/index.d.ts CHANGED
@@ -698,6 +698,7 @@ declare class OIMSlotContentEntityService<TEntity extends object, TKey, TStore =
698
698
  private fillEntitiesUnderKeys;
699
699
  clearAllEntities(storeSlot: TOIMStoreSlot<TStore, TOIMEntitySlot<TEntity, TKey>>): void;
700
700
  private fillEachEntity;
701
+ private refileRepeatedKey;
701
702
  private insertEntityOnFastPath;
702
703
  private insertEntityInSubframe;
703
704
  writeEntity(entitySlot: TOIMEntitySlot<TEntity, TKey>, entity: TEntity): boolean;
@@ -1071,6 +1072,7 @@ declare class OIMIndexService<TKey, TEntity extends object, TSlots, TSourceKey =
1071
1072
  private isBucketColumnChanged;
1072
1073
  private updateIndexKeyForSlot;
1073
1074
  private updateIndexKeysForSlots;
1075
+ private groupUnderMintedBucketKey;
1074
1076
  private decideIndexKeyForSlot;
1075
1077
  private collectSourceSlotsForKey;
1076
1078
  private setIndexKeyForSlots;
package/dist/index.js CHANGED
@@ -699,14 +699,15 @@ var OIMColumnOwner = class extends OIMSlotOwner {
699
699
  return columnSlotStore === void 0 ? void 0 : this.columnSlotStoreService.get(columnSlotStore, key);
700
700
  }
701
701
  mintColumnGroupSlot(carrierSlot, columnGroup) {
702
- if (columnGroup.key !== oimColumnGroupKeyOfColumnNames(columnGroup.columnNames) || columnGroup.key === OIM_ANY_COLUMN_KEY) {
702
+ const storeSlot = carrierSlot.storeSlot;
703
+ const columnGroupsByKey = storeSlot.columnGroupsByKey ?? (storeSlot.columnGroupsByKey = /* @__PURE__ */ new Map());
704
+ const registeredColumnGroup = columnGroupsByKey.get(columnGroup.key);
705
+ if (registeredColumnGroup !== columnGroup && (columnGroup.key !== oimColumnGroupKeyOfColumnNames(columnGroup.columnNames) || columnGroup.key === OIM_ANY_COLUMN_KEY)) {
703
706
  throw new Error(
704
707
  `OIMColumnOwner.holdColumnGroup: "${columnGroup.key}" is not the key of its columns. A column group comes from getColumnGroup, which builds the key from the names.`
705
708
  );
706
709
  }
707
- const storeSlot = carrierSlot.storeSlot;
708
- const columnGroupsByKey = storeSlot.columnGroupsByKey ?? (storeSlot.columnGroupsByKey = /* @__PURE__ */ new Map());
709
- if (!columnGroupsByKey.has(columnGroup.key)) {
710
+ if (registeredColumnGroup === void 0) {
710
711
  columnGroupsByKey.set(columnGroup.key, columnGroup);
711
712
  const columnNames = columnGroup.columnNames;
712
713
  for (let i = 0; i < columnNames.length; i++) getColumnReaders(storeSlot, columnNames[i]).columnGroups.push(columnGroup);
@@ -1110,17 +1111,34 @@ var OIMEffectSourceList = class {
1110
1111
  };
1111
1112
 
1112
1113
  // src/engine/computed/utils/oimMergeRootSlots.ts
1114
+ var scannedRootSlotLimit = 16;
1113
1115
  function oimMergeRootSlots(sourceSlots, sourceComputeds) {
1114
1116
  if (sourceComputeds.length === 0) return sourceSlots;
1115
1117
  if (sourceComputeds.length === 1 && sourceSlots.length === 0) return oimGetAllRootSlots(sourceComputeds[0]);
1116
1118
  const mergedRootSlots = [];
1117
- for (let i = 0; i < sourceSlots.length; i++) mergedRootSlots.push(sourceSlots[i]);
1119
+ let distinctRootSlots;
1120
+ for (let i = 0; i < sourceSlots.length; i++) {
1121
+ distinctRootSlots = pushIfAbsent(mergedRootSlots, distinctRootSlots, sourceSlots[i]);
1122
+ }
1118
1123
  for (let i = 0; i < sourceComputeds.length; i++) {
1119
1124
  const computedRootSlots = oimGetAllRootSlots(sourceComputeds[i]);
1120
- for (let j = 0; j < computedRootSlots.length; j++) mergedRootSlots.push(computedRootSlots[j]);
1125
+ for (let j = 0; j < computedRootSlots.length; j++) {
1126
+ distinctRootSlots = pushIfAbsent(mergedRootSlots, distinctRootSlots, computedRootSlots[j]);
1127
+ }
1121
1128
  }
1122
1129
  return mergedRootSlots;
1123
1130
  }
1131
+ function pushIfAbsent(mergedRootSlots, distinctRootSlots, rootSlot) {
1132
+ if (distinctRootSlots !== void 0) {
1133
+ if (distinctRootSlots.has(rootSlot)) return distinctRootSlots;
1134
+ distinctRootSlots.add(rootSlot);
1135
+ mergedRootSlots.push(rootSlot);
1136
+ return distinctRootSlots;
1137
+ }
1138
+ if (mergedRootSlots.indexOf(rootSlot) !== -1) return void 0;
1139
+ mergedRootSlots.push(rootSlot);
1140
+ return mergedRootSlots.length > scannedRootSlotLimit ? new Set(mergedRootSlots) : void 0;
1141
+ }
1124
1142
 
1125
1143
  // src/engine/computed/utils/oimGetAllRootSlots.ts
1126
1144
  function oimGetAllRootSlots(computedSlot) {
@@ -1887,7 +1905,7 @@ var OIMSlotOwnerService = class extends OIMSlotOwner {
1887
1905
  isAnyColumnReferenced(slot, changedColumns) {
1888
1906
  const storeSlot = slot.storeSlot;
1889
1907
  if (storeSlot === void 0) return false;
1890
- return this.columnOwner.isAnyColumnReferenced(storeSlot, changedColumns) || this.isAnyColumnRead(storeSlot, changedColumns);
1908
+ return slot.columnSlotStore !== void 0 && this.columnOwner.isAnyColumnReferenced(storeSlot, changedColumns) || this.isAnyColumnRead(storeSlot, changedColumns);
1891
1909
  }
1892
1910
  isAnyColumnRead(storeSlot, changedColumns) {
1893
1911
  if (storeSlot.allColumnsListenerCount !== 0) return true;
@@ -2140,16 +2158,25 @@ var OIMSlotContentEntityService = class {
2140
2158
  const slotStoreService = this.slotStoreService;
2141
2159
  const slotOwnerService = this.slotOwnerService;
2142
2160
  const store = storeSlot.store;
2161
+ const isStoreEmptyAtStart = slotStoreService.getSlotCount(store) === 0;
2162
+ const filedEntitySlots = isStoreEmptyAtStart ? [] : void 0;
2143
2163
  let i = 0;
2144
2164
  let filingEntitySlot;
2145
2165
  try {
2146
2166
  for (; i < entities.length; i++) {
2147
2167
  filingEntitySlot = void 0;
2148
2168
  const key = keys === void 0 ? this.keyOf(entities[i]) : keys[i];
2149
- if (slotStoreService.get(store, key) !== void 0) return i;
2169
+ if (filedEntitySlots === void 0 && slotStoreService.get(store, key) !== void 0) return i;
2150
2170
  const entitySlot = slotOwnerService.createSlot(slotStoreService.ownKey(key), storeSlot);
2151
2171
  slotOwnerService.assertWritable(entitySlot);
2152
2172
  slotOwnerService.fileSlot(storeSlot, entitySlot);
2173
+ if (filedEntitySlots !== void 0) {
2174
+ if (slotStoreService.getSlotCount(store) === filedEntitySlots.length) {
2175
+ this.refileRepeatedKey(storeSlot, filedEntitySlots, entitySlot);
2176
+ return i;
2177
+ }
2178
+ filedEntitySlots.push(entitySlot);
2179
+ }
2153
2180
  filingEntitySlot = entitySlot;
2154
2181
  this.fillSlotContent(entitySlot, entities[i]);
2155
2182
  if (oimIsSlotEmpty(entitySlot)) slotOwnerService.releaseSlotIfUnheld(entitySlot);
@@ -2165,6 +2192,15 @@ var OIMSlotContentEntityService = class {
2165
2192
  }
2166
2193
  return entities.length;
2167
2194
  }
2195
+ refileRepeatedKey(storeSlot, filedEntitySlots, repeatingEntitySlot) {
2196
+ const slotStoreService = this.slotStoreService;
2197
+ for (let j = 0; j < filedEntitySlots.length; j++) {
2198
+ const filedEntitySlot = filedEntitySlots[j];
2199
+ if (!slotStoreService.isSameKey(filedEntitySlot.key, repeatingEntitySlot.key)) continue;
2200
+ this.slotOwnerService.fileSlot(storeSlot, filedEntitySlot);
2201
+ return;
2202
+ }
2203
+ }
2168
2204
  insertEntityOnFastPath(storeSlot, entitySlot, entity, changedEntitySlots) {
2169
2205
  const slotOwnerService = this.slotOwnerService;
2170
2206
  try {
@@ -4489,6 +4525,7 @@ var OIMIndexService = class extends OIMSlotCollectionService {
4489
4525
  const indexKeysPosition = indexStoreSlot.indexKeysPosition;
4490
4526
  let arrivingByKey;
4491
4527
  let leavingByKey;
4528
+ const bucketSlotsByKey = /* @__PURE__ */ new Map();
4492
4529
  let isRefused = false;
4493
4530
  let refusal;
4494
4531
  for (let i = 0; i < entitySlotChannelQueue.getEntryCount(); i++) {
@@ -4502,24 +4539,41 @@ var OIMIndexService = class extends OIMSlotCollectionService {
4502
4539
  }
4503
4540
  const nextKey = indexKeysService.get(entitySlot, indexKeysPosition);
4504
4541
  if (nextKey === prevKey) continue;
4505
- if (nextKey !== void 0) groupUnderKey(arrivingByKey ?? (arrivingByKey = /* @__PURE__ */ new Map()), nextKey, entitySlot);
4506
- if (prevKey !== void 0) groupUnderKey(leavingByKey ?? (leavingByKey = /* @__PURE__ */ new Map()), prevKey, entitySlot);
4542
+ if (nextKey !== void 0) {
4543
+ this.groupUnderMintedBucketKey(indexStoreSlot, bucketSlotsByKey, arrivingByKey ?? (arrivingByKey = /* @__PURE__ */ new Map()), nextKey, entitySlot);
4544
+ }
4545
+ if (prevKey !== void 0) {
4546
+ this.groupUnderMintedBucketKey(indexStoreSlot, bucketSlotsByKey, leavingByKey ?? (leavingByKey = /* @__PURE__ */ new Map()), prevKey, entitySlot);
4547
+ }
4507
4548
  }
4508
4549
  const slotContentService = this.slotContentBucketService;
4509
4550
  if (arrivingByKey !== void 0) {
4510
4551
  for (const [key, arriving] of arrivingByKey) {
4511
- const bucketSlot = this.findSlotByKey(indexStoreSlot, key);
4512
- if (bucketSlot !== void 0) slotContentService.addBucketMemberSlots(bucketSlot, arriving);
4552
+ if (arriving !== null) slotContentService.addBucketMemberSlots(bucketSlotsByKey.get(key), arriving);
4513
4553
  }
4514
4554
  }
4515
4555
  if (leavingByKey !== void 0) {
4516
4556
  for (const [key, leaving] of leavingByKey) {
4517
- const bucketSlot = this.findSlotByKey(indexStoreSlot, key);
4518
- if (bucketSlot !== void 0) slotContentService.removeBucketMemberSlots(bucketSlot, leaving);
4557
+ if (leaving !== null) slotContentService.removeBucketMemberSlots(bucketSlotsByKey.get(key), leaving);
4519
4558
  }
4520
4559
  }
4521
4560
  if (isRefused) throw refusal;
4522
4561
  }
4562
+ groupUnderMintedBucketKey(indexStoreSlot, bucketSlotsByKey, entitySlotsByKey, key, entitySlot) {
4563
+ const grouped = entitySlotsByKey.get(key);
4564
+ if (grouped === null) return;
4565
+ if (grouped !== void 0) {
4566
+ grouped.push(entitySlot);
4567
+ return;
4568
+ }
4569
+ const bucketSlot = bucketSlotsByKey.get(key) ?? this.findSlotByKey(indexStoreSlot, key);
4570
+ if (bucketSlot === void 0) {
4571
+ entitySlotsByKey.set(key, null);
4572
+ return;
4573
+ }
4574
+ bucketSlotsByKey.set(key, bucketSlot);
4575
+ entitySlotsByKey.set(key, [entitySlot]);
4576
+ }
4523
4577
  decideIndexKeyForSlot(indexStoreSlot, entitySlot, patch, changedColumns) {
4524
4578
  if (oimIsSlotReleased(entitySlot)) return;
4525
4579
  const isKeyColumnChanged = this.isKeyColumnChanged(changedColumns);
@@ -4581,11 +4635,6 @@ var OIMIndexService = class extends OIMSlotCollectionService {
4581
4635
  function takeNothing() {
4582
4636
  return;
4583
4637
  }
4584
- function groupUnderKey(entitySlotsByKey, key, entitySlot) {
4585
- const grouped = entitySlotsByKey.get(key);
4586
- if (grouped === void 0) entitySlotsByKey.set(key, [entitySlot]);
4587
- else grouped.push(entitySlot);
4588
- }
4589
4638
 
4590
4639
  // src/facade/index/OIMIndexServiceSortedArrayDriven.ts
4591
4640
  var OIMIndexServiceSortedArrayDriven = class extends OIMIndexService {
package/llms.txt CHANGED
@@ -39,8 +39,7 @@
39
39
  >
40
40
  > Check every symbol you write against [the full export list](#full-export-list).
41
41
  >
42
- > **Nothing in this repository is published to npm and nothing consumes it.**
43
- > Backwards compatibility, semver and migration paths are not costs here.
42
+ > Install: `npm install @oimdb/core` (4.x). The 3.x line is the previous engine with a different API.
44
43
  >
45
44
  > `packages/core/src/index.ts` is the entire public surface.
46
45
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oimdb/core",
3
- "version": "4.0.0",
4
- "description": "Identity-addressed rewrite of the OIMDB core. Not published: it replaces @oimdb/core only once every consumer is migrated and the differential suite is green.",
3
+ "version": "4.0.1",
4
+ "description": "Identity-addressed reactive in-memory store: entities, indexes, computed values and effects batched into frames.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",