@memberjunction/global 6.2.0-edge.3 → 6.2.0-edge.5

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 (60) hide show
  1. package/dist/ClassFactory.d.ts +16 -3
  2. package/dist/ClassFactory.d.ts.map +1 -1
  3. package/dist/ClassFactory.js +112 -48
  4. package/dist/ClassFactory.js.map +1 -1
  5. package/dist/DeepDiff.d.ts +2 -0
  6. package/dist/DeepDiff.d.ts.map +1 -1
  7. package/dist/DeepDiff.js +40 -38
  8. package/dist/DeepDiff.js.map +1 -1
  9. package/dist/ObjectCache.d.ts +1 -0
  10. package/dist/ObjectCache.d.ts.map +1 -1
  11. package/dist/ObjectCache.js +14 -22
  12. package/dist/ObjectCache.js.map +1 -1
  13. package/dist/SQLExpressionValidator.d.ts +36 -32
  14. package/dist/SQLExpressionValidator.d.ts.map +1 -1
  15. package/dist/SQLExpressionValidator.js +125 -117
  16. package/dist/SQLExpressionValidator.js.map +1 -1
  17. package/dist/SQLScreeningScanner.d.ts +91 -0
  18. package/dist/SQLScreeningScanner.d.ts.map +1 -0
  19. package/dist/SQLScreeningScanner.js +332 -0
  20. package/dist/SQLScreeningScanner.js.map +1 -0
  21. package/dist/__tests__/SQLExpressionValidator.security.test.js +176 -2
  22. package/dist/__tests__/SQLExpressionValidator.security.test.js.map +1 -1
  23. package/dist/__tests__/SQLScreeningScanner.test.d.ts +2 -0
  24. package/dist/__tests__/SQLScreeningScanner.test.d.ts.map +1 -0
  25. package/dist/__tests__/SQLScreeningScanner.test.js +172 -0
  26. package/dist/__tests__/SQLScreeningScanner.test.js.map +1 -0
  27. package/dist/__tests__/UUIDCollections.test.d.ts +2 -0
  28. package/dist/__tests__/UUIDCollections.test.d.ts.map +1 -0
  29. package/dist/__tests__/UUIDCollections.test.js +173 -0
  30. package/dist/__tests__/UUIDCollections.test.js.map +1 -0
  31. package/dist/__tests__/UUIDCompliance.test.d.ts +2 -1
  32. package/dist/__tests__/UUIDCompliance.test.d.ts.map +1 -1
  33. package/dist/__tests__/UUIDCompliance.test.js +290 -8
  34. package/dist/__tests__/UUIDCompliance.test.js.map +1 -1
  35. package/dist/__tests__/UUIDUtils.test.js +55 -0
  36. package/dist/__tests__/UUIDUtils.test.js.map +1 -1
  37. package/dist/__tests__/util.trimTrailingSlashes.test.d.ts +2 -0
  38. package/dist/__tests__/util.trimTrailingSlashes.test.d.ts.map +1 -0
  39. package/dist/__tests__/util.trimTrailingSlashes.test.js +23 -0
  40. package/dist/__tests__/util.trimTrailingSlashes.test.js.map +1 -0
  41. package/dist/__tests__/util.valuesEqual.test.d.ts +2 -0
  42. package/dist/__tests__/util.valuesEqual.test.d.ts.map +1 -0
  43. package/dist/__tests__/util.valuesEqual.test.js +37 -0
  44. package/dist/__tests__/util.valuesEqual.test.js.map +1 -0
  45. package/dist/index.d.ts +2 -0
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +2 -0
  48. package/dist/index.js.map +1 -1
  49. package/dist/util/UUIDCollections.d.ts +111 -0
  50. package/dist/util/UUIDCollections.d.ts.map +1 -0
  51. package/dist/util/UUIDCollections.js +163 -0
  52. package/dist/util/UUIDCollections.js.map +1 -0
  53. package/dist/util/UUIDUtils.d.ts.map +1 -1
  54. package/dist/util/UUIDUtils.js +58 -3
  55. package/dist/util/UUIDUtils.js.map +1 -1
  56. package/dist/util.d.ts +39 -0
  57. package/dist/util.d.ts.map +1 -1
  58. package/dist/util.js +58 -0
  59. package/dist/util.js.map +1 -1
  60. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ export * from './ClassUtils.js';
