@frogfish/k2db 3.0.7 → 3.0.8

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.
Files changed (3) hide show
  1. package/db.d.ts +1 -1
  2. package/db.js +24 -10
  3. package/package.json +1 -1
package/db.d.ts CHANGED
@@ -288,7 +288,7 @@ export declare class K2DB {
288
288
  private static normalizeCriteriaIds;
289
289
  /** Uppercase helper for `_uuid` field supporting operators like $in/$nin/$eq/$ne and arrays. */
290
290
  private static normalizeUuidField;
291
- /** Lowercase helper for `_owner` field supporting operators like $in/$nin/$eq/$ne and arrays. */
291
+ /** Trim helper for `_owner` field supporting operators like $in/$nin/$eq/$ne and arrays. */
292
292
  private static normalizeOwnerField;
293
293
  /** Strip any user-provided fields that start with '_' (reserved). */
294
294
  private static stripReservedFields;
package/db.js CHANGED
@@ -398,7 +398,9 @@ export class K2DB {
398
398
  return undefined;
399
399
  if (s === "*")
400
400
  return "*";
401
- return s.toLowerCase();
401
+ // Scope maps to `_owner` (usually another record's `_uuid`), which is case-sensitive.
402
+ // Our `_uuid` is UUIDv7 Crockford Base32 (uppercase), so normalize to that form.
403
+ return K2DB.normalizeId(s);
402
404
  }
403
405
  /**
404
406
  * Apply a scope constraint to criteria for ownership enforcement.
@@ -418,8 +420,13 @@ export class K2DB {
418
420
  // If caller already provided _owner in criteria, ensure it matches the scope to avoid ambiguity/bypass.
419
421
  if (criteria && typeof criteria === "object" && Object.prototype.hasOwnProperty.call(criteria, "_owner")) {
420
422
  const existing = criteria._owner;
421
- if (typeof existing === "string" && existing.trim().toLowerCase() !== normalizedScope) {
422
- throw new K2Error(ServiceError.BAD_REQUEST, "Conflicting _owner in criteria and provided scope", "sys_mdb_scope_conflict");
423
+ if (typeof existing === "string") {
424
+ const ex = existing.trim();
425
+ // Treat any explicit "*" as mismatched here (caller should omit _owner or set scope="*").
426
+ const existingNorm = ex === "*" ? "*" : K2DB.normalizeId(ex);
427
+ if (existingNorm !== normalizedScope) {
428
+ throw new K2Error(ServiceError.BAD_REQUEST, "Conflicting _owner in criteria and provided scope", "sys_mdb_scope_conflict");
429
+ }
423
430
  }
424
431
  // If it matches (or is non-string), prefer the explicit scope value.
425
432
  }
@@ -1412,13 +1419,15 @@ export class K2DB {
1412
1419
  if (typeof owner !== "string") {
1413
1420
  throw new K2Error(ServiceError.BAD_REQUEST, "Owner must be of a string type", "sys_mdb_crv2");
1414
1421
  }
1415
- const normalizedOwner = owner.trim().toLowerCase();
1416
- if (!normalizedOwner) {
1422
+ const ownerTrimmed = owner.trim();
1423
+ if (!ownerTrimmed) {
1417
1424
  throw new K2Error(ServiceError.BAD_REQUEST, "Owner must be a non-empty string", "sys_mdb_owner_empty");
1418
1425
  }
1419
- if (normalizedOwner === "*") {
1426
+ if (ownerTrimmed === "*") {
1420
1427
  throw new K2Error(ServiceError.BAD_REQUEST, "Owner cannot be '*'", "sys_mdb_owner_star");
1421
1428
  }
1429
+ // `_owner` is typically another record's `_uuid` (case-sensitive). Normalize to the canonical ID form.
1430
+ const normalizedOwner = K2DB.normalizeId(ownerTrimmed);
1422
1431
  const collection = await this.getCollection(collectionName);
1423
1432
  const timestamp = Date.now();
1424
1433
  // Generate a new UUIDv7 encoded as Crockford Base32 with hyphens
@@ -1560,6 +1569,11 @@ export class K2DB {
1560
1569
  }, {});
1561
1570
  // Merge the preserved fields into the data
1562
1571
  data = { ...data, ...fieldsToPreserve };
1572
+ // Update _owner if scope is provided
1573
+ const normalizedScope = this.normalizeScope(scope);
1574
+ if (normalizedScope) {
1575
+ data._owner = normalizedScope;
1576
+ }
1563
1577
  data._updated = Date.now();
1564
1578
  // Encrypt secure-prefixed fields at rest (no-op unless encryption is configured)
1565
1579
  data = this.encryptSecureFieldsDeep(data, `k2db|${collectionName}|${id}`);
@@ -1936,12 +1950,12 @@ export class K2DB {
1936
1950
  }
1937
1951
  return val;
1938
1952
  }
1939
- /** Lowercase helper for `_owner` field supporting operators like $in/$nin/$eq/$ne and arrays. */
1953
+ /** Trim helper for `_owner` field supporting operators like $in/$nin/$eq/$ne and arrays. */
1940
1954
  static normalizeOwnerField(val) {
1941
1955
  if (typeof val === "string")
1942
- return val.trim().toLowerCase();
1956
+ return val.trim();
1943
1957
  if (Array.isArray(val)) {
1944
- return val.map((x) => (typeof x === "string" ? x.trim().toLowerCase() : x));
1958
+ return val.map((x) => (typeof x === "string" ? x.trim() : x));
1945
1959
  }
1946
1960
  if (val && typeof val === "object") {
1947
1961
  const out = { ...val };
@@ -1972,7 +1986,7 @@ export class K2DB {
1972
1986
  }
1973
1987
  /** Uppercase incoming IDs for case-insensitive lookups. */
1974
1988
  static normalizeId(id) {
1975
- return id.toUpperCase();
1989
+ return id.trim();
1976
1990
  }
1977
1991
  /**
1978
1992
  * Run an async DB operation with timing, slow logging, and hooks.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frogfish/k2db",
3
- "version": "3.0.7",
3
+ "version": "3.0.8",
4
4
  "description": "A data handling library for K2 applications.",
5
5
  "type": "module",
6
6
  "main": "data.js",