@memberjunction/core 6.1.0-edge.5 → 6.1.0-edge.7

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 (98) hide show
  1. package/dist/generic/JSONType-interfaces/IEntitySubtypeSelectorConfig.d.ts +27 -0
  2. package/dist/generic/JSONType-interfaces/IEntitySubtypeSelectorConfig.d.ts.map +1 -0
  3. package/dist/generic/JSONType-interfaces/IEntitySubtypeSelectorConfig.js +6 -0
  4. package/dist/generic/JSONType-interfaces/IEntitySubtypeSelectorConfig.js.map +1 -0
  5. package/dist/generic/baseEngine.d.ts +52 -1
  6. package/dist/generic/baseEngine.d.ts.map +1 -1
  7. package/dist/generic/baseEngine.js +95 -7
  8. package/dist/generic/baseEngine.js.map +1 -1
  9. package/dist/generic/baseEntity.d.ts +292 -0
  10. package/dist/generic/baseEntity.d.ts.map +1 -1
  11. package/dist/generic/baseEntity.js +878 -98
  12. package/dist/generic/baseEntity.js.map +1 -1
  13. package/dist/generic/baseInfo.d.ts +6 -0
  14. package/dist/generic/baseInfo.d.ts.map +1 -1
  15. package/dist/generic/baseInfo.js +19 -1
  16. package/dist/generic/baseInfo.js.map +1 -1
  17. package/dist/generic/compositeKey.d.ts +108 -0
  18. package/dist/generic/compositeKey.d.ts.map +1 -1
  19. package/dist/generic/compositeKey.js +225 -10
  20. package/dist/generic/compositeKey.js.map +1 -1
  21. package/dist/generic/databaseProviderBase.d.ts +49 -0
  22. package/dist/generic/databaseProviderBase.d.ts.map +1 -1
  23. package/dist/generic/databaseProviderBase.js +90 -11
  24. package/dist/generic/databaseProviderBase.js.map +1 -1
  25. package/dist/generic/embeddedRecord.d.ts +2 -1
  26. package/dist/generic/embeddedRecord.d.ts.map +1 -1
  27. package/dist/generic/embeddedRecord.js +9 -2
  28. package/dist/generic/embeddedRecord.js.map +1 -1
  29. package/dist/generic/entityCompanion.d.ts +6 -1
  30. package/dist/generic/entityCompanion.d.ts.map +1 -1
  31. package/dist/generic/entityCompanion.js +7 -0
  32. package/dist/generic/entityCompanion.js.map +1 -1
  33. package/dist/generic/entityInfo.d.ts +550 -8
  34. package/dist/generic/entityInfo.d.ts.map +1 -1
  35. package/dist/generic/entityInfo.js +695 -20
  36. package/dist/generic/entityInfo.js.map +1 -1
  37. package/dist/generic/entitySubtypeResolver.d.ts +19 -0
  38. package/dist/generic/entitySubtypeResolver.d.ts.map +1 -0
  39. package/dist/generic/entitySubtypeResolver.js +24 -0
  40. package/dist/generic/entitySubtypeResolver.js.map +1 -0
  41. package/dist/generic/entityTransactionScope.d.ts +6 -3
  42. package/dist/generic/entityTransactionScope.d.ts.map +1 -1
  43. package/dist/generic/entityTransactionScope.js +6 -3
  44. package/dist/generic/entityTransactionScope.js.map +1 -1
  45. package/dist/generic/extendedTypeValue.d.ts +47 -0
  46. package/dist/generic/extendedTypeValue.d.ts.map +1 -0
  47. package/dist/generic/extendedTypeValue.js +152 -0
  48. package/dist/generic/extendedTypeValue.js.map +1 -0
  49. package/dist/generic/filters/compositeFilter.d.ts +77 -0
  50. package/dist/generic/filters/compositeFilter.d.ts.map +1 -0
  51. package/dist/generic/filters/compositeFilter.js +324 -0
  52. package/dist/generic/filters/compositeFilter.js.map +1 -0
  53. package/dist/generic/filters/filter.types.d.ts +29 -0
  54. package/dist/generic/filters/filter.types.d.ts.map +1 -0
  55. package/dist/generic/filters/filter.types.js +28 -0
  56. package/dist/generic/filters/filter.types.js.map +1 -0
  57. package/dist/generic/filters/index.d.ts +3 -0
  58. package/dist/generic/filters/index.d.ts.map +1 -0
  59. package/dist/generic/filters/index.js +3 -0
  60. package/dist/generic/filters/index.js.map +1 -0
  61. package/dist/generic/geoFields.d.ts +64 -0
  62. package/dist/generic/geoFields.d.ts.map +1 -0
  63. package/dist/generic/geoFields.js +108 -0
  64. package/dist/generic/geoFields.js.map +1 -0
  65. package/dist/generic/interfaces.d.ts +16 -2
  66. package/dist/generic/interfaces.d.ts.map +1 -1
  67. package/dist/generic/interfaces.js.map +1 -1
  68. package/dist/generic/localCacheManager.d.ts +34 -3
  69. package/dist/generic/localCacheManager.d.ts.map +1 -1
  70. package/dist/generic/localCacheManager.js +53 -4
  71. package/dist/generic/localCacheManager.js.map +1 -1
  72. package/dist/generic/providerBase.d.ts +282 -5
  73. package/dist/generic/providerBase.d.ts.map +1 -1
  74. package/dist/generic/providerBase.js +754 -93
  75. package/dist/generic/providerBase.js.map +1 -1
  76. package/dist/generic/recordChangeFieldSecurity.d.ts +164 -0
  77. package/dist/generic/recordChangeFieldSecurity.d.ts.map +1 -0
  78. package/dist/generic/recordChangeFieldSecurity.js +279 -0
  79. package/dist/generic/recordChangeFieldSecurity.js.map +1 -0
  80. package/dist/generic/relatedRecordBatchLoader.js +2 -2
  81. package/dist/generic/relatedRecordBatchLoader.js.map +1 -1
  82. package/dist/generic/relatedRecordCollection.d.ts +2 -1
  83. package/dist/generic/relatedRecordCollection.d.ts.map +1 -1
  84. package/dist/generic/relatedRecordCollection.js +16 -4
  85. package/dist/generic/relatedRecordCollection.js.map +1 -1
  86. package/dist/generic/saveEntityGraphOperation.d.ts +10 -0
  87. package/dist/generic/saveEntityGraphOperation.d.ts.map +1 -1
  88. package/dist/generic/saveEntityGraphOperation.js +2 -1
  89. package/dist/generic/saveEntityGraphOperation.js.map +1 -1
  90. package/dist/generic/wellKnownUserSource.d.ts +70 -0
  91. package/dist/generic/wellKnownUserSource.d.ts.map +1 -0
  92. package/dist/generic/wellKnownUserSource.js +82 -0
  93. package/dist/generic/wellKnownUserSource.js.map +1 -0
  94. package/dist/index.d.ts +7 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +7 -0
  97. package/dist/index.js.map +1 -1
  98. package/package.json +3 -3