12
12
  export * from './util/PatternUtils.js';
13
13
  export * from './util/ResourcePatternUtils.js';
14
14
  export * from './util/UUIDUtils.js';
15
+ export * from './util/UUIDCollections.js';
15
16
  export * from './util/CronUtils.js';
16
17
  export * from './util/SerializationUtils.js';
17
18
  export * from './util/BinaryEncoding.js';
@@ -19,6 +20,7 @@ export * from './ValidationTypes.js';
19
20
  export * from './JSONValidator.js';
20
21
  export * from './SafeExpressionEvaluator.js';
21
22
  export * from './fieldRules/index.js';
23
+ export * from './SQLScreeningScanner.js';
22
24
  export * from './SQLExpressionValidator.js';
23
25
  export * from './warningManager.js';
24
26
  export * from './EncryptionUtils.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AACzC,cAAc,cAAc,CAAA;AAC5B,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,wBAAwB,CAAA;AACtC,cAAc,wBAAwB,CAAA;AAEtC,2DAA2D;AAC3D,oCAAoC;AAEpC,0BAA0B;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,+BAA+B,CAAA;AAE7C,6DAA6D;AAC7D,oCAAoC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AACzC,cAAc,cAAc,CAAA;AAC5B,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,wBAAwB,CAAA;AACtC,cAAc,wBAAwB,CAAA;AAEtC,2DAA2D;AAC3D,oCAAoC;AAEpC,0BAA0B;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,+BAA+B,CAAA;AAE7C,6DAA6D;AAC7D,oCAAoC"}
