@karmaniverous/entity-manager 7.3.4 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -363,7 +363,11 @@ const manager = createEntityManager(config, logger);
363
363
  - `createEntityManager(config, logger?)`
364
364
  - `ConfigInput` (values‑first), `CapturedConfigMapFrom`, `EntitiesFromSchema`
365
365
  - Token aware
366
- - `EntityToken<CC>`, `EntityItemByToken<CC, ET>`, `EntityRecordByToken<CC, ET>`
366
+ - `EntityToken<CC>`
367
+ - `EntityItem<CC, ET>` — strict domain (full), includes optional key/token properties
368
+ - `EntityItemPartial<CC, ET, K>` — projected/seed domain; required keys when K provided, permissive partial when K omitted
369
+ - `EntityRecord<CC, ET>` — DB record (required keys) + partial domain fields
370
+ - `EntityRecordPartial<CC, ET, K>` — projected DB record
367
371
  - Index aware (values‑first config literal, “CF” channel)
368
372
  - `PageKeyByIndex<CC, ET, IT, CF>`
369
373
  - `ShardQueryFunction<CC, ET, IT, CF>`, `ShardQueryMap<CC, ET, ITS, CF>`
@@ -373,6 +377,8 @@ const manager = createEntityManager(config, logger);
373
377
  - `KeysFrom<K>`
374
378
  - `Projected<T, K>`
375
379
  - `ProjectedItemByToken<CC, ET, K>`
380
+ - Advanced (storage shapes; exported for reference and TypeDoc)
381
+ - `StorageItem<CC>`, `StorageRecord<CC>`
376
382
 
377
383
  See the full API: https://docs.karmanivero.us/entity-manager
378
384
 