@@ -0,0 +1,164 @@
1
+ import { EntityInfo } from "./entityInfo.js";
2
+ import { UserInfo } from "./securityInfo.js";
3
+ /**
4
+ * The two metadata lookups this projector needs, and nothing else.
5
+ *
6
+ * Narrower than `IMetadataProvider` on purpose: both `ProviderBase` (which passes `this`) and
7
+ * `Metadata` (which the GraphQL resolvers fall back to) satisfy this, while only the first
8
+ * satisfies the full provider interface. Asking for exactly what is used keeps the resolver half
9
+ * from having to invent a provider it does not have.
10
+ */
11
+ export interface RecordChangeMetadataSource {
12
+ readonly Entities: EntityInfo[];
13
+ EntityByID(entityID: string): EntityInfo | undefined;
14
+ }
15
+ /**
16
+ * The audit entity whose rows carry OTHER entities' field values. Matched by name rather than by
17
+ * ID because every other enforcement point in this feature keys off the entity name too, and a
18
+ * name is the thing a reader can check against metadata without a lookup.
19
+ */
20
+ export declare const RecordChangesEntityName = "MJ: Record Changes";
21
+ /**
22
+ * The Record Change column naming the entity a row is ABOUT. Everything in this module hangs off
23
+ * it: it is what makes the denied set per-ROW rather than per-result.
24
+ */
25
+ export declare const RecordChangeEntityIDField = "EntityID";
26
+ /**
27
+ * Payload columns holding a JSON object keyed by the target entity's field names — projected
28
+ * key by key against the denied set. `ChangesJSON` is `{ [field]: { field, oldValue, newValue } }`;
29
+ * `FullRecordJSON` is a flat whole-row snapshot. Both are top-level-keyed by field name, which is
30
+ * what lets one projection handle them.
31
+ */
32
+ export declare const RecordChangeJSONPayloadFields: readonly ["ChangesJSON", "FullRecordJSON"];
33
+ /**
34
+ * The human-prose payload column — withheld outright, never redacted. See
35
+ * {@link RecordChangeFieldSecurityProjector}.
36
+ */
37
+ export declare const RecordChangeProsePayloadField = "ChangesDescription";
38
+ /**
39
+ * Every payload column this module touches, for callers that need to act on the set as a whole —
40
+ * notably the write guard, which must refuse a narrowed value coming back in.
41
+ */
42
+ export declare const RecordChangePayloadFields: readonly string[];
43
+ /**
44
+ * Outcome of projecting one JSON payload column: either a value to write back, or a decision to
45
+ * withhold the column entirely because the payload could not be inspected.
46
+ *
47
+ * Deliberately an interface with an optional `Value` rather than a discriminated union — MJCore
48
+ * compiles without `strictNullChecks`, under which TypeScript does not narrow a union on a
49
+ * boolean discriminant, so the union shape would force a cast at every read.
50
+ */
51
+ export interface RecordChangePayloadProjection {
52
+ /** When true the caller drops the column; `Value` carries nothing. */
53
+ Withhold: boolean;
54
+ /** The value to write back. Meaningful only when {@link Withhold} is false. */
55
+ Value?: unknown;
56
+ }
57
+ /**
58
+ * Narrows one Record Change JSON payload to the fields the caller may read.
59
+ *
60
+ * **Withholds rather than guesses.** A payload that is not a string, or is a string that does not
61
+ * parse, or parses to something other than a plain object, is a payload this cannot prove is
62
+ * clean — so the column is dropped instead of passed through. A null/undefined/empty value is
63
+ * kept as-is: there is nothing stored to leak, and `ChangesJSON` is legitimately `''` on rows
64
+ * whose diff produced nothing.
65
+ *
66
+ * @param raw the column's stored value
67
+ * @param deniedLowercase field names the caller may not read, already lowercased
68
+ */
69
+ export declare function ProjectRecordChangePayloadJSON(raw: unknown, deniedLowercase: Set<string>): RecordChangePayloadProjection;
70
+ /**
71
+ * Field-level security for the payload columns of `MJ: Record Changes`.
72
+ *
73
+ * ## Why this is not `ProviderBase.ApplyFieldSecurityProjection`
74
+ *
75
+ * Every other FLS enforcement point computes the denied set against **the entity being read**. A
76
+ * Record Change row is about a DIFFERENT entity — the one named by its own `EntityID` column —
77
+ * and `MJ: Record Changes` itself has field security switched off in every default deployment.
78
+ * The main projection therefore short-circuits on `EnableFieldLevelSecurity` and returns the row
79
+ * untouched, with a denied field's old and new values sitting in `ChangesJSON` in plain text.
80
+ * That is the leak this closes: a user with entity-level read on the audit trail could read a
81
+ * salary they were denied on `MJ: Employees` straight out of it, in the default configuration.
82
+ *
83
+ * ## What happens to each column
84
+ *
85
+ * | Column | Treatment |
86
+ * |---|---|
87
+ * | `ChangesJSON` | projected — denied field keys dropped |
88
+ * | `FullRecordJSON` | projected — same, it is a whole-row snapshot |
89
+ * | `ChangesDescription` | **withheld entirely** whenever the caller is denied anything on the target entity |
90
+ *
91
+ * `ChangesDescription` is human prose ("Salary changed from 100000 to 120000"). Redacting prose
92
+ * on the fly leaks on the first value that appears in an unexpected form, and regenerating it
93
+ * from the filtered JSON is a larger surface than this is worth. Withholding the whole column is
94
+ * coarse and it is safe, which is the right trade for a field whose only job is to be readable
95
+ * text — and callers already degrade, the record-changes UI falling back to 'Changes made'.
96
+ *
97
+ * ## Rows in one result span different entities
98
+ *
99
+ * `EntityID` varies row to row, and `EntityInfo.GetDeniedReadFields` walks every field on the
100
+ * entity — its documented performance contract is that it must not be called in a row loop. Every
101
+ * lookup here is memoized on the raw `EntityID` string for the projector's lifetime, which is one
102
+ * request. Construct one projector per request, never one per row.
103
+ */
104
+ export declare class RecordChangeFieldSecurityProjector {
105
+ private readonly provider;
106
+ private readonly user;
107
+ private readonly deniedByEntityID;
108
+ private carriesDenials;
109
+ private payloadKeys;
110
+ constructor(provider: RecordChangeMetadataSource, user: UserInfo);
111
+ /**
112
+ * Whether an entity is the audit trail this projector guards. Callers gate on this before
113
+ * constructing a projector, so nothing is paid on the other 99% of reads.
114
+ */
115
+ static IsRecordChangesEntity(entity: EntityInfo | null | undefined): boolean;
116
+ /**
117
+ * Projects a whole result set. Returns the ORIGINAL array when nothing needed changing, so an
118
+ * unrestricted caller's rows are never rebuilt — and, on the cache-hit paths, so the cache's
119
+ * own frozen objects are handed back by reference exactly as they are today.
120
+ */
121
+ ProjectRows<T>(rows: T[]): T[];
122
+ /**
123
+ * Single-row form, for the GraphQL read boundary. Returns the original object untouched when
124
+ * there is nothing to project.
125
+ */
126
+ ProjectRow<T>(row: T): T;
127
+ /**
128
+ * Whether this caller is denied ANY field on ANY field-security-enabled entity.
129
+ *
130
+ * The whole projector is a no-op for everyone else, and this gate is what makes that true —
131
+ * including for the fail-closed branch in {@link deniedFieldsFor}, which would otherwise blank
132
+ * audit rows on deployments that never enabled field security at all. Cost is one pass over
133
+ * the entity list plus one denied-set walk per ENABLED entity, and the flag is off on every
134
+ * entity an administrator has not explicitly opted in.
135
+ *
136
+ * Public because the WRITE side needs the same question: a caller who could have been served a
137
+ * narrowed payload must not be allowed to write one back. See
138
+ * `ResolverBase.StripRecordChangePayloadFromClientInput`.
139
+ */
140
+ CallerCarriesAnyDenial(): boolean;
141
+ private callerCarriesDenials;
142
+ private projectOne;
143
+ /**
144
+ * The denied-read set for the entity a Record Change row is ABOUT, or `null` to fail closed.
145
+ *
146
+ * **`null` drops all three payload columns.** Two shapes reach it and both have to. The first
147
+ * is an `EntityID` that no longer resolves to a known entity. The second is the one that
148
+ * decides the policy: a row that does not carry `EntityID` at all. A caller can ask for
149
+ * `Fields: ['ChangesJSON']` and nothing else, and field narrowing runs BEFORE this projection
150
+ * — so failing open on a missing `EntityID` would be a one-parameter bypass of the entire
151
+ * control.
152
+ *
153
+ * The cost of failing closed is paid only by callers who already carry denials somewhere (see
154
+ * {@link callerCarriesDenials}), and lands on audit rows for entities that are gone from
155
+ * metadata — rows for which no caller can render an entity name either way.
156
+ */
157
+ private deniedFieldsFor;
158
+ /**
159
+ * Resolves the row's actual key casing once. Returns null — cached as null — when the rows
160
+ * carry no payload column at all, which makes every later row a single map read.
161
+ */
162
+ private resolvePayloadKeys;
163
+ }
164
+ //# sourceMappingURL=recordChangeFieldSecurity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recordChangeFieldSecurity.d.ts","sourceRoot":"","sources":["../../src/generic/recordChangeFieldSecurity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C;;;;;;;GAOG;AACH,MAAM,WAAW,0BAA0B;IACvC,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC;IAChC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;CACxD;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,uBAAuB,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,yBAAyB,aAAa,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,4CAA6C,CAAC;AAExF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,uBAAuB,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EAGtD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,WAAW,6BAA6B;IAC1C,sEAAsE;IACtE,QAAQ,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,6BAA6B,CAiCxH;AA8BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,kCAAkC;IAMvC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI;IANzB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAyC;IAC1E,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,WAAW,CAAyD;gBAGvD,QAAQ,EAAE,0BAA0B,EACpC,IAAI,EAAE,QAAQ;IAGnC;;;OAGG;WACW,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO;IAInF;;;;OAIG;IACI,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE;IAerC;;;OAGG;IACI,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC;IAO/B;;;;;;;;;;;;OAYG;IACI,sBAAsB,IAAI,OAAO;IAIxC,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,UAAU;IAiClB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,eAAe;IAkBvB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;CAsB7B"}
@@ -0,0 +1,279 @@
1
+ /**
2
+ * The audit entity whose rows carry OTHER entities' field values. Matched by name rather than by
3
+ * ID because every other enforcement point in this feature keys off the entity name too, and a
4
+ * name is the thing a reader can check against metadata without a lookup.
5
+ */
6
+ export const RecordChangesEntityName = 'MJ: Record Changes';
7
+ /**
8
+ * The Record Change column naming the entity a row is ABOUT. Everything in this module hangs off
9
+ * it: it is what makes the denied set per-ROW rather than per-result.
10
+ */
11
+ export const RecordChangeEntityIDField = 'EntityID';
12
+ /**
13
+ * Payload columns holding a JSON object keyed by the target entity's field names — projected
14
+ * key by key against the denied set. `ChangesJSON` is `{ [field]: { field, oldValue, newValue } }`;
15
+ * `FullRecordJSON` is a flat whole-row snapshot. Both are top-level-keyed by field name, which is
16
+ * what lets one projection handle them.
17
+ */
18
+ export const RecordChangeJSONPayloadFields = ['ChangesJSON', 'FullRecordJSON'];
19
+ /**
20
+ * The human-prose payload column — withheld outright, never redacted. See
21
+ * {@link RecordChangeFieldSecurityProjector}.
22
+ */
23
+ export const RecordChangeProsePayloadField = 'ChangesDescription';
24
+ /**
25
+ * Every payload column this module touches, for callers that need to act on the set as a whole —
26
+ * notably the write guard, which must refuse a narrowed value coming back in.
27
+ */
28
+ export const RecordChangePayloadFields = [
29
+ ...RecordChangeJSONPayloadFields,
30
+ RecordChangeProsePayloadField,
31
+ ];
32
+ /**
33
+ * Narrows one Record Change JSON payload to the fields the caller may read.
34
+ *
35
+ * **Withholds rather than guesses.** A payload that is not a string, or is a string that does not
36
+ * parse, or parses to something other than a plain object, is a payload this cannot prove is
37
+ * clean — so the column is dropped instead of passed through. A null/undefined/empty value is
38
+ * kept as-is: there is nothing stored to leak, and `ChangesJSON` is legitimately `''` on rows
39
+ * whose diff produced nothing.
40
+ *
41
+ * @param raw the column's stored value
42
+ * @param deniedLowercase field names the caller may not read, already lowercased
43
+ */
44
+ export function ProjectRecordChangePayloadJSON(raw, deniedLowercase) {
45
+ if (raw === null || raw === undefined) {
46
+ return { Withhold: false, Value: raw };
47
+ }
48
+ if (typeof raw !== 'string') {
49
+ return { Withhold: true };
50
+ }
51
+ if (raw.trim().length === 0) {
52
+ return { Withhold: false, Value: raw };
53
+ }
54
+ let parsed;
55
+ try {
56
+ parsed = JSON.parse(raw);
57
+ }
58
+ catch {
59
+ return { Withhold: true };
60
+ }
61
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
62
+ return { Withhold: true };
63
+ }
64
+ const source = parsed;
65
+ const kept = {};
66
+ for (const key of Object.keys(source)) {
67
+ if (deniedLowercase.has(key.trim().toLowerCase())) {
68
+ continue;
69
+ }
70
+ if (isDeniedChangeEntry(source[key], deniedLowercase)) {
71
+ continue;
72
+ }
73
+ kept[key] = source[key];
74
+ }
75
+ return { Withhold: false, Value: JSON.stringify(kept) };
76
+ }
77
+ /**
78
+ * A `ChangesJSON` entry is `{ field, oldValue, newValue }` stored under a key that is that same
79
+ * field name, so the key check already catches it. This second check costs one property read and
80
+ * covers the case where the two disagree — a payload written by something other than
81
+ * `DatabaseProviderBase.DiffObjects`, or hand-edited. Where they disagree, the entry is dropped.
82
+ */
83
+ function isDeniedChangeEntry(value, deniedLowercase) {
84
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
85
+ return false;
86
+ }
87
+ const field = value['field'];
88
+ return typeof field === 'string' && deniedLowercase.has(field.trim().toLowerCase());
89
+ }
90
+ /**
91
+ * Field-level security for the payload columns of `MJ: Record Changes`.
92
+ *
93
+ * ## Why this is not `ProviderBase.ApplyFieldSecurityProjection`
94
+ *
95
+ * Every other FLS enforcement point computes the denied set against **the entity being read**. A
96
+ * Record Change row is about a DIFFERENT entity — the one named by its own `EntityID` column —
97
+ * and `MJ: Record Changes` itself has field security switched off in every default deployment.
98
+ * The main projection therefore short-circuits on `EnableFieldLevelSecurity` and returns the row
99
+ * untouched, with a denied field's old and new values sitting in `ChangesJSON` in plain text.
100
+ * That is the leak this closes: a user with entity-level read on the audit trail could read a
101
+ * salary they were denied on `MJ: Employees` straight out of it, in the default configuration.
102
+ *
103
+ * ## What happens to each column
104
+ *
105
+ * | Column | Treatment |
106
+ * |---|---|
107
+ * | `ChangesJSON` | projected — denied field keys dropped |
108
+ * | `FullRecordJSON` | projected — same, it is a whole-row snapshot |
109
+ * | `ChangesDescription` | **withheld entirely** whenever the caller is denied anything on the target entity |
110
+ *
111
+ * `ChangesDescription` is human prose ("Salary changed from 100000 to 120000"). Redacting prose
112
+ * on the fly leaks on the first value that appears in an unexpected form, and regenerating it
113
+ * from the filtered JSON is a larger surface than this is worth. Withholding the whole column is
114
+ * coarse and it is safe, which is the right trade for a field whose only job is to be readable
115
+ * text — and callers already degrade, the record-changes UI falling back to 'Changes made'.
116
+ *
117
+ * ## Rows in one result span different entities
118
+ *
119
+ * `EntityID` varies row to row, and `EntityInfo.GetDeniedReadFields` walks every field on the
120
+ * entity — its documented performance contract is that it must not be called in a row loop. Every
121
+ * lookup here is memoized on the raw `EntityID` string for the projector's lifetime, which is one
122
+ * request. Construct one projector per request, never one per row.
123
+ */
124
+ export class RecordChangeFieldSecurityProjector {
125
+ constructor(provider, user) {
126
+ this.provider = provider;
127
+ this.user = user;
128
+ this.deniedByEntityID = new Map();
129
+ this.carriesDenials = null;
130
+ this.payloadKeys = undefined;
131
+ }
132
+ /**
133
+ * Whether an entity is the audit trail this projector guards. Callers gate on this before
134
+ * constructing a projector, so nothing is paid on the other 99% of reads.
135
+ */
136
+ static IsRecordChangesEntity(entity) {
137
+ return entity?.Name?.trim().toLowerCase() === RecordChangesEntityName.toLowerCase();
138
+ }
139
+ /**
140
+ * Projects a whole result set. Returns the ORIGINAL array when nothing needed changing, so an
141
+ * unrestricted caller's rows are never rebuilt — and, on the cache-hit paths, so the cache's
142
+ * own frozen objects are handed back by reference exactly as they are today.
143
+ */
144
+ ProjectRows(rows) {
145
+ if (!rows?.length || !this.callerCarriesDenials()) {
146
+ return rows;
147
+ }
148
+ let mutated = false;
149
+ const projected = rows.map((row) => {
150
+ const next = this.projectOne(row);
151
+ if (next !== row) {
152
+ mutated = true;
153
+ }
154
+ return next;
155
+ });
156
+ return mutated ? projected : rows;
157
+ }
158
+ /**
159
+ * Single-row form, for the GraphQL read boundary. Returns the original object untouched when
160
+ * there is nothing to project.
161
+ */
162
+ ProjectRow(row) {
163
+ if (!row || !this.callerCarriesDenials()) {
164
+ return row;
165
+ }
166
+ return this.projectOne(row);
167
+ }
168
+ /**
169
+ * Whether this caller is denied ANY field on ANY field-security-enabled entity.
170
+ *
171
+ * The whole projector is a no-op for everyone else, and this gate is what makes that true —
172
+ * including for the fail-closed branch in {@link deniedFieldsFor}, which would otherwise blank
173
+ * audit rows on deployments that never enabled field security at all. Cost is one pass over
174
+ * the entity list plus one denied-set walk per ENABLED entity, and the flag is off on every
175
+ * entity an administrator has not explicitly opted in.
176
+ *
177
+ * Public because the WRITE side needs the same question: a caller who could have been served a
178
+ * narrowed payload must not be allowed to write one back. See
179
+ * `ResolverBase.StripRecordChangePayloadFromClientInput`.
180
+ */
181
+ CallerCarriesAnyDenial() {
182
+ return this.callerCarriesDenials();
183
+ }
184
+ callerCarriesDenials() {
185
+ if (this.carriesDenials === null) {
186
+ this.carriesDenials = this.provider.Entities.some((e) => e.EnableFieldLevelSecurity && e.GetDeniedReadFields(this.user).size > 0);
187
+ }
188
+ return this.carriesDenials;
189
+ }
190
+ projectOne(row) {
191
+ const source = row;
192
+ if (!source || typeof source !== 'object') {
193
+ return row;
194
+ }
195
+ const keys = this.resolvePayloadKeys(source);
196
+ if (!keys) {
197
+ return row; // the caller selected none of the payload columns — nothing to protect
198
+ }
199
+ const denied = this.deniedFieldsFor(source, keys);
200
+ if (denied !== null && denied.size === 0) {
201
+ return row; // caller reads every field on the entity this row is about
202
+ }
203
+ const projected = { ...source };
204
+ if (keys.Prose) {
205
+ delete projected[keys.Prose];
206
+ }
207
+ for (const key of keys.JSON) {
208
+ if (denied === null) {
209
+ delete projected[key];
210
+ continue;
211
+ }
212
+ const result = ProjectRecordChangePayloadJSON(source[key], denied);
213
+ if (result.Withhold) {
214
+ delete projected[key];
215
+ }
216
+ else {
217
+ projected[key] = result.Value;
218
+ }
219
+ }
220
+ return projected;
221
+ }
222
+ /**
223
+ * The denied-read set for the entity a Record Change row is ABOUT, or `null` to fail closed.
224
+ *
225
+ * **`null` drops all three payload columns.** Two shapes reach it and both have to. The first
226
+ * is an `EntityID` that no longer resolves to a known entity. The second is the one that
227
+ * decides the policy: a row that does not carry `EntityID` at all. A caller can ask for
228
+ * `Fields: ['ChangesJSON']` and nothing else, and field narrowing runs BEFORE this projection
229
+ * — so failing open on a missing `EntityID` would be a one-parameter bypass of the entire
230
+ * control.
231
+ *
232
+ * The cost of failing closed is paid only by callers who already carry denials somewhere (see
233
+ * {@link callerCarriesDenials}), and lands on audit rows for entities that are gone from
234
+ * metadata — rows for which no caller can render an entity name either way.
235
+ */
236
+ deniedFieldsFor(source, keys) {
237
+ if (!keys.EntityID) {
238
+ return null;
239
+ }
240
+ const rawEntityID = source[keys.EntityID];
241
+ if (typeof rawEntityID !== 'string' || rawEntityID.trim().length === 0) {
242
+ return null;
243
+ }
244
+ const cached = this.deniedByEntityID.get(rawEntityID);
245
+ if (cached !== undefined) {
246
+ return cached;
247
+ }
248
+ const entity = this.provider.EntityByID(rawEntityID);
249
+ const denied = entity ? entity.GetDeniedReadFields(this.user) : null;
250
+ this.deniedByEntityID.set(rawEntityID, denied);
251
+ return denied;
252
+ }
253
+ /**
254
+ * Resolves the row's actual key casing once. Returns null — cached as null — when the rows
255
+ * carry no payload column at all, which makes every later row a single map read.
256
+ */
257
+ resolvePayloadKeys(source) {
258
+ if (this.payloadKeys !== undefined) {
259
+ return this.payloadKeys;
260
+ }
261
+ const byLowerName = new Map();
262
+ for (const key of Object.keys(source)) {
263
+ byLowerName.set(key.trim().toLowerCase(), key);
264
+ }
265
+ const jsonKeys = RecordChangeJSONPayloadFields
266
+ .map((name) => byLowerName.get(name.toLowerCase()))
267
+ .filter((key) => key !== undefined);
268
+ const proseKey = byLowerName.get(RecordChangeProsePayloadField.toLowerCase()) ?? null;
269
+ this.payloadKeys = (jsonKeys.length === 0 && proseKey === null)
270
+ ? null
271
+ : {
272
+ JSON: jsonKeys,
273
+ Prose: proseKey,
274
+ EntityID: byLowerName.get(RecordChangeEntityIDField.toLowerCase()) ?? null,
275
+ };
276
+ return this.payloadKeys;
277
+ }
278
+ }
279
+ //# sourceMappingURL=recordChangeFieldSecurity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recordChangeFieldSecurity.js","sourceRoot":"","sources":["../../src/generic/recordChangeFieldSecurity.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,oBAAoB,CAAC;AAE5D;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,UAAU,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,aAAa,EAAE,gBAAgB,CAAU,CAAC;AAExF;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,oBAAoB,CAAC;AAElE;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAsB;IACxD,GAAG,6BAA6B;IAChC,6BAA6B;CAChC,CAAC;AAiBF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,8BAA8B,CAAC,GAAY,EAAE,eAA4B;IACrF,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAC3C,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAC3C,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACzE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC;IAED,MAAM,MAAM,GAAG,MAAiC,CAAC;IACjD,MAAM,IAAI,GAA4B,EAAE,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,IAAI,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YAChD,SAAS;QACb,CAAC;QACD,IAAI,mBAAmB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,eAAe,CAAC,EAAE,CAAC;YACpD,SAAS;QACb,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,KAAc,EAAE,eAA4B;IACrE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACtE,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,MAAM,KAAK,GAAI,KAAiC,CAAC,OAAO,CAAC,CAAC;IAC1D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AACxF,CAAC;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,OAAO,kCAAkC;IAK3C,YACqB,QAAoC,EACpC,IAAc;QADd,aAAQ,GAAR,QAAQ,CAA4B;QACpC,SAAI,GAAJ,IAAI,CAAU;QANlB,qBAAgB,GAAG,IAAI,GAAG,EAA8B,CAAC;QAClE,mBAAc,GAAmB,IAAI,CAAC;QACtC,gBAAW,GAA+C,SAAS,CAAC;IAKzE,CAAC;IAEJ;;;OAGG;IACI,MAAM,CAAC,qBAAqB,CAAC,MAAqC;QACrE,OAAO,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,uBAAuB,CAAC,WAAW,EAAE,CAAC;IACxF,CAAC;IAED;;;;OAIG;IACI,WAAW,CAAI,IAAS;QAC3B,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC;YAChD,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACf,OAAO,GAAG,IAAI,CAAC;YACnB,CAAC;YACD,OAAO,IAAI,CAAC;QAChB,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC;IAED;;;OAGG;IACI,UAAU,CAAI,GAAM;QACvB,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC;YACvC,OAAO,GAAG,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED;;;;;;;;;;;;OAYG;IACI,sBAAsB;QACzB,OAAO,IAAI,CAAC,oBAAoB,EAAE,CAAC;IACvC,CAAC;IAEO,oBAAoB;QACxB,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YAC/B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAC7C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,wBAAwB,IAAI,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CACjF,CAAC;QACN,CAAC;QACD,OAAO,IAAI,CAAC,cAAc,CAAC;IAC/B,CAAC;IAEO,UAAU,CAAI,GAAM;QACxB,MAAM,MAAM,GAAG,GAA8B,CAAC;QAC9C,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxC,OAAO,GAAG,CAAC;QACf,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,EAAE,CAAC;YACR,OAAO,GAAG,CAAC,CAAC,uEAAuE;QACvF,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAClD,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO,GAAG,CAAC,CAAC,2DAA2D;QAC3E,CAAC;QAED,MAAM,SAAS,GAA4B,EAAE,GAAG,MAAM,EAAE,CAAC;QACzD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1B,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBAClB,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC;gBACtB,SAAS;YACb,CAAC;YACD,MAAM,MAAM,GAAG,8BAA8B,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;YACnE,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAClB,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACJ,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC;YAClC,CAAC;QACL,CAAC;QACD,OAAO,SAAc,CAAC;IAC1B,CAAC;IAED;;;;;;;;;;;;;OAaG;IACK,eAAe,CAAC,MAA+B,EAAE,IAA6B;QAClF,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrE,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACtD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,MAAM,CAAC;QAClB,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACrE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC/C,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;OAGG;IACK,kBAAkB,CAAC,MAA+B;QACtD,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,WAAW,CAAC;QAC5B,CAAC;QACD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC9C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;QACnD,CAAC;QACD,MAAM,QAAQ,GAAG,6BAA6B;aACzC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;aAClD,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC;QACvD,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,6BAA6B,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;QAEtF,IAAI,CAAC,WAAW,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,KAAK,IAAI,CAAC;YAC3D,CAAC,CAAC,IAAI;YACN,CAAC,CAAC;gBACE,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,QAAQ;gBACf,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,yBAAyB,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI;aAC7E,CAAC;QACN,OAAO,IAAI,CAAC,WAAW,CAAC;IAC5B,CAAC;CACJ"}
@@ -114,7 +114,7 @@ function distributeChildren(parents, collectionName, foreignKey, children) {
114
114
  if (!(collection instanceof RelatedRecordCollection)) {
115
115
  continue;
116
116
  }
117
- const key = normalizeKey(parent.FirstPrimaryKey?.Value);
117
+ const key = normalizeKey(parent.FirstPrimaryKey?.Value); // first-pk-ok: RelatedEntityJoinField is one FK column, so the parent key it holds is single-column by design
118
118
  collection.SetLoadedItems(byParent.get(key) ?? []);
119
119
  }