@@ -0,0 +1,111 @@
1
+ /** A UUID as it arrives from data: possibly upper-case, padded, or missing. */
2
+ export type UUIDInput = string | null | undefined;
3
+ /** Reads the UUID used to match an item. */
4
+ export type UUIDSelector<T> = (item: T) => UUIDInput;
5
+ /**
6
+ * A `Set` of UUIDs that matches case- and whitespace-insensitively. Every ID is normalized on
7
+ * insert and on lookup, so `Has('A1B2…')` finds an ID added as `'a1b2…'`. Iterates normalized IDs.
8
+ *
9
+ * @example
10
+ * const selected = new UUIDSet(selectedIds);
11
+ * const picked = rows.filter(r => selected.Has(r.ID));
12
+ */
13
+ export declare class UUIDSet implements Iterable<string> {
14
+ private readonly ids;
15
+ constructor(ids?: Iterable<UUIDInput>);
16
+ /** Adds an ID. Returns this set, for chaining. */
17
+ Add(id: UUIDInput): this;
18
+ /** True when the ID is in the set, ignoring case and surrounding whitespace. */
19
+ Has(id: UUIDInput): boolean;
20
+ /** Removes an ID. Returns true when it was present. */
21
+ Delete(id: UUIDInput): boolean;
22
+ Clear(): void;
23
+ /** Number of distinct IDs (case variants of one ID count once). */
24
+ get Size(): number;
25
+ [Symbol.iterator](): Iterator<string>;
26
+ }
27
+ /**
28
+ * A `Map` keyed by UUID that matches case- and whitespace-insensitively. Every key is normalized
29
+ * on insert and on lookup, so a value stored under `'a1b2…'` is found with `Get('A1B2…')`.
30
+ * Iterates `[normalizedKey, value]` pairs.
31
+ *
32
+ * @example
33
+ * const roleNames = new UUIDMap(roles.map(r => [r.ID, r.Name]));
34
+ * const name = roleNames.Get(permission.RoleID);
35
+ */
36
+ export declare class UUIDMap<V> implements Iterable<[string, V]> {
37
+ private readonly entries;
38
+ constructor(entries?: Iterable<readonly [UUIDInput, V]>);
39
+ /** The value stored for the ID, or undefined. */
40
+ Get(id: UUIDInput): V | undefined;
41
+ /** Stores a value for the ID, replacing any value stored under a case variant of it. */
42
+ Set(id: UUIDInput, value: V): this;
43
+ Has(id: UUIDInput): boolean;
44
+ Delete(id: UUIDInput): boolean;
45
+ Clear(): void;
46
+ get Size(): number;
47
+ /** Normalized keys. */
48
+ Keys(): IterableIterator<string>;
49
+ Values(): IterableIterator<V>;
50
+ [Symbol.iterator](): Iterator<[string, V]>;
51
+ }
52
+ /**
53
+ * The items whose ID appears in `ids`, in `items` order. Linear: builds one {@link UUIDSet}
54
+ * (or reuses the one passed) instead of scanning `ids` once per item.
55
+ *
56
+ * @example
57
+ * const moved = FilterByUUIDs(this.Dashboards, droppedIds);
58
+ * const pending = FilterByUUIDs(artifacts, loadedIds, a => a.artifactId);
59
+ */
60
+ export declare function FilterByUUIDs<T extends {
61
+ ID: UUIDInput;
62
+ }>(items: readonly T[], ids: Iterable<UUIDInput> | UUIDSet): T[];
63
+ export declare function FilterByUUIDs<T>(items: readonly T[], ids: Iterable<UUIDInput> | UUIDSet, getId: UUIDSelector<T>): T[];
64
+ /**
65
+ * The items whose ID does NOT appear in `ids`, in `items` order. The complement of
66
+ * {@link FilterByUUIDs}, with the same linear cost.
67
+ *
68
+ * @example
69
+ * const withoutPermission = ExcludeByUUIDs(roles, existingPermissions.map(p => p.RoleID));
70
+ */
71
+ export declare function ExcludeByUUIDs<T extends {
72
+ ID: UUIDInput;
73
+ }>(items: readonly T[], ids: Iterable<UUIDInput> | UUIDSet): T[];
74
+ export declare function ExcludeByUUIDs<T>(items: readonly T[], ids: Iterable<UUIDInput> | UUIDSet, getId: UUIDSelector<T>): T[];
75
+ /**
76
+ * How many items share each ID. Look a count up with `.Get(id) ?? 0`; any casing works.
77
+ *
78
+ * @example
79
+ * const perEntity = CountByUUID(relationships, r => r.RelatedEntityID);
80
+ * const shared = (perEntity.Get(rel.RelatedEntityID) ?? 0) > 1;
81
+ */
82
+ export declare function CountByUUID<T extends {
83
+ ID: UUIDInput;
84
+ }>(items: Iterable<T>): UUIDMap<number>;
85
+ export declare function CountByUUID<T>(items: Iterable<T>, getId: UUIDSelector<T>): UUIDMap<number>;
86
+ /**
87
+ * The items grouped by ID, each group in `items` order. Look a group up with `.Get(id) ?? []`;
88
+ * any casing works. Linear, where `items.filter(x => UUIDsEqual(x.ParentID, id))` run once per
89
+ * `id` scans the whole list every time.
90
+ *
91
+ * @example
92
+ * const rolesByUser = GroupByUUID(userRoles, r => r.UserID);
93
+ * const roles = rolesByUser.Get(user.ID) ?? [];
94
+ */
95
+ export declare function GroupByUUID<T extends {
96
+ ID: UUIDInput;
97
+ }>(items: Iterable<T>): UUIDMap<T[]>;
98
+ export declare function GroupByUUID<T>(items: Iterable<T>, getId: UUIDSelector<T>): UUIDMap<T[]>;
99
+ /**
100
+ * The items keyed by ID, for repeated lookups. When two items share an ID, the FIRST one wins —
101
+ * the same answer `items.find(x => UUIDsEqual(x.ID, id))` would give.
102
+ *
103
+ * @example
104
+ * const usersByID = IndexByUUID(this.users);
105
+ * const owner = usersByID.Get(record.OwnerID);
106
+ */
107
+ export declare function IndexByUUID<T extends {
108
+ ID: UUIDInput;
109
+ }>(items: Iterable<T>): UUIDMap<T>;
110
+ export declare function IndexByUUID<T>(items: Iterable<T>, getId: UUIDSelector<T>): UUIDMap<T>;
111
+ //# sourceMappingURL=UUIDCollections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UUIDCollections.d.ts","sourceRoot":"","sources":["../../src/util/UUIDCollections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * @fileoverview UUID-keyed collections and set-based helpers for MemberJunction
3
+ *
4
+ * `UUIDsEqual` compares two IDs, so code that matches one list of records against another list of
5
+ * IDs tends to be written as a nested scan — for every item, `.some(id => UUIDsEqual(...))` over the
6
+ * other list. That is O(n x m), and every mismatched comparison lowercases both strings.
7
+ *
8
+ * The collections here normalize on every insert and every lookup (via {@link NormalizeUUID}), so
9
+ * they can be used exactly like a native `Set` / `Map` without anyone having to remember to
10
+ * normalize both sides. The helpers cover the five operations those nested scans actually perform:
11
+ * keep matches, drop matches, count per ID, group per ID, and look up by ID.
12
+ *
13
+ * Normalization follows `NormalizeUUID` exactly, including its handling of `null` / `undefined`
14
+ * (both normalize to `''`).
15
+ *
16
+ * @module @memberjunction/global/UUIDCollections
17
+ */
18
+ import { NormalizeUUID } from './UUIDUtils.js';
19
+ /**
20
+ * A `Set` of UUIDs that matches case- and whitespace-insensitively. Every ID is normalized on
21
+ * insert and on lookup, so `Has('A1B2…')` finds an ID added as `'a1b2…'`. Iterates normalized IDs.
22
+ *
23
+ * @example
24
+ * const selected = new UUIDSet(selectedIds);
25
+ * const picked = rows.filter(r => selected.Has(r.ID));
26
+ */
27
+ export class UUIDSet {
28
+ constructor(ids) {
29
+ this.ids = new Set();
30
+ if (ids) {
31
+ for (const id of ids)
32
+ this.ids.add(NormalizeUUID(id));
33
+ }
34
+ }
35
+ /** Adds an ID. Returns this set, for chaining. */
36
+ Add(id) {
37
+ this.ids.add(NormalizeUUID(id));
38
+ return this;
39
+ }
40
+ /** True when the ID is in the set, ignoring case and surrounding whitespace. */
41
+ Has(id) {
42
+ return this.ids.has(NormalizeUUID(id));
43
+ }
44
+ /** Removes an ID. Returns true when it was present. */
45
+ Delete(id) {
46
+ return this.ids.delete(NormalizeUUID(id));
47
+ }
48
+ Clear() {
49
+ this.ids.clear();
50
+ }
51
+ /** Number of distinct IDs (case variants of one ID count once). */
52
+ get Size() {
53
+ return this.ids.size;
54
+ }
55
+ [Symbol.iterator]() {
56
+ return this.ids.values();
57
+ }
58
+ }
59
+ /**
60
+ * A `Map` keyed by UUID that matches case- and whitespace-insensitively. Every key is normalized
61
+ * on insert and on lookup, so a value stored under `'a1b2…'` is found with `Get('A1B2…')`.
62
+ * Iterates `[normalizedKey, value]` pairs.
63
+ *
64
+ * @example
65
+ * const roleNames = new UUIDMap(roles.map(r => [r.ID, r.Name]));
66
+ * const name = roleNames.Get(permission.RoleID);
67
+ */
68
+ export class UUIDMap {
69
+ constructor(entries) {
70
+ this.entries = new Map();
71
+ if (entries) {
72
+ for (const [id, value] of entries)
73
+ this.entries.set(NormalizeUUID(id), value);
74
+ }
75
+ }
76
+ /** The value stored for the ID, or undefined. */
77
+ Get(id) {
78
+ return this.entries.get(NormalizeUUID(id));
79
+ }
80
+ /** Stores a value for the ID, replacing any value stored under a case variant of it. */
81
+ Set(id, value) {
82
+ this.entries.set(NormalizeUUID(id), value);
83
+ return this;
84
+ }
85
+ Has(id) {
86
+ return this.entries.has(NormalizeUUID(id));
87
+ }
88
+ Delete(id) {
89
+ return this.entries.delete(NormalizeUUID(id));
90
+ }
91
+ Clear() {
92
+ this.entries.clear();
93
+ }
94
+ get Size() {
95
+ return this.entries.size;
96
+ }
97
+ /** Normalized keys. */
98
+ Keys() {
99
+ return this.entries.keys();
100
+ }
101
+ Values() {
102
+ return this.entries.values();
103
+ }
104
+ [Symbol.iterator]() {
105
+ return this.entries.entries();
106
+ }
107
+ }
108
+ /**
109
+ * The default selector: an item's `ID`. The overloads guarantee callers that omit `getId` pass items
110
+ * with an `ID`; this narrows instead of casting, so anything else reads as "no ID" rather than crashing.
111
+ */
112
+ function readID(item) {
113
+ if (typeof item !== 'object' || item === null || !('ID' in item))
114
+ return undefined;
115
+ const id = item.ID;
116
+ return typeof id === 'string' ? id : undefined;
117
+ }
118
+ function asUUIDSet(ids) {
119
+ return ids instanceof UUIDSet ? ids : new UUIDSet(ids);
120
+ }
121
+ export function FilterByUUIDs(items, ids, getId) {
122
+ const wanted = asUUIDSet(ids);
123
+ const idOf = getId ?? readID;
124
+ return items.filter((item) => wanted.Has(idOf(item)));
125
+ }
126
+ export function ExcludeByUUIDs(items, ids, getId) {
127
+ const unwanted = asUUIDSet(ids);
128
+ const idOf = getId ?? readID;
129
+ return items.filter((item) => !unwanted.Has(idOf(item)));
130
+ }
131
+ export function CountByUUID(items, getId) {
132
+ const idOf = getId ?? readID;
133
+ const counts = new UUIDMap();
134
+ for (const item of items) {
135
+ const id = idOf(item);
136
+ counts.Set(id, (counts.Get(id) ?? 0) + 1);
137
+ }
138
+ return counts;
139
+ }
140
+ export function GroupByUUID(items, getId) {
141
+ const idOf = getId ?? readID;
142
+ const groups = new UUIDMap();
143
+ for (const item of items) {
144
+ const id = idOf(item);
145
+ const group = groups.Get(id);
146
+ if (group)
147
+ group.push(item);
148
+ else
149
+ groups.Set(id, [item]);
150
+ }
151
+ return groups;
152
+ }
153
+ export function IndexByUUID(items, getId) {
154
+ const idOf = getId ?? readID;
155
+ const index = new UUIDMap();
156
+ for (const item of items) {
157
+ const id = idOf(item);
158
+ if (!index.Has(id))
159
+ index.Set(id, item);
160
+ }
161
+ return index;
162
+ }
163
+ //# sourceMappingURL=UUIDCollections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UUIDCollections.js","sourceRoot":"","sources":["../../src/util/UUIDCollections.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"UUIDUtils.d.ts","sourceRoot":"","sources":["../../src/util/UUIDUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGrE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAQtG;AASD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGpE"}
1
+ {"version":3,"file":"UUIDUtils.d.ts","sourceRoot":"","sources":["../../src/util/UUIDUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGrE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAatG;AAsDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGpE"}
@@ -49,13 +49,68 @@ export function UUIDsEqual(uuid1, uuid2) {
49
49
  return true;
50
50
  if (uuid1 == null || uuid2 == null)
51
51
  return false;
52
- // Fast path: identical references / already-equal strings (same value, same platform casing)
53
- // are the overwhelmingly common case in tight `.find()`/`.some()` loops. Short-circuit before
54
- // allocating two normalized copies via trim().toLowerCase().
52
+ // Fast path: identical references / already-equal strings (same value, same platform casing).
55
53
  if (uuid1 === uuid2)
56
54
  return true;
55
+ // Compare without allocating. `trim().toLowerCase()` on both sides built two new strings per
56
+ // call, and most calls in a `.filter`/`.some` scan are MISMATCHES, which the `===` path above
57
+ // never catches. The ASCII compare below settles every UUID-shaped input; anything it cannot
58
+ // settle exactly (a non-ASCII character) falls back to the original expression, so the
59
+ // result is identical to `uuid1.trim().toLowerCase() === uuid2.trim().toLowerCase()`.
60
+ const settled = compareTrimmedAsciiCaseInsensitive(uuid1, uuid2);
61
+ if (settled !== undefined)
62
+ return settled;
57
63
  return uuid1.trim().toLowerCase() === uuid2.trim().toLowerCase();
58
64
  }
65
+ /** Characters `String.prototype.trim` removes: ECMAScript WhiteSpace plus LineTerminator. */
66
+ function isTrimmable(code) {
67
+ return (code === 0x20 || (code >= 0x09 && code <= 0x0d) || code === 0xa0 || code === 0x1680 ||
68
+ (code >= 0x2000 && code <= 0x200a) || code === 0x2028 || code === 0x2029 || code === 0x202f ||
69
+ code === 0x205f || code === 0x3000 || code === 0xfeff);
70
+ }
71
+ function hasNonAscii(value, start, end) {
72
+ for (let i = start; i < end; i++) {
73
+ if (value.charCodeAt(i) > 0x7f)
74
+ return true;
75
+ }
76
+ return false;
77
+ }
78
+ /**
79
+ * Compares the trimmed ranges of `a` and `b`, folding ASCII A-Z to a-z, without allocating.
80
+ * Returns the answer when ASCII rules decide it, or `undefined` when a non-ASCII character is
81
+ * involved (Unicode lower-casing can change a string's length or map outside ASCII, so only the
82
+ * original `toLowerCase()` path can answer those exactly).
83
+ */
84
+ function compareTrimmedAsciiCaseInsensitive(a, b) {
85
+ let aStart = 0, aEnd = a.length, bStart = 0, bEnd = b.length;
86
+ while (aStart < aEnd && isTrimmable(a.charCodeAt(aStart)))
87
+ aStart++;
88
+ while (aEnd > aStart && isTrimmable(a.charCodeAt(aEnd - 1)))
89
+ aEnd--;
90
+ while (bStart < bEnd && isTrimmable(b.charCodeAt(bStart)))
91
+ bStart++;
92
+ while (bEnd > bStart && isTrimmable(b.charCodeAt(bEnd - 1)))
93
+ bEnd--;
94
+ const length = aEnd - aStart;
95
+ if (length !== bEnd - bStart) {
96
+ return hasNonAscii(a, aStart, aEnd) || hasNonAscii(b, bStart, bEnd) ? undefined : false;
97
+ }
98
+ for (let i = 0; i < length; i++) {
99
+ let x = a.charCodeAt(aStart + i);
100
+ let y = b.charCodeAt(bStart + i);
101
+ if (x === y)
102
+ continue;
103
+ if (x > 0x7f || y > 0x7f)
104
+ return undefined;
105
+ if (x >= 0x41 && x <= 0x5a)
106
+ x += 0x20;
107
+ if (y >= 0x41 && y <= 0x5a)
108
+ y += 0x20;
109
+ if (x !== y)
110
+ return false;
111
+ }
112
+ return true;
113
+ }
59
114
  /**
60
115
  * Canonical UUID format (8-4-4-4-12 hex groups). Case-insensitive; the version/variant digits are
61
116
  * NOT constrained, so this validates SHAPE rather than RFC version — which is exactly what is needed
@@ -1 +1 @@
1
- {"version":3,"file":"UUIDUtils.js","sourceRoot":"","sources":["../../src/util/UUIDUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAAC,IAA+B;IACzD,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC5B,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAgC,EAAE,KAAgC;IACzF,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAChD,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,KAAK,CAAC;IACjD,6FAA6F;IAC7F,8FAA8F;IAC9F,6DAA6D;IAC7D,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,MAAM,WAAW,GAAG,iEAAiE,CAAC;AAEtF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,WAAW,CAAC,IAA+B;IACvD,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,KAAK,CAAC;IAC/B,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AACzC,CAAC"}
1
+ {"version":3,"file":"UUIDUtils.js","sourceRoot":"","sources":["../../src/util/UUIDUtils.ts"],"names":[],"mappings":"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"}
package/dist/util.d.ts CHANGED
@@ -348,6 +348,20 @@ export declare function adjustCasing(word: string, options?: {
348
348
  export declare function StripTrailingChars(s: string, charsToStrip: string, skipIfExactMatch: boolean): string;
349
349
  /** @deprecated Use {@link StripTrailingChars}. */
350
350
  export declare function stripTrailingChars(s: string, charsToStrip: string, skipIfExactMatch: boolean): string;
351
+ /**
352
+ * Removes every trailing `/` from a string, typically a base URL before a path is joined onto it.
353
+ *
354
+ * Linear in the length of the input. The regex `/\/+$/` is not: on a string holding many slashes that
355
+ * are NOT at the end, it backtracks quadratically, which makes it a denial-of-service vector on any
356
+ * caller-supplied URL.
357
+ *
358
+ * @example
359
+ * ```typescript
360
+ * TrimTrailingSlashes('http://localhost:4000///'); // 'http://localhost:4000'
361
+ * TrimTrailingSlashes('/'); // ''
362
+ * ```
363
+ */
364
+ export declare function TrimTrailingSlashes(s: string): string;
351
365
  /**
352
366
  * Recursively removes all spaces from a given string.
353
367
  *
@@ -562,6 +576,31 @@ export declare function IsOnlyTimezoneShift(date1: Date, date2: Date): boolean;
562
576
  * call in that case — `"…"?.getTime` is `undefined`, and calling it throws.
563
577
  */
564
578
  export declare function ToEpochMs(value: Date | string | number | null | undefined): number;
579
+ /**
580
+ * Compares two values for equality, including cross-representation `Date` comparisons
581
+ * where one or both values may be `Date` instances, ISO date strings, or numeric epoch
582
+ * timestamps (e.g., comparing in-memory entity field values before and after database or
583
+ * JSON wire serialization).
584
+ *
585
+ * Returns `true` when:
586
+ * - `a === b` (strict identity for primitives and references)
587
+ * - Both `a` and `b` are `Date` instances with identical `.getTime()` epoch milliseconds
588
+ * - One side is a `Date` and the other is a `string` or `number` that parses to the same
589
+ * epoch milliseconds as the `Date`
590
+ *
591
+ * @param a - First value to compare
592
+ * @param b - Second value to compare
593
+ * @returns `true` if the values are equal, `false` otherwise
594
+ *
595
+ * @example
596
+ * ```typescript
597
+ * ValuesEqual(42, 42); // true
598
+ * ValuesEqual(new Date('2026-08-01T00:00:00.000Z'), new Date('2026-08-01T00:00:00.000Z')); // true
599
+ * ValuesEqual(new Date('2026-08-01T00:00:00.000Z'), '2026-08-01T00:00:00.000Z'); // true
600
+ * ValuesEqual('a', 'b'); // false
601
+ * ```
602
+ */
603
+ export declare function ValuesEqual(a: unknown, b: unknown): boolean;
565
604
  /**
566
605
  * Locale-independent total order on strings (UTF-16 code units). Use for every sort whose
567
606
  * result is EMITTED (generated code, SQL, file names, migration captures). Not for UI display —
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
package/dist/util.js CHANGED
@@ -1322,6 +1322,26 @@ export function StripTrailingChars(s, charsToStrip, skipIfExactMatch) {
1322
1322
  export function stripTrailingChars(s, charsToStrip, skipIfExactMatch) {
1323
1323
  return StripTrailingChars(s, charsToStrip, skipIfExactMatch);
1324
1324
  }
1325
+ /**
1326
+ * Removes every trailing `/` from a string, typically a base URL before a path is joined onto it.
1327
+ *
1328
+ * Linear in the length of the input. The regex `/\/+$/` is not: on a string holding many slashes that
1329
+ * are NOT at the end, it backtracks quadratically, which makes it a denial-of-service vector on any
1330
+ * caller-supplied URL.
1331
+ *
1332
+ * @example
1333
+ * ```typescript
1334
+ * TrimTrailingSlashes('http://localhost:4000///'); // 'http://localhost:4000'
1335
+ * TrimTrailingSlashes('/'); // ''
1336
+ * ```
1337
+ */
1338
+ export function TrimTrailingSlashes(s) {
1339
+ let end = s.length;
1340
+ while (end > 0 && s.charCodeAt(end - 1) === 47 /* '/' */) {
1341
+ end--;
1342
+ }
1343
+ return end === s.length ? s : s.substring(0, end);
1344
+ }
1325
1345
  /**
1326
1346
  * Recursively removes all spaces from a given string.
1327
1347
  *
@@ -1831,6 +1851,44 @@ export function ToEpochMs(value) {
1831
1851
  const ms = value instanceof Date ? value.getTime() : new Date(value).getTime();
1832
1852
  return Number.isNaN(ms) ? 0 : ms;
1833
1853
  }
1854
+ /**
1855
+ * Compares two values for equality, including cross-representation `Date` comparisons
1856
+ * where one or both values may be `Date` instances, ISO date strings, or numeric epoch
1857
+ * timestamps (e.g., comparing in-memory entity field values before and after database or
1858
+ * JSON wire serialization).
1859
+ *
1860
+ * Returns `true` when:
1861
+ * - `a === b` (strict identity for primitives and references)
1862
+ * - Both `a` and `b` are `Date` instances with identical `.getTime()` epoch milliseconds
1863
+ * - One side is a `Date` and the other is a `string` or `number` that parses to the same
1864
+ * epoch milliseconds as the `Date`
1865
+ *
1866
+ * @param a - First value to compare
1867
+ * @param b - Second value to compare
1868
+ * @returns `true` if the values are equal, `false` otherwise
1869
+ *
1870
+ * @example
1871
+ * ```typescript
1872
+ * ValuesEqual(42, 42); // true
1873
+ * ValuesEqual(new Date('2026-08-01T00:00:00.000Z'), new Date('2026-08-01T00:00:00.000Z')); // true
1874
+ * ValuesEqual(new Date('2026-08-01T00:00:00.000Z'), '2026-08-01T00:00:00.000Z'); // true
1875
+ * ValuesEqual('a', 'b'); // false
1876
+ * ```
1877
+ */
1878
+ export function ValuesEqual(a, b) {
1879
+ if (a === b)
1880
+ return true;
1881
+ if (a instanceof Date && b instanceof Date) {
1882
+ return a.getTime() === b.getTime();
1883
+ }
1884
+ if (a instanceof Date && (typeof b === 'string' || typeof b === 'number')) {
1885
+ return a.getTime() === new Date(b).getTime();
1886
+ }
1887
+ if (b instanceof Date && (typeof a === 'string' || typeof a === 'number')) {
1888
+ return new Date(a).getTime() === b.getTime();
1889
+ }
1890
+ return false;
1891
+ }
1834
1892
  /**
1835
1893
  * Locale-independent total order on strings (UTF-16 code units). Use for every sort whose
1836
1894
  * result is EMITTED (generated code, SQL, file names, migration captures). Not for UI display —