@@ -64,7 +64,7 @@ class EntityManager {
64
64
  * Encode a generated property value. Returns a string or undefined if atomicity requirement of sharded properties not met.
65
65
  *
66
66
  * @param property - {@link Config | Config} `generatedProperties` key.
67
- * @param item - {@link EntityItem | `EntityItem`} object.
67
+ * @param item - {@link StorageItem | `StorageItem`} object.
68
68
  *
69
69
  * @returns Encoded generated property value.
70
70
  *
@@ -87,9 +87,11 @@ class EntityManager {
87
87
  }
88
88
  removeKeys(entityToken, i) {
89
89
  if (Array.isArray(i)) {
90
- return i.map((item) => removeKeys.removeKeys(this, entityToken, item));
90
+ const out = i.map((item) => removeKeys.removeKeys(this, entityToken, item));
91
+ return out;
91
92
  }
92
- return removeKeys.removeKeys(this, entityToken, i);
93
+ const out = removeKeys.removeKeys(this, entityToken, i);
94
+ return out;
93
95
  }
94
96
  findIndexToken(hashKeyToken, rangeKeyToken, suppressError) {
95
97
  // Dispatch with a literal to satisfy overload selection.
@@ -120,7 +122,8 @@ class EntityManager {
120
122
  * @protected
121
123
  */
122
124
  async query(options) {
123
- return await query.query(this, options);
125
+ const result = await query.query(this, options);
126
+ return result;
124
127
  }
125
128
  }
126
129
  _EntityManager_config = new WeakMap();
@@ -8,7 +8,7 @@ var validateGeneratedProperty = require('./validateGeneratedProperty.js');
8
8
  *
9
9
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
10
10
  * @param property - {@link Config.generatedProperties | Generated property} key.
11
- * @param item - {@link EntityItem | `EntityItem`} object.
11
+ * @param item - {@link StorageItem | `StorageItem`} object.
12
12
  *
13
13
  * @returns Encoded generated property value.
14
14
  *
@@ -21,7 +21,10 @@ function encodeGeneratedProperty(entityManager, property, item) {
21
21
  const sharded = property in entityManager.config.generatedProperties.sharded;
22
22
  const elements = entityManager.config.generatedProperties[sharded ? 'sharded' : 'unsharded'][property];
23
23
  // Map elements to [element, value] pairs.
24
- const elementMap = elements.map((element) => [element, item[element]]);
24
+ const elementMap = elements.map((element) => [
25
+ element,
26
+ item[element],
27
+ ]);
25
28
  // Return undefined if sharded & atomicity requirement fails.
26
29
  if (sharded && elementMap.some(([, value]) => entityTools.isNil(value)))
27
30
  return;
@@ -52,7 +52,7 @@ function getHashKeySpace(entityManager, entityToken, hashKeyToken, item, timesta
52
52
  // Map shard keys to hash keys.
53
53
  .map((shardKey) => {
54
54
  // Calculate record hash key.
55
- let hashKey = `${entityToken}${entityManager.config.shardKeyDelimiter}${shardKey}`;
55
+ let hashKey = `${String(entityToken)}${entityManager.config.shardKeyDelimiter}${shardKey}`;
56
56
  // If hash key space basis is a different property, encode it.
57
57
  if (hashKeyToken !== entityManager.config.hashKey)
58
58
  hashKey = encodeGeneratedProperty.encodeGeneratedProperty(entityManager, hashKeyToken, {
@@ -27,11 +27,14 @@ var updateItemRangeKey = require('./updateItemRangeKey.js');
27
27
  function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
28
28
  const { hashKey, rangeKey } = entityManager.config;
29
29
  // If both keys are present and we're not overwriting, return the exact pair.
30
- if (!overwrite && item[hashKey] && item[rangeKey]) {
30
+ const rec = item;
31
+ const hk = hashKey;
32
+ const rk = rangeKey;
33
+ if (!overwrite && rec[hk] && rec[rk]) {
31
34
  return [
32
35
  {
33
- [hashKey]: item[hashKey],
34
- [rangeKey]: item[rangeKey],
36
+ [hashKey]: rec[hk],
37
+ [rangeKey]: rec[rk],
35
38
  },
36
39
  ];
37
40
  }
@@ -40,6 +43,7 @@ function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
40
43
  // If timestamp present, compute exactly one hash key and return single pair.
41
44
  const tsProp = entityManager.config.entities[entityToken].timestampProperty;
42
45
  if (withRangeKey[tsProp] !== undefined) {
46
+ // Note: use StorageItem here
43
47
  const withHashKey = updateItemHashKey.updateItemHashKey(entityManager, entityToken, withRangeKey, true);
44
48
  return [
45
49
  {
@@ -51,12 +55,15 @@ function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
51
55
  // No timestamp: enumerate hash-key space across all shard bumps (0..Infinity).
52
56
  const hashKeys = getHashKeySpace.getHashKeySpace(entityManager, entityToken, hashKey, withRangeKey, 0, Infinity);
53
57
  // Map to keys and de-duplicate.
54
- const rk = withRangeKey[rangeKey];
58
+ const rangeKeyValue = withRangeKey[rangeKey];
55
59
  const seen = new Set();
56
60
  const keys = hashKeys
57
61
  .map((hk) => {
58
- const key = { [hashKey]: hk, [rangeKey]: rk };
59
- const sig = `${hk}|${rk}`;
62
+ const key = {
63
+ [hashKey]: hk,
64
+ [rangeKey]: rangeKeyValue,
65
+ };
66
+ const sig = `${hk}|${rangeKeyValue}`;
60
67
  if (seen.has(sig))
61
68
  return undefined;
62
69
  seen.add(sig);
@@ -25,14 +25,21 @@ function removeKeys(entityManager, entityToken, item) {
25
25
  ...Object.keys(sharded),
26
26
  ...Object.keys(unsharded),
27
27
  ]);
28
- // Create a shallow copy of item omitting the keys above (no delete operator).
29
- const newItem = Object.fromEntries(Object.entries(item).filter(([key]) => !keysToStrip.has(key)));
28
+ // Create a shallow copy of item omitting the keys above (no delete operator),
29
+ // avoiding any-typed assignments.
30
+ const source = item;
31
+ const newItemObj = {};
32
+ for (const [key, value] of Object.entries(source)) {
33
+ if (!keysToStrip.has(key)) {
34
+ newItemObj[key] = value;
35
+ }
36
+ }
30
37
  entityManager.logger.debug('stripped entity item generated properties', {
31
38
  entityToken,
32
39
  item,
33
- newItem,
40
+ newItem: newItemObj,
34
41
  });
35
- return newItem;
42
+ return newItemObj;
36
43
  }
37
44
  catch (error) {
38
45
  if (error instanceof Error)
@@ -6,11 +6,11 @@ var getShardBump = require('./getShardBump.js');
6
6
  var validateEntityToken = require('./validateEntityToken.js');
7
7
 
8
8
  /**
9
- * Update the hash key on an partial {@link EntityItem | `EntityItem`} object.
9
+ * Update the hash key on an {@link EntityItemPartial | `EntityItemPartial`} object.
10
10
  *
11
11
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
12
12
  * @param entityToken - {@link Config.entities | `this.config.entities`} key.
13
- * @param item - {@link EntityItem | `EntityItem`} object.
13
+ * @param item - {@link StorageItem | `StorageItem`} object.
14
14
  * @param overwrite - Overwrite existing {@link ConfigKeys.hashKey | `this.config.hashKey`} property value (default `false`).
15
15
  *
16
16
  * @returns Shallow clone of `item` with updated hash key.
@@ -32,13 +32,14 @@ function updateItemHashKey(entityManager, entityToken, item, overwrite = false)
32
32
  return { ...item };
33
33
  }
34
34
  // Get item timestamp property & validate.
35
- const timestamp = item[entityManager.config.entities[entityToken]
36
- .timestampProperty];
35
+ const tsProp = entityManager.config.entities[entityToken]
36
+ .timestampProperty;
37
+ const timestamp = item[tsProp];
37
38
  if (entityTools.isNil(timestamp))
38
39
  throw new Error(`missing item timestamp property`);
39
40
  // Find first entity sharding bump before timestamp.
40
41
  const { charBits, chars } = getShardBump.getShardBump(entityManager, entityToken, timestamp);
41
- let hashKey = `${entityToken}${entityManager.config.shardKeyDelimiter}`;
42
+ let hashKey = `${String(entityToken)}${entityManager.config.shardKeyDelimiter}`;
42
43
  if (chars) {
43
44
  // Radix is the numerical base of the shardKey.
44
45
  const radix = 2 ** charBits;
@@ -46,8 +47,9 @@ function updateItemHashKey(entityManager, entityToken, item, overwrite = false)
46
47
  // all placeholders are utilized (e.g., chars=2, charBits=2 => 16 combos).
47
48
  const space = radix ** chars;
48
49
  // Get item unique property & validate.
49
- const uniqueId = item[entityManager.config.entities[entityToken]
50
- .uniqueProperty];
50
+ const upProp = entityManager.config.entities[entityToken]
51
+ .uniqueProperty;
52
+ const uniqueId = item[upProp];
51
53
  if (entityTools.isNil(uniqueId))
52
54
  throw new Error(`missing item unique property`);
53
55
  hashKey += (stringHash(uniqueId) % space)
@@ -4,11 +4,11 @@ var entityTools = require('@karmaniverous/entity-tools');
4
4
  var validateEntityToken = require('./validateEntityToken.js');
5
5
 
6
6
  /**
7
- * Update the range key on an {@link EntityItem | `EntityItem`} object.
7
+ * Update the range key on an {@link EntityItemPartial | `EntityItemPartial`} object.
8
8
  *
9
9
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
10
10
  * @param entityToken - {@link Config.entities | `this.config.entities`} key.
11
- * @param item - {@link EntityItem | `EntityItem`} object.
11
+ * @param item - {@link StorageItem | `StorageItem`} object.
12
12
  * @param overwrite - Overwrite existing {@link ConfigKeys.rangeKey | `this.config.rangeKey`} property value (default `false`).
13
13
  *
14
14
  * @returns Shallow clone of `item` with updated range key.
@@ -21,8 +21,8 @@ function updateItemRangeKey(entityManager, entityToken, item, overwrite = false)
21
21
  // Validate params.
22
22
  validateEntityToken.validateEntityToken(entityManager, entityToken);
23
23
  // Return current item if rangeKey exists and overwrite is false.
24
- if (item[entityManager.config.rangeKey] &&
25
- !overwrite) {
24
+ const rkProp = entityManager.config.rangeKey;
25
+ if (item[rkProp] && !overwrite) {
26
26
  entityManager.logger.debug('did not overwrite existing entity item range key', {
27
27
  entityToken,
28
28
  item,
@@ -31,15 +31,16 @@ function updateItemRangeKey(entityManager, entityToken, item, overwrite = false)
31
31
  return { ...item };
32
32
  }
33
33
  // Get item unique property & validate.
34
- const uniqueProperty = item[entityManager.config.entities[entityToken]
35
- .uniqueProperty];
36
- if (entityTools.isNil(uniqueProperty))
34
+ const upProp = entityManager.config.entities[entityToken]
35
+ .uniqueProperty;
36
+ const uniqueValue = item[upProp];
37
+ if (entityTools.isNil(uniqueValue))
37
38
  throw new Error(`missing item unique property`);
38
39
  // Update range key.
39
40
  const newItem = Object.assign({ ...item }, {
40
41
  [entityManager.config.rangeKey]: [
41
42
  entityManager.config.entities[entityToken].uniqueProperty,
42
- uniqueProperty,
43
+ uniqueValue,
43
44
  ].join(entityManager.config.generatedValueDelimiter),
44
45
  });
45
46
  entityManager.logger.debug('updated entity item range key', {
package/dist/index.d.ts CHANGED
@@ -58,8 +58,8 @@ type Config<C extends BaseConfigMap = BaseConfigMap> = ConditionalProperty<'enti
58
58
  defaultLimit?: number;
59
59
  defaultPageSize?: number;
60
60
  shardBumps?: ShardBump[];
61
- timestampProperty: C['TranscodedProperties'] & PropertiesOfType<C['EntityMap'][E], number> & TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>;
62
- uniqueProperty: C['TranscodedProperties'] & keyof C['EntityMap'][E] & TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>;
61
+ timestampProperty: Extract<Extract<C['TranscodedProperties'], PropertiesOfType<C['EntityMap'][E], number>>, TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>>;
62
+ uniqueProperty: Extract<Extract<C['TranscodedProperties'], keyof C['EntityMap'][E]>, TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>>;
63
63
  };
64
64
  }> & ConditionalProperty<'generatedProperties', C['ShardedKeys'] | C['UnshardedKeys'], ConditionalProperty<'sharded', C['ShardedKeys'], Record<C['ShardedKeys'], (C['TranscodedProperties'] & TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>)[]>> & ConditionalProperty<'unsharded', C['UnshardedKeys'], Record<C['UnshardedKeys'], (C['TranscodedProperties'] & TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>)[]>>> & ConditionalProperty<'propertyTranscodes', C['TranscodedProperties'] & TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>, {
65
65
  [P in C['TranscodedProperties'] & TranscodableProperties<C['EntityMap'], C['TranscodeRegistry']>]: PropertiesOfType<C['TranscodeRegistry'], FlattenEntityMap<C['EntityMap']>[P]>;
@@ -119,44 +119,46 @@ type ConfigMap<M extends Partial<BaseConfigMap> = Partial<BaseConfigMap>> = Vali
119
119
  }>;
120
120
 
121
121
  /**
122
- * Extracts a database-facing partial item type from a {@link BaseConfigMap | `ConfigMap`}.
122
+ * Database-facing record key type from a {@link BaseConfigMap | `ConfigMap`} with required hash & range keys.
123
123
  *
124
124
  * @typeParam CC - {@link ConfigMap | `ConfigMap`} that defines an {@link Config | `EntityManager configuration`}'s {@link EntityMap | `EntityMap`}, key properties, and {@link TranscodeRegistry | `TranscodeRegistry`}. If omitted, defaults to {@link BaseConfigMap | `BaseConfigMap`}.
125
125
  *
126
- * @category EntityManager
126
+ * @category EntityClient
127
127
  * @protected
128
128
  */
129
- type EntityItem<CC extends BaseConfigMap> = Partial<FlattenEntityMap<CC['EntityMap']> & Record<CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'], string>> & Record<string, unknown>;
129
+ type EntityKey<CC extends BaseConfigMap> = Record<CC['HashKey'] | CC['RangeKey'], string>;
130
130
 
131
131
  /**
132
- * Database-facing record key type from a {@link BaseConfigMap | `ConfigMap`} with required hash & range keys.
132
+ * Extracts entity tokens from a {@link ConfigMap | `ConfigMap`}.
133
133
  *
134
134
  * @typeParam CC - {@link ConfigMap | `ConfigMap`} that defines an {@link Config | `EntityManager configuration`}'s {@link EntityMap | `EntityMap`}, key properties, and {@link TranscodeRegistry | `TranscodeRegistry`}. If omitted, defaults to {@link BaseConfigMap | `BaseConfigMap`}.
135
135
  *
136
- * @category EntityClient
136
+ * @category EntityManager
137
137
  * @protected
138
138
  */
139
- type EntityKey<CC extends BaseConfigMap> = Record<CC['HashKey'] | CC['RangeKey'], string>;
139
+ type EntityToken<CC extends BaseConfigMap> = Extract<keyof Exactify<CC['EntityMap']>, string>;
140
140
 
141
141
  /**
142
- * Extracts entity tokens from a {@link ConfigMap | `ConfigMap`}.
142
+ * Storage-facing partial item type from a {@link BaseConfigMap | `ConfigMap`}.
143
+ *
144
+ * Token-agnostic shape used by encoding/decoding, key updates, and
145
+ * (de)hydration services.
143
146
  *
144
147
  * @typeParam CC - {@link ConfigMap | `ConfigMap`} that defines an {@link Config | `EntityManager configuration`}'s {@link EntityMap | `EntityMap`}, key properties, and {@link TranscodeRegistry | `TranscodeRegistry`}. If omitted, defaults to {@link BaseConfigMap | `BaseConfigMap`}.
145
148
  *
146
149
  * @category EntityManager
147
- * @protected
148
150
  */
149
- type EntityToken<CC extends BaseConfigMap> = keyof Exactify<CC['EntityMap']> & string;
151
+ type StorageItem<CC extends BaseConfigMap> = Partial<FlattenEntityMap<CC['EntityMap']> & Record<CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'], string>> & Record<string, unknown>;
150
152
 
151
153
  /**
152
- * A partial {@link EntityItem | `EntityItem`} restricted to keys defined in `C`.
154
+ * A partial {@link StorageItem | `StorageItem`} restricted to keys defined in `C`.
153
155
  *
154
156
  * @typeParam CC - {@link ConfigMap | `ConfigMap`} that defines an {@link Config | `EntityManager configuration`}'s {@link EntityMap | `EntityMap`}, key properties, and {@link TranscodeRegistry | `TranscodeRegistry`}. If omitted, defaults to {@link BaseConfigMap | `BaseConfigMap`}.
155
157
  *
156
158
  * @category QueryBuilder
157
159
  * @protected
158
160
  */
159
- type PageKey<CC extends BaseConfigMap> = Pick<EntityItem<CC>, CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'] | CC['TranscodedProperties']>;
161
+ type PageKey<CC extends BaseConfigMap> = Pick<StorageItem<CC>, CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'] | CC['TranscodedProperties']>;
160
162
  /**
161
163
  * Internal helpers to safely derive index component tokens for an index IT.
162
164
  *
@@ -182,11 +184,39 @@ type IndexRangeKeyOf<CF, IT extends string> = CF extends {
182
184
  */
183
185
  type IndexTokensOf<CF> = CF extends {
184
186
  indexes?: infer I;
185
- } ? I extends Record<string, unknown> ? keyof I & string : string : string;
187
+ } ? I extends Record<string, unknown> ? Extract<keyof I, string> : string : string;
186
188
  type HasIndexFor<CF, IT extends string> = CF extends {
187
189
  indexes?: infer I;
188
190
  } ? I extends Record<string, unknown> ? IT extends keyof I ? true : false : false : false;
189
- type IndexComponentTokens<CC extends BaseConfigMap, CF, IT extends string> = HasIndexFor<CF, IT> extends true ? CC['HashKey'] | CC['RangeKey'] | IndexHashKeyOf<CF, IT> | IndexRangeKeyOf<CF, IT> : CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'] | CC['TranscodedProperties'];
191
+ /**
192
+ * Base index component tokens shared by all indexes
193
+ * (the global hashKey and rangeKey defined in the Config).
194
+ *
195
+ * @category QueryBuilder
196
+ */
197
+ type BaseKeyTokens<CC extends BaseConfigMap> = CC['HashKey'] | CC['RangeKey'];
198
+ /**
199
+ * Key set for index component tokens when CF/IT identify a concrete index.
200
+ * - Always includes base key tokens (global hash/range).
201
+ * - Conditionally includes index hashKey/rangeKey when they do not collapse
202
+ * to the base key union.
203
+ *
204
+ * @category QueryBuilder
205
+ */
206
+ type PresentIndexTokenSet<CC extends BaseConfigMap, CF, IT extends string> = Record<BaseKeyTokens<CC>, true> & {
207
+ [K in IndexHashKeyOf<CF, IT> as K extends BaseKeyTokens<CC> ? never : K]: true;
208
+ } & {
209
+ [K in IndexRangeKeyOf<CF, IT> as K extends BaseKeyTokens<CC> ? never : K]: true;
210
+ };
211
+ /**
212
+ * Key set for index component tokens when CF does not carry an `indexes` map
213
+ * or IT is unknown. Includes global keys, generated keys, and transcodable
214
+ * properties.
215
+ *
216
+ * @category QueryBuilder
217
+ */
218
+ type FallbackIndexTokenSet<CC extends BaseConfigMap> = Record<CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'] | CC['TranscodedProperties'], true>;
219
+ type IndexComponentTokens<CC extends BaseConfigMap, CF, IT extends string> = HasIndexFor<CF, IT> extends true ? keyof PresentIndexTokenSet<CC, CF, IT> : keyof FallbackIndexTokenSet<CC>;
190
220
  /**
191
221
  * Page key typed for a specific index token.
192
222
  *
@@ -194,7 +224,7 @@ type IndexComponentTokens<CC extends BaseConfigMap, CF, IT extends string> = Has
194
224
  * shape narrows to exactly the component tokens of IT.
195
225
  * - Without CF, falls back to the broad PageKey<CC> shape.
196
226
  */
197
- type PageKeyByIndex<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT extends string = string, CF = unknown> = Pick<EntityItem<CC>, IndexComponentTokens<CC, CF, IT>>;
227
+ type PageKeyByIndex<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT extends string = string, CF = unknown> = Pick<StorageItem<CC>, IndexComponentTokens<CC, CF, IT>>;
198
228
 
199
229
  declare const configSchema: z$1.ZodObject<{
200
230
  entities: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodRecord<z$1.ZodString, z$1.ZodObject<{
@@ -247,15 +277,11 @@ type ParsedConfig = z$1.infer<typeof configSchema>;
247
277
  /** EntityOfToken — resolves the concrete entity shape for a specific entity token. */
248
278
  type EntityOfToken<CC extends BaseConfigMap, ET extends EntityToken<CC>> = Exactify<CC['EntityMap']>[ET];
249
279
  /**
250
- * EntityItemByTokendatabase-facing partial item narrowed to a specific entity token.
251
- * Mirrors `EntityItem<CC>` with the entity surface restricted to `EntityOfToken<CC, ET>`.
252
- *
253
- * Note: If using createEntityManager with entitiesSchema, the schema must declare
254
- * only base (non-generated) properties. Generated keys/tokens are layered by EntityManager.
280
+ * EntityItemdomain-facing item narrowed to a specific entity token, plus
281
+ * optional key/token properties. Required fields per captured entitiesSchema
282
+ * (when present); no string index signature.
255
283
  */
256
- type EntityItemByToken<CC extends BaseConfigMap, ET extends EntityToken<CC>> = Partial<EntityOfToken<CC, ET> & Record<CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'], string>> & Record<string, unknown>;
257
- /** EntityRecordByToken — database-facing record (keys required) narrowed to a specific entity token. */
258
- type EntityRecordByToken<CC extends BaseConfigMap, ET extends EntityToken<CC>> = EntityItemByToken<CC, ET> & EntityKey<CC>;
284
+ type EntityItem<CC extends BaseConfigMap, ET extends EntityToken<CC>> = EntityOfToken<CC, ET> & Partial<Record<CC['HashKey'] | CC['RangeKey'] | CC['ShardedKeys'] | CC['UnshardedKeys'], string>>;
259
285
  /**
260
286
  * Normalize literals: string | readonly string[] -\> union of strings.
261
287
  */
@@ -264,10 +290,15 @@ type KeysFrom<K> = K extends readonly (infer E)[] ? Extract<E, string> : K exten
264
290
  * Project item shape by keys; if K is never/unknown, fall back to T.
265
291
  */
266
292
  type Projected<T, K> = [KeysFrom<K>] extends [never] ? T : T extends object ? Pick<T, Extract<KeysFrom<K>, keyof Exactify<T>>> : T;
267
- /**
268
- * Projected item by token narrows EntityItemByToken by K when provided.
269
- */
270
- type ProjectedItemByToken<CC extends BaseConfigMap, ET extends EntityToken<CC>, K = unknown> = Projected<EntityItemByToken<CC, ET>, K>;
293
+ /** EntityRecord — DB-facing record (keys required), narrowed to a specific entity token. */
294
+ type EntityRecord<CC extends BaseConfigMap, ET extends EntityToken<CC>> = Partial<EntityItem<CC, ET>> & EntityKey<CC>;
295
+ /** EntityItemPartial — projected/seed domain shape by token.
296
+ * - If K provided: required projected keys (`Projected<EntityItem<CC, ET>, K>`).
297
+ * - If K omitted: permissive seed (`Partial<EntityItem<CC, ET>>`).
298
+ */
299
+ type EntityItemPartial<CC extends BaseConfigMap, ET extends EntityToken<CC>, K = unknown> = [KeysFrom<K>] extends [never] ? Partial<EntityItem<CC, ET>> : Projected<EntityItem<CC, ET>, K>;
300
+ /** EntityRecordPartial — projected DB record shape by token. */
301
+ type EntityRecordPartial<CC extends BaseConfigMap, ET extends EntityToken<CC>, K = unknown> = Projected<EntityRecord<CC, ET>, K>;
271
302
 
272
303
  /**
273
304
  * A result returned by a {@link ShardQueryFunction | `ShardQueryFunction`} querying an individual shard.
@@ -285,7 +316,7 @@ interface ShardQueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>,
285
316
  /** The number of records returned. */
286
317
  count: number;
287
318
  /** The returned records. */
288
- items: ProjectedItemByToken<CC, ET, K>[];
319
+ items: EntityItemPartial<CC, ET, K>[];
289
320
  /** The page key for the next query on this shard. */
290
321
  pageKey?: PageKeyByIndex<CC, ET, IT, CF>;
291
322
  }
@@ -310,7 +341,7 @@ interface ShardQueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>,
310
341
  */
311
342
  type ShardQueryFunction<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT extends string, CF = unknown, K = unknown> = CF extends {
312
343
  indexes?: infer I;
313
- } ? I extends Record<string, unknown> ? IT extends keyof I & string ? (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF, K>> : never : (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF, K>> : (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF, K>>;
344
+ } ? I extends Record<string, unknown> ? IT extends Extract<keyof I, string> ? (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF, K>> : never : (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF, K>> : (hashKey: string, pageKey?: PageKeyByIndex<CC, ET, IT, CF>, pageSize?: number) => Promise<ShardQueryResult<CC, ET, IT, CF, K>>;
314
345
 
315
346
  /**
316
347
  * Relates a specific index token to a {@link ShardQueryFunction | `ShardQueryFunction`} to be performed on that index.
@@ -330,7 +361,7 @@ type ShardQueryFunction<CC extends BaseConfigMap, ET extends EntityToken<CC>, IT
330
361
  */
331
362
  type ShardQueryMap<CC extends BaseConfigMap, ET extends EntityToken<CC>, ITS extends string, CF = unknown, K = unknown> = CF extends {
332
363
  indexes?: infer I;
333
- } ? I extends Record<string, unknown> ? Record<ITS & (keyof I & string), ShardQueryFunction<CC, ET, ITS & (keyof I & string), CF, K>> : Record<ITS, ShardQueryFunction<CC, ET, ITS, CF, K>> : Record<ITS, ShardQueryFunction<CC, ET, ITS, CF, K>>;
364
+ } ? I extends Record<string, unknown> ? Record<Extract<ITS, Extract<keyof I, string>>, ShardQueryFunction<CC, ET, Extract<ITS, Extract<keyof I, string>>, CF, K>> : Record<ITS, ShardQueryFunction<CC, ET, ITS, CF, K>> : Record<ITS, ShardQueryFunction<CC, ET, ITS, CF, K>>;
334
365
  /**
335
366
  * Convenience alias for ShardQueryMap that derives ITS (index token subset)
336
367
  * from a values-first captured config CC (e.g., your config literal type).
@@ -373,7 +404,7 @@ interface QueryOptions<CC extends BaseConfigMap, ET extends EntityToken<CC> = En
373
404
  /**
374
405
  * Partial item object sufficiently populated to generate index hash keys.
375
406
  */
376
- item: EntityItemByToken<CC, ET>;
407
+ item: EntityItemPartial<CC, ET>;
377
408
  /**
378
409
  * The target maximum number of records to be returned by the query across
379
410
  * all shards.
@@ -409,7 +440,7 @@ interface QueryOptions<CC extends BaseConfigMap, ET extends EntityToken<CC> = En
409
440
  /**
410
441
  * A {@link SortOrder | `SortOrder`} object specifying the sort order of the result set. Defaults to `[]`. Aligned with the projected item shape when K is provided.
411
442
  */
412
- sortOrder?: SortOrder<ProjectedItemByToken<CC, ET, K>> | undefined;
443
+ sortOrder?: SortOrder<EntityItemPartial<CC, ET, K>> | undefined;
413
444
  /**
414
445
  * Lower limit to query shard space.
415
446
  *
@@ -476,7 +507,7 @@ interface QueryResult<CC extends BaseConfigMap, ET extends EntityToken<CC>, ITS
476
507
  /** Total number of records returned across all shards. */
477
508
  count: number;
478
509
  /** The returned records. */
479
- items: ProjectedItemByToken<CC, ET, K>[];
510
+ items: EntityItemPartial<CC, ET, K>[];
480
511
  /**
481
512
  * A compressed, two-layer map of page keys, used to query the next page of
482
513
  * data for a given sort key on each shard of a given hash key.
@@ -526,13 +557,13 @@ declare class EntityManager<CC extends BaseConfigMap, CF = unknown> {
526
557
  * Encode a generated property value. Returns a string or undefined if atomicity requirement of sharded properties not met.
527
558
  *
528
559
  * @param property - {@link Config | Config} `generatedProperties` key.
529
- * @param item - {@link EntityItem | `EntityItem`} object.
560
+ * @param item - {@link StorageItem | `StorageItem`} object.
530
561
  *
531
562
  * @returns Encoded generated property value.
532
563
  *
533
564
  * @throws `Error` if `property` is not a {@link Config | Config} `generatedProperties` key.
534
565
  */
535
- encodeGeneratedProperty(property: CC['ShardedKeys'] | CC['UnshardedKeys'], item: EntityItem<CC>): string | undefined;
566
+ encodeGeneratedProperty(property: CC['ShardedKeys'] | CC['UnshardedKeys'], item: StorageItem<CC>): string | undefined;
536
567
  /**
537
568
  * Update generated properties, hash key, and range key on an {@link EntityItem | `EntityItem`} object.
538
569
  *
@@ -546,28 +577,27 @@ declare class EntityManager<CC extends BaseConfigMap, CF = unknown> {
546
577
  *
547
578
  * @overload
548
579
  */
549
- addKeys<ET extends EntityToken<CC>>(entityToken: ET, item: EntityItemByToken<CC, ET>, overwrite?: boolean): EntityRecordByToken<CC, ET>;
580
+ addKeys<ET extends EntityToken<CC>>(entityToken: ET, item: EntityItemPartial<CC, ET>, overwrite?: boolean): EntityRecordPartial<CC, ET>;
550
581
  /**
551
582
  * @overload
552
583
  */
553
- addKeys<ET extends EntityToken<CC>>(entityToken: ET, item: EntityItemByToken<CC, ET>[], overwrite?: boolean): EntityRecordByToken<CC, ET>[];
584
+ addKeys<ET extends EntityToken<CC>>(entityToken: ET, item: EntityItemPartial<CC, ET>[], overwrite?: boolean): EntityRecordPartial<CC, ET>[];
554
585
  /**
555
586
  * Convert one or more {@link EntityItem | `EntityItem`} objects into an array of {@link EntityKey | `EntityKey`} values.
556
587
  *
557
588
  * @param entityToken - {@link Config | `Config`} `entities` key.
558
- * @param item - {@link EntityItem | `EntityItem`} object, or array of them.
589
+ * @param item - {@link EntityItem | `EntityItem`} object.
559
590
  * @param overwrite - Overwrite existing properties (default `false`).
560
591
  *
561
- * @returns An array of {@link EntityKey | `EntityKey`} values. For a single input item, returns 0..N keys (usually 1).
562
- * For an array input, returns a single flattened array of keys across all inputs.
592
+ * @returns Array of {@link EntityKey | `EntityKey`} values derived from `item`.
563
593
  *
564
594
  * @throws `Error` if `entityToken` is invalid.
565
595
  */
566
- getPrimaryKey<ET extends EntityToken<CC>>(entityToken: ET, item: EntityItemByToken<CC, ET>, overwrite?: boolean): EntityKey<CC>[];
596
+ getPrimaryKey<ET extends EntityToken<CC>>(entityToken: ET, item: EntityItemPartial<CC, ET>, overwrite?: boolean): EntityKey<CC>[];
567
597
  /**
568
598
  * @overload
569
599
  */
570
- getPrimaryKey<ET extends EntityToken<CC>>(entityToken: ET, items: EntityItemByToken<CC, ET>[], overwrite?: boolean): EntityKey<CC>[];
600
+ getPrimaryKey<ET extends EntityToken<CC>>(entityToken: ET, items: EntityItemPartial<CC, ET>[], overwrite?: boolean): EntityKey<CC>[];
571
601
  /**
572
602
  * Strips generated properties, hash key, and range key from an {@link EntityRecord | `EntityRecord`} object.
573
603
  *
@@ -578,13 +608,12 @@ declare class EntityManager<CC extends BaseConfigMap, CF = unknown> {
578
608
  *
579
609
  * @throws `Error` if `entityToken` is invalid.
580
610
  *
581
- * @overload
611
+ * Overloads:
582
612
  */
583
- removeKeys<ET extends EntityToken<CC>>(entityToken: ET, item: EntityRecordByToken<CC, ET>): EntityItemByToken<CC, ET>;
584
- /**
585
- * @overload
586
- */
587
- removeKeys<ET extends EntityToken<CC>>(entityToken: ET, items: EntityRecordByToken<CC, ET>[]): EntityItemByToken<CC, ET>[];
613
+ removeKeys<ET extends EntityToken<CC>>(entityToken: ET, item: EntityRecord<CC, ET>): EntityItem<CC, ET>;
614
+ removeKeys<ET extends EntityToken<CC>, K = unknown>(entityToken: ET, item: EntityRecordPartial<CC, ET, K>): EntityItemPartial<CC, ET, K>;
615
+ removeKeys<ET extends EntityToken<CC>>(entityToken: ET, items: EntityRecord<CC, ET>[]): EntityItem<CC, ET>[];
616
+ removeKeys<ET extends EntityToken<CC>, K = unknown>(entityToken: ET, items: EntityRecordPartial<CC, ET, K>[]): EntityItemPartial<CC, ET, K>[];
588
617
  /**
589
618
  * Find an index token based on the configured hash and range key tokens.
590
619
  *
@@ -683,7 +712,7 @@ type TranscodedPropertiesFrom<CC> = CC extends {
683
712
  type EntitiesFromSchema<CC> = CC extends {
684
713
  entitiesSchema?: infer S;
685
714
  } ? S extends Record<string, ZodType> ? {
686
- [K in keyof S & string]: z.infer<S[K]>;
715
+ [K in Extract<keyof S, string>]: z.infer<S[K]>;
687
716
  } & EntityMap : EntityMap : EntityMap;
688
717
  /**
689
718
  * Derive the union of index token names from a values-first config input.
@@ -699,7 +728,7 @@ type IndexTokensFrom<CC> = CC extends {
699
728
  * Captures a BaseConfigMap-compatible type from a literal ConfigInput value
700
729
  * and an EntityMap (defaults to MinimalEntityMapFrom<CC>).
701
730
  */
702
- type CapturedConfigMapFrom<CC, EM extends EntityMap> = {
731
+ interface CapturedConfigMapFrom<CC, EM extends EntityMap> extends BaseConfigMap {
703
732
  EntityMap: EM;
704
733
  HashKey: HashKeyFrom<CC>;
705
734
  RangeKey: RangeKeyFrom<CC>;
@@ -707,7 +736,7 @@ type CapturedConfigMapFrom<CC, EM extends EntityMap> = {
707
736
  UnshardedKeys: UnshardedKeysFrom<CC>;
708
737
  TranscodedProperties: TranscodedPropertiesFrom<CC>;
709
738
  TranscodeRegistry: DefaultTranscodeRegistry;
710
- } & BaseConfigMap;
739
+ }
711
740
  /**
712
741
  * Values-first factory that captures literal tokens and index names directly
713
742
  * from the provided config value. Runtime config parsing/validation is
@@ -725,14 +754,13 @@ type CapturedConfigMapFrom<CC, EM extends EntityMap> = {
725
754
  declare function createEntityManager<const CC extends ConfigInput, EM extends EntityMap = EntitiesFromSchema<CC>>(config: CC, logger?: Pick<Console, 'debug' | 'error'>): EntityManager<CapturedConfigMapFrom<CC, EM>, CC>;
726
755
 
727
756
  /**
728
- * Database-facing record type from a {@link BaseConfigMap | `ConfigMap`} with required hash & range keys.
757
+ * Storage-facing record type with required keys.
729
758
  *
730
759
  * @typeParam CC - {@link ConfigMap | `ConfigMap`} that defines an {@link Config | `EntityManager configuration`}'s {@link EntityMap | `EntityMap`}, key properties, and {@link TranscodeRegistry | `TranscodeRegistry`}. If omitted, defaults to {@link BaseConfigMap | `BaseConfigMap`}.
731
760
  *
732
761
  * @category EntityManager
733
- * @protected
734
762
  */
735
- type EntityRecord<CC extends BaseConfigMap> = EntityItem<CC> & EntityKey<CC>;
763
+ type StorageRecord<CC extends BaseConfigMap> = StorageItem<CC> & EntityKey<CC>;
736
764
 
737
765
  /**
738
766
  * Base EntityClient options.
@@ -777,8 +805,8 @@ declare abstract class BaseEntityClient<CC extends BaseConfigMap, CF = unknown>
777
805
  }
778
806
 
779
807
  type ConfigOfClient<EC> = EC extends BaseEntityClient<infer CC> ? CC : never;
780
- type EntityClientRecordByToken<EC, ET extends EntityToken<ConfigOfClient<EC>>> = EntityRecordByToken<ConfigOfClient<EC>, ET>;
781
- type EntityClientItemByToken<EC, ET extends EntityToken<ConfigOfClient<EC>>> = EntityItemByToken<ConfigOfClient<EC>, ET>;
808
+ type EntityClientRecordByToken<EC, ET extends EntityToken<ConfigOfClient<EC>>> = EntityRecord<ConfigOfClient<EC>, ET>;
809
+ type EntityClientItemByToken<EC, ET extends EntityToken<ConfigOfClient<EC>>> = EntityItem<ConfigOfClient<EC>, ET>;
782
810
 
783
811
  /**
784
812
  * Constructor options for {@link BaseQueryBuilder | `BaseQueryBuilder`}.
@@ -850,4 +878,4 @@ declare abstract class BaseQueryBuilder<CC extends BaseConfigMap, EntityClient e
850
878
  }
851
879
 
852
880
  export { BaseEntityClient, BaseQueryBuilder, EntityManager, configSchema, createEntityManager };
853
- export type { BaseConfigMap, BaseEntityClientOptions, BaseQueryBuilderOptions, CapturedConfigMapFrom, Config, ConfigInput, ConfigMap, ConfigOfClient, EntitiesFromSchema, EntityClientItemByToken, EntityClientRecordByToken, EntityItem, EntityItemByToken, EntityKey, EntityOfToken, EntityRecord, EntityRecordByToken, EntityToken, HasIndexFor, HashKeyFrom, IndexComponentTokens, IndexHashKeyOf, IndexRangeKeyOf, IndexTokensFrom, IndexTokensOf, KeysFrom, PageKey, PageKeyByIndex, ParsedConfig, Projected, ProjectedItemByToken, QueryBuilderQueryOptions, QueryOptions, QueryOptionsByCC, QueryOptionsByCF, QueryResult, RangeKeyFrom, ShardBump, ShardQueryFunction, ShardQueryMap, ShardQueryMapByCC, ShardQueryMapByCF, ShardQueryResult, ShardedKeysFrom, TranscodedPropertiesFrom, UnshardedKeysFrom, ValidateConfigMap };
881
+ export type { BaseConfigMap, BaseEntityClientOptions, BaseKeyTokens, BaseQueryBuilderOptions, CapturedConfigMapFrom, Config, ConfigInput, ConfigMap, ConfigOfClient, EntitiesFromSchema, EntityClientItemByToken, EntityClientRecordByToken, EntityItem, EntityItemPartial, EntityKey, EntityOfToken, EntityRecord, EntityRecordPartial, EntityToken, FallbackIndexTokenSet, HasIndexFor, HashKeyFrom, IndexComponentTokens, IndexHashKeyOf, IndexRangeKeyOf, IndexTokensFrom, IndexTokensOf, KeysFrom, PageKey, PageKeyByIndex, ParsedConfig, PresentIndexTokenSet, Projected, QueryBuilderQueryOptions, QueryOptions, QueryOptionsByCC, QueryOptionsByCF, QueryResult, RangeKeyFrom, ShardBump, ShardQueryFunction, ShardQueryMap, ShardQueryMapByCC, ShardQueryMapByCF, ShardQueryResult, ShardedKeysFrom, StorageItem, StorageRecord, TranscodedPropertiesFrom, UnshardedKeysFrom, ValidateConfigMap };
@@ -62,7 +62,7 @@ class EntityManager {
62
62
  * Encode a generated property value. Returns a string or undefined if atomicity requirement of sharded properties not met.
63
63
  *
64
64
  * @param property - {@link Config | Config} `generatedProperties` key.
65
- * @param item - {@link EntityItem | `EntityItem`} object.
65
+ * @param item - {@link StorageItem | `StorageItem`} object.
66
66
  *
67
67
  * @returns Encoded generated property value.
68
68
  *
@@ -85,9 +85,11 @@ class EntityManager {
85
85
  }
86
86
  removeKeys(entityToken, i) {
87
87
  if (Array.isArray(i)) {
88
- return i.map((item) => removeKeys(this, entityToken, item));
88
+ const out = i.map((item) => removeKeys(this, entityToken, item));
89
+ return out;
89
90
  }
90
- return removeKeys(this, entityToken, i);
91
+ const out = removeKeys(this, entityToken, i);
92
+ return out;
91
93
  }
92
94
  findIndexToken(hashKeyToken, rangeKeyToken, suppressError) {
93
95
  // Dispatch with a literal to satisfy overload selection.
@@ -118,7 +120,8 @@ class EntityManager {
118
120
  * @protected
119
121
  */
120
122
  async query(options) {
121
- return await query(this, options);
123
+ const result = await query(this, options);
124
+ return result;
122
125
  }
123
126
  }
124
127
  _EntityManager_config = new WeakMap();
@@ -6,7 +6,7 @@ import { validateGeneratedProperty } from './validateGeneratedProperty.js';
6
6
  *
7
7
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
8
8
  * @param property - {@link Config.generatedProperties | Generated property} key.
9
- * @param item - {@link EntityItem | `EntityItem`} object.
9
+ * @param item - {@link StorageItem | `StorageItem`} object.
10
10
  *
11
11
  * @returns Encoded generated property value.
12
12
  *
@@ -19,7 +19,10 @@ function encodeGeneratedProperty(entityManager, property, item) {
19
19
  const sharded = property in entityManager.config.generatedProperties.sharded;
20
20
  const elements = entityManager.config.generatedProperties[sharded ? 'sharded' : 'unsharded'][property];
21
21
  // Map elements to [element, value] pairs.
22
- const elementMap = elements.map((element) => [element, item[element]]);
22
+ const elementMap = elements.map((element) => [
23
+ element,
24
+ item[element],
25
+ ]);
23
26
  // Return undefined if sharded & atomicity requirement fails.
24
27
  if (sharded && elementMap.some(([, value]) => isNil(value)))
25
28
  return;
@@ -50,7 +50,7 @@ function getHashKeySpace(entityManager, entityToken, hashKeyToken, item, timesta
50
50
  // Map shard keys to hash keys.
51
51
  .map((shardKey) => {
52
52
  // Calculate record hash key.
53
- let hashKey = `${entityToken}${entityManager.config.shardKeyDelimiter}${shardKey}`;
53
+ let hashKey = `${String(entityToken)}${entityManager.config.shardKeyDelimiter}${shardKey}`;
54
54
  // If hash key space basis is a different property, encode it.
55
55
  if (hashKeyToken !== entityManager.config.hashKey)
56
56
  hashKey = encodeGeneratedProperty(entityManager, hashKeyToken, {
@@ -25,11 +25,14 @@ import { updateItemRangeKey } from './updateItemRangeKey.js';
25
25
  function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
26
26
  const { hashKey, rangeKey } = entityManager.config;
27
27
  // If both keys are present and we're not overwriting, return the exact pair.
28
- if (!overwrite && item[hashKey] && item[rangeKey]) {
28
+ const rec = item;
29
+ const hk = hashKey;
30
+ const rk = rangeKey;
31
+ if (!overwrite && rec[hk] && rec[rk]) {
29
32
  return [
30
33
  {
31
- [hashKey]: item[hashKey],
32
- [rangeKey]: item[rangeKey],
34
+ [hashKey]: rec[hk],
35
+ [rangeKey]: rec[rk],
33
36
  },
34
37
  ];
35
38
  }
@@ -38,6 +41,7 @@ function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
38
41
  // If timestamp present, compute exactly one hash key and return single pair.
39
42
  const tsProp = entityManager.config.entities[entityToken].timestampProperty;
40
43
  if (withRangeKey[tsProp] !== undefined) {
44
+ // Note: use StorageItem here
41
45
  const withHashKey = updateItemHashKey(entityManager, entityToken, withRangeKey, true);
42
46
  return [
43
47
  {
@@ -49,12 +53,15 @@ function getPrimaryKey(entityManager, entityToken, item, overwrite = false) {
49
53
  // No timestamp: enumerate hash-key space across all shard bumps (0..Infinity).
50
54
  const hashKeys = getHashKeySpace(entityManager, entityToken, hashKey, withRangeKey, 0, Infinity);
51
55
  // Map to keys and de-duplicate.
52
- const rk = withRangeKey[rangeKey];
56
+ const rangeKeyValue = withRangeKey[rangeKey];
53
57
  const seen = new Set();
54
58
  const keys = hashKeys
55
59
  .map((hk) => {
56
- const key = { [hashKey]: hk, [rangeKey]: rk };
57
- const sig = `${hk}|${rk}`;
60
+ const key = {
61
+ [hashKey]: hk,
62
+ [rangeKey]: rangeKeyValue,
63
+ };
64
+ const sig = `${hk}|${rangeKeyValue}`;
58
65
  if (seen.has(sig))
59
66
  return undefined;
60
67
  seen.add(sig);
@@ -23,14 +23,21 @@ function removeKeys(entityManager, entityToken, item) {
23
23
  ...Object.keys(sharded),
24
24
  ...Object.keys(unsharded),
25
25
  ]);
26
- // Create a shallow copy of item omitting the keys above (no delete operator).
27
- const newItem = Object.fromEntries(Object.entries(item).filter(([key]) => !keysToStrip.has(key)));
26
+ // Create a shallow copy of item omitting the keys above (no delete operator),
27
+ // avoiding any-typed assignments.
28
+ const source = item;
29
+ const newItemObj = {};
30
+ for (const [key, value] of Object.entries(source)) {
31
+ if (!keysToStrip.has(key)) {
32
+ newItemObj[key] = value;
33
+ }
34
+ }
28
35
  entityManager.logger.debug('stripped entity item generated properties', {
29
36
  entityToken,
30
37
  item,
31
- newItem,
38
+ newItem: newItemObj,
32
39
  });
33
- return newItem;
40
+ return newItemObj;
34
41
  }
35
42
  catch (error) {
36
43
  if (error instanceof Error)
@@ -4,11 +4,11 @@ import { getShardBump } from './getShardBump.js';
4
4
  import { validateEntityToken } from './validateEntityToken.js';
5
5
 
6
6
  /**
7
- * Update the hash key on an partial {@link EntityItem | `EntityItem`} object.
7
+ * Update the hash key on an {@link EntityItemPartial | `EntityItemPartial`} object.
8
8
  *
9
9
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
10
10
  * @param entityToken - {@link Config.entities | `this.config.entities`} key.
11
- * @param item - {@link EntityItem | `EntityItem`} object.
11
+ * @param item - {@link StorageItem | `StorageItem`} object.
12
12
  * @param overwrite - Overwrite existing {@link ConfigKeys.hashKey | `this.config.hashKey`} property value (default `false`).
13
13
  *
14
14
  * @returns Shallow clone of `item` with updated hash key.
@@ -30,13 +30,14 @@ function updateItemHashKey(entityManager, entityToken, item, overwrite = false)
30
30
  return { ...item };
31
31
  }
32
32
  // Get item timestamp property & validate.
33
- const timestamp = item[entityManager.config.entities[entityToken]
34
- .timestampProperty];
33
+ const tsProp = entityManager.config.entities[entityToken]
34
+ .timestampProperty;
35
+ const timestamp = item[tsProp];
35
36
  if (isNil(timestamp))
36
37
  throw new Error(`missing item timestamp property`);
37
38
  // Find first entity sharding bump before timestamp.
38
39
  const { charBits, chars } = getShardBump(entityManager, entityToken, timestamp);
39
- let hashKey = `${entityToken}${entityManager.config.shardKeyDelimiter}`;
40
+ let hashKey = `${String(entityToken)}${entityManager.config.shardKeyDelimiter}`;
40
41
  if (chars) {
41
42
  // Radix is the numerical base of the shardKey.
42
43
  const radix = 2 ** charBits;
@@ -44,8 +45,9 @@ function updateItemHashKey(entityManager, entityToken, item, overwrite = false)
44
45
  // all placeholders are utilized (e.g., chars=2, charBits=2 => 16 combos).
45
46
  const space = radix ** chars;
46
47
  // Get item unique property & validate.
47
- const uniqueId = item[entityManager.config.entities[entityToken]
48
- .uniqueProperty];
48
+ const upProp = entityManager.config.entities[entityToken]
49
+ .uniqueProperty;
50
+ const uniqueId = item[upProp];
49
51
  if (isNil(uniqueId))
50
52
  throw new Error(`missing item unique property`);
51
53
  hashKey += (stringHash(uniqueId) % space)
@@ -2,11 +2,11 @@ import { isNil } from '@karmaniverous/entity-tools';
2
2
  import { validateEntityToken } from './validateEntityToken.js';
3
3
 
4
4
  /**
5
- * Update the range key on an {@link EntityItem | `EntityItem`} object.
5
+ * Update the range key on an {@link EntityItemPartial | `EntityItemPartial`} object.
6
6
  *
7
7
  * @param entityManager - {@link EntityManager | `EntityManager`} instance.
8
8
  * @param entityToken - {@link Config.entities | `this.config.entities`} key.
9
- * @param item - {@link EntityItem | `EntityItem`} object.
9
+ * @param item - {@link StorageItem | `StorageItem`} object.
10
10
  * @param overwrite - Overwrite existing {@link ConfigKeys.rangeKey | `this.config.rangeKey`} property value (default `false`).
11
11
  *
12
12
  * @returns Shallow clone of `item` with updated range key.
@@ -19,8 +19,8 @@ function updateItemRangeKey(entityManager, entityToken, item, overwrite = false)
19
19
  // Validate params.
20
20
  validateEntityToken(entityManager, entityToken);
21
21
  // Return current item if rangeKey exists and overwrite is false.
22
- if (item[entityManager.config.rangeKey] &&
23
- !overwrite) {
22
+ const rkProp = entityManager.config.rangeKey;
23
+ if (item[rkProp] && !overwrite) {
24
24
  entityManager.logger.debug('did not overwrite existing entity item range key', {
25
25
  entityToken,
26
26
  item,
@@ -29,15 +29,16 @@ function updateItemRangeKey(entityManager, entityToken, item, overwrite = false)
29
29
  return { ...item };
30
30
  }
31
31
  // Get item unique property & validate.
32
- const uniqueProperty = item[entityManager.config.entities[entityToken]
33
- .uniqueProperty];
34
- if (isNil(uniqueProperty))
32
+ const upProp = entityManager.config.entities[entityToken]
33
+ .uniqueProperty;
34
+ const uniqueValue = item[upProp];
35
+ if (isNil(uniqueValue))
35
36
  throw new Error(`missing item unique property`);
36
37
  // Update range key.
37
38
  const newItem = Object.assign({ ...item }, {
38
39
  [entityManager.config.rangeKey]: [
39
40
  entityManager.config.entities[entityToken].uniqueProperty,
40
- uniqueProperty,
41
+ uniqueValue,
41
42
  ].join(entityManager.config.generatedValueDelimiter),
42
43
  });
43
44
  entityManager.logger.debug('updated entity item range key', {
package/package.json CHANGED
@@ -11,12 +11,12 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@karmaniverous/batch-process": "^0.1.0",
14
- "@karmaniverous/entity-tools": "^0.7.1",
15
- "@karmaniverous/string-utilities": "^0.2.1",
14
+ "@karmaniverous/entity-tools": "^0.8.0",
15
+ "@karmaniverous/string-utilities": "^0.2.2",
16
16
  "lz-string": "^1.5.0",
17
17
  "radash": "^12.1.1",
18
18
  "string-hash": "^1.1.3",
19
- "zod": "^4.1.12"
19
+ "zod": "^4.1.13"
20
20
  },
21
21
  "description": "Rational indexing & cross-shard querying at scale in your NoSQL database so you can focus on your application logic.",
22
22
  "devDependencies": {
@@ -39,24 +39,24 @@
39
39
  "eslint-plugin-prettier": "^5.5.4",
40
40
  "eslint-plugin-simple-import-sort": "^12.1.1",
41
41
  "eslint-plugin-tsdoc": "^0.5.0",
42
- "knip": "^5.69.1",
42
+ "knip": "^5.70.2",
43
43
  "lefthook": "^2.0.4",
44
- "prettier": "^3.6.2",
44
+ "prettier": "^3.7.3",
45
45
  "release-it": "^19.0.6",
46
- "rimraf": "^6.1.0",
47
- "rollup": "^4.53.2",
48
- "rollup-plugin-dts": "^6.2.3",
46
+ "rimraf": "^6.1.2",
47
+ "rollup": "^4.53.3",
48
+ "rollup-plugin-dts": "^6.3.0",
49
49
  "tsd": "^0.33.0",
50
50
  "tslib": "^2.8.1",
51
- "typedoc": "^0.28.14",
51
+ "typedoc": "^0.28.15",
52
52
  "typedoc-plugin-mdn-links": "^5.0.10",
53
53
  "typedoc-plugin-replace-text": "^4.2.0",
54
54
  "typedoc-plugin-zod": "^1.4.3",
55
- "@vitest/coverage-v8": "^4.0.9",
56
- "@vitest/eslint-plugin": "^1.4.3",
57
- "vitest": "^4.0.9",
55
+ "@vitest/coverage-v8": "^4.0.14",
56
+ "@vitest/eslint-plugin": "^1.5.1",
57
+ "vitest": "^4.0.14",
58
58
  "typescript": "^5.9.3",
59
- "typescript-eslint": "^8.46.4"
59
+ "typescript-eslint": "^8.48.0"
60
60
  },
61
61
  "exports": {
62
62
  ".": {
@@ -134,5 +134,5 @@
134
134
  },
135
135
  "type": "module",
136
136
  "types": "dist/index.d.ts",
137
- "version": "7.3.4"
137
+ "version": "8.0.0"
138
138
  }