120
120
  }
@@ -127,7 +127,7 @@ function distributeChildren(parents, collectionName, foreignKey, children) {
127
127
  function collectParentKeys(parents) {
128
128
  const keys = new Set();
129
129
  for (const parent of parents) {
130
- const value = parent.FirstPrimaryKey?.Value;
130
+ const value = parent.FirstPrimaryKey?.Value; // first-pk-ok: RelatedEntityJoinField is one FK column, so the parent key it holds is single-column by design
131
131
  if (value !== null && value !== undefined && value !== '') {
132
132
  keys.add(String(value));
133
133
  }
@@ -1 +1 @@
1
- {"version":3,"file":"relatedRecordBatchLoader.js","sourceRoot":"","sources":["../../src/generic/relatedRecordBatchLoader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relatedRecordBatchLoader.js","sourceRoot":"","sources":["../../src/generic/relatedRecordBatchLoader.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,7 @@ import type { BaseEntity } from './baseEntity.js';
26
26
  import { EntityCompanion, EntityCompanionDeserializeMode, EntityCompanionPayload } from './entityCompanion.js';
27
27
  import type { EntitySavePlan } from './entitySavePlan.js';
28
28
  import { ValidationResult } from './entityInfo.js';
29
- import type { EntitySaveOptions } from './interfaces.js';
29
+ import type { EntitySaveOptions, IEntityDataProvider } from './interfaces.js';
30
30
  /**
31
31
  * When a child collection populates itself from the database.
32
32
  *
@@ -606,5 +606,6 @@ export declare class RelatedRecordCollection<T extends BaseEntity = BaseEntity>
606
606
  * callers assume when they display or reference "line 3".
607
607
  */
608
608
  private applySequence;
609
+ BindProvider(provider: IEntityDataProvider | null): void;
609
610
  }
610
611
  //# sourceMappingURL=relatedRecordCollection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"relatedRecordCollection.d.ts","sourceRoot":"","sources":["../../src/generic/relatedRecordCollection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relatedRecordCollection.d.ts","sourceRoot":"","sources":["../../src/generic/relatedRecordCollection.ts"],"names":[],"mappings":"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"}
@@ -365,7 +365,7 @@ export class RelatedRecordCollection extends EntityCompanion {
365
365
  if (!provider) {
366
366
  throw new Error(`RelatedRecordCollection '${this.Name}': owner has no provider; cannot load.`);
367
367
  }
368
- const parentKey = this.Owner.FirstPrimaryKey?.Value;
368
+ const parentKey = this.Owner.FirstPrimaryKey?.Value; // first-pk-ok: RelatedEntityJoinField is one FK column, so the parent key it holds is single-column by design
369
369
  const result = await provider.RunView({
370
370
  EntityName: this.RelatedEntityName,
371
371
  ExtraFilter: `${this.options.RelatedEntityJoinField} = '${String(parentKey).replace(/'/g, "''")}'`,
@@ -487,7 +487,7 @@ export class RelatedRecordCollection extends EntityCompanion {
487
487
  // survives the engine reassigning it wholesale, which is the case a captured array
488
488
  // reference misses. Re-running discovery here would also risk silently binding to a
489
489
  // DIFFERENT engine mid-life if two happened to cache the same entity.
490
- const parentKey = this.Owner.FirstPrimaryKey?.Value;
490
+ const parentKey = this.Owner.FirstPrimaryKey?.Value; // first-pk-ok: RelatedEntityJoinField is one FK column, so the parent key it holds is single-column by design
491
491
  if (parentKey === null || parentKey === undefined || parentKey === '') {
492
492
  return;
493
493
  }
@@ -598,7 +598,7 @@ export class RelatedRecordCollection extends EntityCompanion {
598
598
  * entity — in which case the caller falls back to a database load.
599
599
  */
600
600
  findCachedRecords() {
601
- const parentKey = this.Owner.FirstPrimaryKey?.Value;
601
+ const parentKey = this.Owner.FirstPrimaryKey?.Value; // first-pk-ok: RelatedEntityJoinField is one FK column, so the parent key it holds is single-column by design
602
602
  if (parentKey === null || parentKey === undefined || parentKey === '') {
603
603
  return null; // an unsaved parent owns no persisted related records
604
604
  }
@@ -1030,7 +1030,7 @@ export class RelatedRecordCollection extends EntityCompanion {
1030
1030
  * already be correct.
1031
1031
  */
1032
1032
  stampParentKey() {
1033
- const parentKey = this.Owner.FirstPrimaryKey?.Value;
1033
+ const parentKey = this.Owner.FirstPrimaryKey?.Value; // first-pk-ok: RelatedEntityJoinField is one FK column, so the parent key it holds is single-column by design
1034
1034
  if (parentKey === null || parentKey === undefined || parentKey === '') {
1035
1035
  return;
1036
1036
  }
@@ -1062,5 +1062,17 @@ export class RelatedRecordCollection extends EntityCompanion {
1062
1062
  }
1063
1063
  });
1064
1064
  }
1065
+ BindProvider(provider) {
1066
+ for (const item of this.items) {
1067
+ if (item.BoundProvider !== provider) {
1068
+ item.BindProvider(provider);
1069
+ }
1070
+ }
1071
+ for (const item of this.removed) {
1072
+ if (item.BoundProvider !== provider) {
1073
+ item.BindProvider(provider);
1074
+ }
1075
+ }
1076
+ }
1065
1077
  }
1066
1078
  //# sourceMappingURL=relatedRecordCollection.js.map