@syntax-syllogism/warden-core 0.2.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.
Files changed (191) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +21 -0
  3. package/README.md +111 -0
  4. package/lib/access/assignees.d.ts +27 -0
  5. package/lib/access/assignees.js +139 -0
  6. package/lib/access/assignees.js.map +1 -0
  7. package/lib/access/messages.d.ts +1 -0
  8. package/lib/access/messages.js +24 -0
  9. package/lib/access/messages.js.map +1 -0
  10. package/lib/access/metadata.d.ts +41 -0
  11. package/lib/access/metadata.js +168 -0
  12. package/lib/access/metadata.js.map +1 -0
  13. package/lib/access/muting.d.ts +7 -0
  14. package/lib/access/muting.js +22 -0
  15. package/lib/access/muting.js.map +1 -0
  16. package/lib/access/output.d.ts +12 -0
  17. package/lib/access/output.js +108 -0
  18. package/lib/access/output.js.map +1 -0
  19. package/lib/access/resolvers/field.d.ts +2 -0
  20. package/lib/access/resolvers/field.js +93 -0
  21. package/lib/access/resolvers/field.js.map +1 -0
  22. package/lib/access/resolvers/index.d.ts +2 -0
  23. package/lib/access/resolvers/index.js +22 -0
  24. package/lib/access/resolvers/index.js.map +1 -0
  25. package/lib/access/resolvers/object.d.ts +2 -0
  26. package/lib/access/resolvers/object.js +101 -0
  27. package/lib/access/resolvers/object.js.map +1 -0
  28. package/lib/access/resolvers/recordType.d.ts +2 -0
  29. package/lib/access/resolvers/recordType.js +181 -0
  30. package/lib/access/resolvers/recordType.js.map +1 -0
  31. package/lib/access/resolvers/setupEntity.d.ts +4 -0
  32. package/lib/access/resolvers/setupEntity.js +43 -0
  33. package/lib/access/resolvers/setupEntity.js.map +1 -0
  34. package/lib/access/resolvers/tab.d.ts +2 -0
  35. package/lib/access/resolvers/tab.js +36 -0
  36. package/lib/access/resolvers/tab.js.map +1 -0
  37. package/lib/access/reverse.d.ts +9 -0
  38. package/lib/access/reverse.js +429 -0
  39. package/lib/access/reverse.js.map +1 -0
  40. package/lib/access/soql.d.ts +6 -0
  41. package/lib/access/soql.js +31 -0
  42. package/lib/access/soql.js.map +1 -0
  43. package/lib/access/targetValidation.d.ts +7 -0
  44. package/lib/access/targetValidation.js +110 -0
  45. package/lib/access/targetValidation.js.map +1 -0
  46. package/lib/access/types.d.ts +88 -0
  47. package/lib/access/types.js +20 -0
  48. package/lib/access/types.js.map +1 -0
  49. package/lib/errors.d.ts +18 -0
  50. package/lib/errors.js +39 -0
  51. package/lib/errors.js.map +1 -0
  52. package/lib/index.d.ts +37 -0
  53. package/lib/index.js +33 -0
  54. package/lib/index.js.map +1 -0
  55. package/lib/lifecycle/assignmentState.d.ts +62 -0
  56. package/lib/lifecycle/assignmentState.js +89 -0
  57. package/lib/lifecycle/assignmentState.js.map +1 -0
  58. package/lib/lifecycle/conformance.d.ts +10 -0
  59. package/lib/lifecycle/conformance.js +59 -0
  60. package/lib/lifecycle/conformance.js.map +1 -0
  61. package/lib/lifecycle/diffOutput.d.ts +7 -0
  62. package/lib/lifecycle/diffOutput.js +94 -0
  63. package/lib/lifecycle/diffOutput.js.map +1 -0
  64. package/lib/lifecycle/dmlRunner.d.ts +30 -0
  65. package/lib/lifecycle/dmlRunner.js +45 -0
  66. package/lib/lifecycle/dmlRunner.js.map +1 -0
  67. package/lib/lifecycle/errors.d.ts +5 -0
  68. package/lib/lifecycle/errors.js +8 -0
  69. package/lib/lifecycle/errors.js.map +1 -0
  70. package/lib/lifecycle/freezeState.d.ts +28 -0
  71. package/lib/lifecycle/freezeState.js +88 -0
  72. package/lib/lifecycle/freezeState.js.map +1 -0
  73. package/lib/lifecycle/messages.d.ts +1 -0
  74. package/lib/lifecycle/messages.js +20 -0
  75. package/lib/lifecycle/messages.js.map +1 -0
  76. package/lib/lifecycle/output.d.ts +23 -0
  77. package/lib/lifecycle/output.js +148 -0
  78. package/lib/lifecycle/output.js.map +1 -0
  79. package/lib/lifecycle/snapshotState.d.ts +12 -0
  80. package/lib/lifecycle/snapshotState.js +353 -0
  81. package/lib/lifecycle/snapshotState.js.map +1 -0
  82. package/lib/lifecycle/stripApply.d.ts +3 -0
  83. package/lib/lifecycle/stripApply.js +17 -0
  84. package/lib/lifecycle/stripApply.js.map +1 -0
  85. package/lib/lifecycle/stripPlan.d.ts +75 -0
  86. package/lib/lifecycle/stripPlan.js +192 -0
  87. package/lib/lifecycle/stripPlan.js.map +1 -0
  88. package/lib/lifecycle/targeting.d.ts +32 -0
  89. package/lib/lifecycle/targeting.js +195 -0
  90. package/lib/lifecycle/targeting.js.map +1 -0
  91. package/lib/lifecycle/types.d.ts +88 -0
  92. package/lib/lifecycle/types.js +2 -0
  93. package/lib/lifecycle/types.js.map +1 -0
  94. package/lib/lifecycle/userDiff.d.ts +70 -0
  95. package/lib/lifecycle/userDiff.js +393 -0
  96. package/lib/lifecycle/userDiff.js.map +1 -0
  97. package/lib/matching/index.d.ts +53 -0
  98. package/lib/matching/index.js +181 -0
  99. package/lib/matching/index.js.map +1 -0
  100. package/lib/provisioning/assignmentPlan.d.ts +53 -0
  101. package/lib/provisioning/assignmentPlan.js +90 -0
  102. package/lib/provisioning/assignmentPlan.js.map +1 -0
  103. package/lib/provisioning/definitionReader.d.ts +38 -0
  104. package/lib/provisioning/definitionReader.js +77 -0
  105. package/lib/provisioning/definitionReader.js.map +1 -0
  106. package/lib/provisioning/errors.d.ts +9 -0
  107. package/lib/provisioning/errors.js +14 -0
  108. package/lib/provisioning/errors.js.map +1 -0
  109. package/lib/provisioning/licenseUsage.d.ts +15 -0
  110. package/lib/provisioning/licenseUsage.js +53 -0
  111. package/lib/provisioning/licenseUsage.js.map +1 -0
  112. package/lib/provisioning/messages.d.ts +4 -0
  113. package/lib/provisioning/messages.js +72 -0
  114. package/lib/provisioning/messages.js.map +1 -0
  115. package/lib/provisioning/planner.d.ts +63 -0
  116. package/lib/provisioning/planner.js +407 -0
  117. package/lib/provisioning/planner.js.map +1 -0
  118. package/lib/provisioning/provisionUserUseCase.d.ts +52 -0
  119. package/lib/provisioning/provisionUserUseCase.js +200 -0
  120. package/lib/provisioning/provisionUserUseCase.js.map +1 -0
  121. package/lib/provisioning/referenceResolution.d.ts +4 -0
  122. package/lib/provisioning/referenceResolution.js +173 -0
  123. package/lib/provisioning/referenceResolution.js.map +1 -0
  124. package/lib/provisioning/userPlan.d.ts +85 -0
  125. package/lib/provisioning/userPlan.js +162 -0
  126. package/lib/provisioning/userPlan.js.map +1 -0
  127. package/lib/provisioning/userSave.d.ts +24 -0
  128. package/lib/provisioning/userSave.js +119 -0
  129. package/lib/provisioning/userSave.js.map +1 -0
  130. package/lib/relatedRecords/apply.d.ts +18 -0
  131. package/lib/relatedRecords/apply.js +121 -0
  132. package/lib/relatedRecords/apply.js.map +1 -0
  133. package/lib/relatedRecords/catalog.d.ts +7 -0
  134. package/lib/relatedRecords/catalog.js +108 -0
  135. package/lib/relatedRecords/catalog.js.map +1 -0
  136. package/lib/relatedRecords/errors.d.ts +5 -0
  137. package/lib/relatedRecords/errors.js +8 -0
  138. package/lib/relatedRecords/errors.js.map +1 -0
  139. package/lib/relatedRecords/messages.d.ts +1 -0
  140. package/lib/relatedRecords/messages.js +2 -0
  141. package/lib/relatedRecords/messages.js.map +1 -0
  142. package/lib/relatedRecords/plan.d.ts +22 -0
  143. package/lib/relatedRecords/plan.js +271 -0
  144. package/lib/relatedRecords/plan.js.map +1 -0
  145. package/lib/relatedRecords/preflight.d.ts +29 -0
  146. package/lib/relatedRecords/preflight.js +164 -0
  147. package/lib/relatedRecords/preflight.js.map +1 -0
  148. package/lib/relatedRecords/sources.d.ts +25 -0
  149. package/lib/relatedRecords/sources.js +65 -0
  150. package/lib/relatedRecords/sources.js.map +1 -0
  151. package/lib/relatedRecords/types.d.ts +46 -0
  152. package/lib/relatedRecords/types.js +2 -0
  153. package/lib/relatedRecords/types.js.map +1 -0
  154. package/lib/shared/csv.d.ts +26 -0
  155. package/lib/shared/csv.js +237 -0
  156. package/lib/shared/csv.js.map +1 -0
  157. package/lib/shared/output.d.ts +25 -0
  158. package/lib/shared/output.js +74 -0
  159. package/lib/shared/output.js.map +1 -0
  160. package/lib/shared/prompt.d.ts +4 -0
  161. package/lib/shared/prompt.js +15 -0
  162. package/lib/shared/prompt.js.map +1 -0
  163. package/lib/shared/sfUtils.d.ts +19 -0
  164. package/lib/shared/sfUtils.js +42 -0
  165. package/lib/shared/sfUtils.js.map +1 -0
  166. package/lib/shared/userFields.d.ts +23 -0
  167. package/lib/shared/userFields.js +41 -0
  168. package/lib/shared/userFields.js.map +1 -0
  169. package/lib/spec/index.d.ts +10 -0
  170. package/lib/spec/index.js +6 -0
  171. package/lib/spec/index.js.map +1 -0
  172. package/lib/spec/parse.d.ts +32 -0
  173. package/lib/spec/parse.js +77 -0
  174. package/lib/spec/parse.js.map +1 -0
  175. package/lib/spec/personaDefinitions.d.ts +56 -0
  176. package/lib/spec/personaDefinitions.js +25 -0
  177. package/lib/spec/personaDefinitions.js.map +1 -0
  178. package/lib/spec/relatedCatalog.d.ts +61 -0
  179. package/lib/spec/relatedCatalog.js +32 -0
  180. package/lib/spec/relatedCatalog.js.map +1 -0
  181. package/lib/spec/snapshot.d.ts +42 -0
  182. package/lib/spec/snapshot.js +32 -0
  183. package/lib/spec/snapshot.js.map +1 -0
  184. package/lib/spec/usersDefinition.d.ts +19 -0
  185. package/lib/spec/usersDefinition.js +21 -0
  186. package/lib/spec/usersDefinition.js.map +1 -0
  187. package/package.json +78 -0
  188. package/schemas/persona-definitions.schema.json +108 -0
  189. package/schemas/related-catalog.schema.json +141 -0
  190. package/schemas/snapshot.schema.json +128 -0
  191. package/schemas/users-definition.schema.json +36 -0
@@ -0,0 +1,271 @@
1
+ import { esc, soqlIn } from '../shared/sfUtils.js';
2
+ import { resolveSource } from './sources.js';
3
+ import { relatedRecordsMessage } from './messages.js';
4
+ /** Salesforce accepts at most 200 records per create/update request. */
5
+ export const RELATED_DML_CHUNK_SIZE = 200;
6
+ const MATCH_QUERY_CHUNK_SIZE = 200;
7
+ const MATCH_QUERY_MAX_LENGTH = 18_000;
8
+ const matchGroupKey = (sobject, matchField) => `${sobject.toLowerCase()}|${matchField.toLowerCase()}`;
9
+ const matchValueKey = (value, def, preflight) => {
10
+ const matchField = preflight.fieldsBySobject.get(def.sobject.toLowerCase())?.get(def.match.field.toLowerCase());
11
+ return matchField?.caseSensitive === false ? value.toLowerCase() : value;
12
+ };
13
+ /**
14
+ * A value is "empty" only when it is literally null or the empty string. A
15
+ * whitespace-only value counts as populated and is preserved by `setIfEmpty`.
16
+ */
17
+ const isEmptyExistingValue = (value) => value === null || value === '';
18
+ const canonicalFieldName = (field, fieldMap) => fieldMap?.get(field.toLowerCase())?.name ?? field;
19
+ /** Split IN-list values at Salesforce's count and query-text limits. */
20
+ const matchQueryBatches = (values, prefix) => {
21
+ const batches = [];
22
+ let current = [];
23
+ let currentLength = prefix.length + 1; // Closing parenthesis.
24
+ for (const value of values) {
25
+ const renderedLength = `'${esc(value)}'`.length;
26
+ const nextLength = currentLength + (current.length > 0 ? 1 : 0) + renderedLength;
27
+ if (current.length > 0 && (current.length === MATCH_QUERY_CHUNK_SIZE || nextLength > MATCH_QUERY_MAX_LENGTH)) {
28
+ batches.push(current);
29
+ current = [];
30
+ currentLength = prefix.length + 1;
31
+ }
32
+ current.push(value);
33
+ currentLength += (current.length > 1 ? 1 : 0) + renderedLength;
34
+ }
35
+ if (current.length > 0)
36
+ batches.push(current);
37
+ return batches;
38
+ };
39
+ const toErrorMessage = (message, error) => message(error.code, error.messageArgs);
40
+ const selectFieldsFor = (defs, fieldMap) => {
41
+ const names = new Set(['Id']);
42
+ if (fieldMap?.has('recordtypeid'))
43
+ names.add('RecordTypeId');
44
+ for (const def of defs) {
45
+ names.add(canonicalFieldName(def.match.field, fieldMap));
46
+ for (const field of Object.keys(def.fields))
47
+ names.add(canonicalFieldName(field, fieldMap));
48
+ }
49
+ return [...names];
50
+ };
51
+ const skippedPlan = (relationship, def) => ({
52
+ relationship,
53
+ phase: 'after',
54
+ sobject: def.sobject,
55
+ matchField: def.match.field,
56
+ fields: {},
57
+ pendingUserIdFields: [],
58
+ mode: def.mode ?? 'setIfEmpty',
59
+ status: 'skipped',
60
+ errors: [],
61
+ });
62
+ const failedPlan = (relationship, def, errors) => ({
63
+ ...skippedPlan(relationship, def),
64
+ status: 'failed',
65
+ errors,
66
+ });
67
+ /** Resolve each user's match value; a resolution failure fails that user's plan only. */
68
+ const resolveMatchValues = (options) => {
69
+ const { users, catalog, preflight, userFieldMap, message } = options;
70
+ const pending = [];
71
+ const plansByOrder = new Map();
72
+ for (const { user, order } of users) {
73
+ const plans = [];
74
+ for (const relationship of user.related ?? []) {
75
+ const def = catalog.relationships[relationship];
76
+ if (!def)
77
+ continue;
78
+ if (!preflight.eligible.has(relationship)) {
79
+ plans.push(skippedPlan(relationship, def));
80
+ continue;
81
+ }
82
+ const resolved = resolveSource({ from: def.match.from }, { relationship, fieldName: 'match.from', userFields: user.fields, userFieldMap });
83
+ if (resolved.error) {
84
+ plans.push(failedPlan(relationship, def, [toErrorMessage(message, resolved.error)]));
85
+ continue;
86
+ }
87
+ const matchValue = String(resolved.value);
88
+ plans.push({
89
+ ...skippedPlan(relationship, def),
90
+ matchField: canonicalFieldName(def.match.field, preflight.fieldsBySobject.get(def.sobject.toLowerCase())),
91
+ status: 'planned',
92
+ matchValue,
93
+ });
94
+ pending.push({ order, relationship, def, matchValue });
95
+ }
96
+ if (plans.length > 0)
97
+ plansByOrder.set(order, plans);
98
+ }
99
+ return { pending, plansByOrder };
100
+ };
101
+ /** One bulk query per (sObject, match field) across the whole batch, never per user. */
102
+ const queryExistingRecords = async (conn, pending, preflight) => {
103
+ const groups = new Map();
104
+ for (const entry of pending) {
105
+ const key = matchGroupKey(entry.def.sobject, entry.def.match.field);
106
+ const group = groups.get(key) ?? { defs: [], values: new Set() };
107
+ if (!group.defs.includes(entry.def))
108
+ group.defs.push(entry.def);
109
+ group.values.add(entry.matchValue);
110
+ groups.set(key, group);
111
+ }
112
+ // Reads go through conn.query so dry runs never touch conn.sobject(...).
113
+ const grouped = await Promise.all([...groups].map(async ([key, group]) => {
114
+ const primaryDef = group.defs[0];
115
+ const fieldMap = preflight.fieldsBySobject.get(primaryDef.sobject.toLowerCase());
116
+ const select = selectFieldsFor(group.defs, fieldMap).join(', ');
117
+ const matchField = canonicalFieldName(primaryDef.match.field, fieldMap);
118
+ const prefix = `SELECT ${select} FROM ${primaryDef.sobject} WHERE ${matchField} IN (`;
119
+ const rows = (await Promise.all(matchQueryBatches([...group.values], prefix).map(async (chunk) => (await conn.query(`${prefix}${soqlIn(chunk)})`)).records))).flat();
120
+ const byValue = new Map();
121
+ for (const row of rows) {
122
+ const rowValue = row[matchField];
123
+ if (rowValue === undefined || rowValue === null)
124
+ continue;
125
+ const valueKey = matchValueKey(String(rowValue), primaryDef, preflight);
126
+ byValue.set(valueKey, (byValue.get(valueKey) ?? []).concat(row));
127
+ }
128
+ return [key, byValue];
129
+ }));
130
+ return new Map(grouped);
131
+ };
132
+ const applyModeFilter = (fields, existing, mode) => {
133
+ if (!existing || mode === 'sync')
134
+ return fields;
135
+ return Object.fromEntries(Object.entries(fields).filter(([name]) => isEmptyExistingValue(existing[name])));
136
+ };
137
+ /** Check only fields that this individual create or update will actually send. */
138
+ const assertPlannedFieldsWritable = (plan, fieldMap, message) => {
139
+ const requiredPermission = plan.existingId ? 'updateable' : 'createable';
140
+ const unavailable = [...Object.keys(plan.fields), ...plan.pendingUserIdFields].filter((field) => {
141
+ const meta = fieldMap.get(field.toLowerCase());
142
+ return meta ? !meta[requiredPermission] : false;
143
+ });
144
+ if (unavailable.length > 0) {
145
+ plan.status = 'failed';
146
+ plan.errors.push(message('errorRelatedFieldsNotWritableForOperation', [plan.sobject, unavailable.join(', '), requiredPermission]));
147
+ }
148
+ };
149
+ const resolveConfiguredFields = (options) => {
150
+ const { relationship, def, user, userFieldMap, targetFieldMap, message } = options;
151
+ const fields = {};
152
+ const pendingUserIdFields = [];
153
+ const errors = [];
154
+ for (const [fieldName, expr] of Object.entries(def.fields)) {
155
+ const resolved = resolveSource(expr, { relationship, fieldName, userFields: user.fields, userFieldMap });
156
+ if (resolved.error)
157
+ errors.push(toErrorMessage(message, resolved.error));
158
+ else if (resolved.pending)
159
+ pendingUserIdFields.push(canonicalFieldName(fieldName, targetFieldMap));
160
+ else
161
+ fields[canonicalFieldName(fieldName, targetFieldMap)] = resolved.value;
162
+ }
163
+ return { fields, pendingUserIdFields, errors };
164
+ };
165
+ const finalizePlan = (options) => {
166
+ const { plan, def, user, userFieldMap, targetFieldMap, matches, recordTypeId, message } = options;
167
+ const matchValue = plan.matchValue;
168
+ if (matches.length > 1) {
169
+ plan.status = 'failed';
170
+ plan.errors.push(message('errorAmbiguousRelatedMatch', [plan.relationship, def.sobject, def.match.field, matchValue]));
171
+ return;
172
+ }
173
+ const existing = matches[0];
174
+ const resolved = resolveConfiguredFields({
175
+ relationship: plan.relationship,
176
+ def,
177
+ user,
178
+ userFieldMap,
179
+ targetFieldMap,
180
+ message,
181
+ });
182
+ if (resolved.errors.length > 0) {
183
+ plan.status = 'failed';
184
+ plan.errors.push(...resolved.errors);
185
+ return;
186
+ }
187
+ if (existing) {
188
+ plan.existingId = existing.Id;
189
+ plan.existingValues = { ...existing };
190
+ if (recordTypeId && existing.RecordTypeId !== recordTypeId) {
191
+ plan.status = 'failed';
192
+ plan.errors.push(message('errorRelatedRecordTypeMismatch', [plan.relationship, def.sobject, def.recordType?.developerName ?? '']));
193
+ return;
194
+ }
195
+ }
196
+ else if (recordTypeId) {
197
+ // RecordTypeId is written on create only; warden never retags an existing record.
198
+ plan.recordTypeId = recordTypeId;
199
+ }
200
+ const filtered = applyModeFilter(resolved.fields, existing, plan.mode);
201
+ // A create always writes the match field, so a re-run can match what this run created.
202
+ plan.fields = existing
203
+ ? filtered
204
+ : { ...filtered, [canonicalFieldName(def.match.field, targetFieldMap)]: matchValue };
205
+ // `user.Id` fields are filled in after the User save, so they carry the same mode
206
+ // filtering the resolved fields already went through.
207
+ plan.pendingUserIdFields =
208
+ existing && plan.mode === 'setIfEmpty'
209
+ ? resolved.pendingUserIdFields.filter((name) => isEmptyExistingValue(existing[name]))
210
+ : resolved.pendingUserIdFields;
211
+ assertPlannedFieldsWritable(plan, targetFieldMap, message);
212
+ };
213
+ /** Fail every plan that shares a `(relationship, match value)` with another plan. */
214
+ const applyCollisionCheck = (plansByOrder, catalog, preflight, message) => {
215
+ const byKey = new Map();
216
+ for (const plans of plansByOrder.values()) {
217
+ for (const plan of plans) {
218
+ if (plan.status !== 'planned' || plan.matchValue === undefined)
219
+ continue;
220
+ const def = catalog.relationships[plan.relationship];
221
+ const key = `${plan.relationship} ${matchValueKey(plan.matchValue, def, preflight)}`;
222
+ byKey.set(key, (byKey.get(key) ?? []).concat(plan));
223
+ }
224
+ }
225
+ for (const colliding of byKey.values()) {
226
+ if (colliding.length < 2)
227
+ continue;
228
+ for (const plan of colliding) {
229
+ plan.status = 'failed';
230
+ plan.errors.push(message('errorRelatedMatchCollision', [plan.relationship, plan.matchField, plan.matchValue]));
231
+ }
232
+ }
233
+ };
234
+ /**
235
+ * Build every user's `after`-phase related-record plans for the batch.
236
+ *
237
+ * Matching is a read, so this is safe in a dry run; the returned plans carry no DML.
238
+ */
239
+ export const buildRelatedPlans = async (options) => {
240
+ const { conn, users, catalog, preflight, userFieldMap, message = relatedRecordsMessage } = options;
241
+ const { pending, plansByOrder } = resolveMatchValues({ users, catalog, preflight, userFieldMap, message });
242
+ if (plansByOrder.size === 0)
243
+ return plansByOrder;
244
+ const index = await queryExistingRecords(conn, pending, preflight);
245
+ const usersByOrder = new Map(users.map(({ user, order }) => [order, user]));
246
+ for (const [order, plans] of plansByOrder) {
247
+ const user = usersByOrder.get(order);
248
+ if (!user)
249
+ continue;
250
+ for (const plan of plans) {
251
+ if (plan.status !== 'planned' || plan.matchValue === undefined)
252
+ continue;
253
+ const def = catalog.relationships[plan.relationship];
254
+ const matches = index.get(matchGroupKey(def.sobject, def.match.field))?.get(matchValueKey(plan.matchValue, def, preflight)) ??
255
+ [];
256
+ finalizePlan({
257
+ plan,
258
+ def,
259
+ user,
260
+ userFieldMap,
261
+ targetFieldMap: preflight.fieldsBySobject.get(def.sobject.toLowerCase()) ?? new Map(),
262
+ matches,
263
+ recordTypeId: preflight.recordTypeIdByRelationship.get(plan.relationship),
264
+ message,
265
+ });
266
+ }
267
+ }
268
+ applyCollisionCheck(plansByOrder, catalog, preflight, message);
269
+ return plansByOrder;
270
+ };
271
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/relatedRecords/plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { Connection } from '@salesforce/core';
2
+ import type { UserFieldMeta } from '../provisioning/planner.js';
3
+ import { type SobjectDescribeCache } from '../shared/userFields.js';
4
+ import type { RelatedCatalog, RelatedMessage } from './types.js';
5
+ export type RelatedPreflightResult = {
6
+ eligible: Set<string>;
7
+ ineligible: Map<string, string>;
8
+ warnings: string[];
9
+ /** Field metadata for every relationship sObject that could be described. */
10
+ fieldsBySobject: Map<string, Map<string, UserFieldMeta>>;
11
+ /** Resolved `RecordTypeId` per relationship name, when the relationship declares one. */
12
+ recordTypeIdByRelationship: Map<string, string>;
13
+ };
14
+ export declare const emptyPreflightResult: () => RelatedPreflightResult;
15
+ /**
16
+ * Validate every relationship at least one user selected, once per batch.
17
+ *
18
+ * Ineligible relationships become warning lines rather than errors: they flow into the
19
+ * single `acknowledgeWarnings` confirmation the command already issues, so confirming
20
+ * skips them, declining exits before any DML, and `--no-prompt`/JSON runs skip
21
+ * automatically.
22
+ */
23
+ export declare const runRelatedPreflight: (options: {
24
+ conn: Connection;
25
+ catalog: RelatedCatalog;
26
+ selected: string[];
27
+ cache: SobjectDescribeCache;
28
+ message?: RelatedMessage;
29
+ }) => Promise<RelatedPreflightResult>;
@@ -0,0 +1,164 @@
1
+ import { soqlIn } from '../shared/sfUtils.js';
2
+ import { describeSobject } from '../shared/userFields.js';
3
+ import { relatedRecordsMessage } from './messages.js';
4
+ export const emptyPreflightResult = () => ({
5
+ eligible: new Set(),
6
+ ineligible: new Map(),
7
+ warnings: [],
8
+ fieldsBySobject: new Map(),
9
+ recordTypeIdByRelationship: new Map(),
10
+ });
11
+ /**
12
+ * An `Account` relationship must accept either spelling of the record type's owning
13
+ * sObject.
14
+ *
15
+ * Confirmed against a person-accounts-enabled org: `RecordType.SobjectType` reads
16
+ * `Account` there, not `PersonAccount`, so the extra alias is currently unused. It is
17
+ * kept because it costs one IN value and guards the other spelling.
18
+ */
19
+ const sobjectAliases = (sobject) => sobject.toLowerCase() === 'account' ? ['Account', 'PersonAccount'] : [sobject];
20
+ /**
21
+ * `RecordType.IsPersonType` only exists when the org has person accounts enabled --
22
+ * selecting it elsewhere fails the whole query with `No such column 'IsPersonType'`,
23
+ * which would take down record-type resolution for every relationship. So it is only
24
+ * requested once the Account describe has shown person accounts to be on.
25
+ */
26
+ const queryRecordTypes = async (conn, requests, personAccountsEnabled) => {
27
+ if (requests.length === 0)
28
+ return [];
29
+ const sobjects = [...new Set(requests.flatMap((request) => sobjectAliases(request.sobject)))];
30
+ const developerNames = [...new Set(requests.map((request) => request.developerName))];
31
+ const columns = [
32
+ 'Id',
33
+ 'DeveloperName',
34
+ 'SobjectType',
35
+ 'IsActive',
36
+ ...(personAccountsEnabled ? ['IsPersonType'] : []),
37
+ ];
38
+ const soql = `SELECT ${columns.join(', ')} FROM RecordType ` +
39
+ `WHERE SobjectType IN (${soqlIn(sobjects)}) AND DeveloperName IN (${soqlIn(developerNames)})`;
40
+ return (await conn.query(soql)).records;
41
+ };
42
+ /**
43
+ * `Account.IsPersonAccount` exists only when person accounts are enabled, which makes it
44
+ * the cheapest reliable signal -- the Account describe is already in hand.
45
+ */
46
+ const hasPersonAccounts = (described) => described?.fields.has('ispersonaccount') === true;
47
+ const missingFields = (def, fieldMap) => [def.match.field, ...Object.keys(def.fields)].filter((field) => !fieldMap.has(field.toLowerCase()));
48
+ const unwritableFields = (def, fieldMap) => Object.keys(def.fields).filter((field) => {
49
+ const meta = fieldMap.get(field.toLowerCase());
50
+ return meta ? !meta.createable && !meta.updateable : false;
51
+ });
52
+ const unreadableFields = (def, fieldMap) => [def.match.field, ...Object.keys(def.fields)].filter((field) => fieldMap.get(field.toLowerCase())?.readable === false);
53
+ const describeOrUndefined = async (conn, sobject, cache) => {
54
+ try {
55
+ return await describeSobject(conn, sobject, cache);
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
60
+ };
61
+ /**
62
+ * The REST describe omits `isPersonType` from `recordTypeInfos` -- verified absent at
63
+ * API v67.0 in a person-accounts-enabled org, for every Account record type including
64
+ * the person one. Reading it there silently rejects every Account relationship, so the
65
+ * SOQL `IsPersonType` is the primary source and the describe flag is only a fallback for
66
+ * describes that do carry it.
67
+ */
68
+ const isEligiblePersonAccountRecordType = (def, described, id, row) => {
69
+ if (def.sobject.toLowerCase() !== 'account')
70
+ return true;
71
+ const recordType = described.recordTypeInfos.get(id);
72
+ if (recordType?.available !== true)
73
+ return false;
74
+ return row.IsPersonType === true || recordType.isPersonType === true;
75
+ };
76
+ const checkFieldMetadata = (def, fieldMap, message) => {
77
+ const missing = missingFields(def, fieldMap);
78
+ if (missing.length > 0)
79
+ return message('errorRelatedUnknownFields', [def.sobject, missing.join(', ')]);
80
+ const matchMeta = fieldMap.get(def.match.field.toLowerCase());
81
+ if (!matchMeta?.filterable || !(matchMeta.externalId === true || matchMeta.unique === true)) {
82
+ return message('errorRelatedMatchFieldNotUnique', [def.match.field, def.sobject]);
83
+ }
84
+ const unreadable = unreadableFields(def, fieldMap);
85
+ if (unreadable.length > 0)
86
+ return message('errorRelatedFieldsNotReadable', [def.sobject, unreadable.join(', ')]);
87
+ const unwritable = unwritableFields(def, fieldMap);
88
+ if (unwritable.length > 0)
89
+ return message('errorRelatedFieldsNotWritable', [def.sobject, unwritable.join(', ')]);
90
+ return undefined;
91
+ };
92
+ /**
93
+ * Validate every relationship at least one user selected, once per batch.
94
+ *
95
+ * Ineligible relationships become warning lines rather than errors: they flow into the
96
+ * single `acknowledgeWarnings` confirmation the command already issues, so confirming
97
+ * skips them, declining exits before any DML, and `--no-prompt`/JSON runs skip
98
+ * automatically.
99
+ */
100
+ export const runRelatedPreflight = async (options) => {
101
+ const { conn, catalog, selected, cache, message = relatedRecordsMessage } = options;
102
+ const result = emptyPreflightResult();
103
+ const names = [...new Set(selected)].filter((name) => Boolean(catalog.relationships[name]));
104
+ if (names.length === 0)
105
+ return result;
106
+ const describedByName = new Map();
107
+ for (const name of names) {
108
+ const def = catalog.relationships[name];
109
+ // Sequential so the describe cache is shared between relationships on one sObject.
110
+ // eslint-disable-next-line no-await-in-loop
111
+ describedByName.set(name, await describeOrUndefined(conn, def.sobject, cache));
112
+ }
113
+ const recordTypeRequests = names
114
+ .filter((name) => catalog.relationships[name].recordType)
115
+ .map((name) => ({
116
+ sobject: catalog.relationships[name].sobject,
117
+ developerName: catalog.relationships[name].recordType.developerName,
118
+ }));
119
+ const recordTypeRows = await queryRecordTypes(conn, recordTypeRequests, names.some((name) => catalog.relationships[name].sobject.toLowerCase() === 'account' && hasPersonAccounts(describedByName.get(name))));
120
+ for (const name of names) {
121
+ const def = catalog.relationships[name];
122
+ const described = describedByName.get(name);
123
+ if (!described) {
124
+ result.ineligible.set(name, message('errorRelatedSobjectUnavailable', [def.sobject]));
125
+ continue;
126
+ }
127
+ result.fieldsBySobject.set(def.sobject.toLowerCase(), described.fields);
128
+ if (!described.queryable) {
129
+ result.ineligible.set(name, message('errorRelatedSobjectNotQueryable', [def.sobject]));
130
+ continue;
131
+ }
132
+ const fieldProblem = checkFieldMetadata(def, described.fields, message);
133
+ if (fieldProblem) {
134
+ result.ineligible.set(name, fieldProblem);
135
+ continue;
136
+ }
137
+ if (def.sobject.toLowerCase() === 'account' && !def.recordType) {
138
+ result.ineligible.set(name, message('errorRelatedPersonAccountRecordTypeRequired', [def.sobject]));
139
+ continue;
140
+ }
141
+ if (def.recordType) {
142
+ const allowed = new Set(sobjectAliases(def.sobject).map((alias) => alias.toLowerCase()));
143
+ const row = recordTypeRows.find((candidate) => candidate.DeveloperName === def.recordType.developerName &&
144
+ allowed.has(String(candidate.SobjectType).toLowerCase()) &&
145
+ candidate.IsActive !== false);
146
+ if (!row) {
147
+ result.ineligible.set(name, message('errorRelatedRecordTypeUnavailable', [def.recordType.developerName, def.sobject]));
148
+ continue;
149
+ }
150
+ if (!isEligiblePersonAccountRecordType(def, described, row.Id, row)) {
151
+ result.ineligible.set(name, message('errorRelatedRecordTypeUnavailable', [def.recordType.developerName, def.sobject]));
152
+ continue;
153
+ }
154
+ result.recordTypeIdByRelationship.set(name, row.Id);
155
+ }
156
+ result.eligible.add(name);
157
+ }
158
+ // One aggregated warning line per ineligible relationship, never one per user.
159
+ for (const [name, reason] of result.ineligible) {
160
+ result.warnings.push(message('warningRelationshipSkipped', [name, reason]));
161
+ }
162
+ return result;
163
+ };
164
+ //# sourceMappingURL=preflight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../src/relatedRecords/preflight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { UserFieldMeta, ValidationError } from '../provisioning/planner.js';
2
+ import type { ParsedSource, SourceExpr } from './types.js';
3
+ /** Split a source expression string into the shape the resolver dispatches on. */
4
+ export declare const parseSource: (from: unknown) => ParsedSource;
5
+ export declare const isSourceExpr: (value: unknown) => value is SourceExpr;
6
+ export type SourceContext = {
7
+ relationship: string;
8
+ fieldName: string;
9
+ userFields: Record<string, unknown>;
10
+ userFieldMap: Map<string, UserFieldMeta>;
11
+ savedUserId?: string;
12
+ };
13
+ export type SourceResolution = {
14
+ value?: unknown;
15
+ /** True when the source is `user.Id` and the User has not been saved yet. */
16
+ pending?: boolean;
17
+ error?: ValidationError;
18
+ };
19
+ /**
20
+ * Resolve one configured field source against a canonicalized user.
21
+ *
22
+ * Syntax problems and unknown `User` fields are caught during catalog validation, so
23
+ * anything reported here is per-user: a known source whose effective value is absent.
24
+ */
25
+ export declare const resolveSource: (expr: SourceExpr, ctx: SourceContext) => SourceResolution;
@@ -0,0 +1,65 @@
1
+ const USER_SOURCE_PREFIX = 'user.';
2
+ const CONTEXT_SOURCE_PREFIX = 'context.';
3
+ /** Split a source expression string into the shape the resolver dispatches on. */
4
+ export const parseSource = (from) => {
5
+ if (typeof from !== 'string')
6
+ return { kind: 'invalid' };
7
+ const trimmed = from.trim();
8
+ if (trimmed.toLowerCase().startsWith(CONTEXT_SOURCE_PREFIX)) {
9
+ const name = trimmed.slice(CONTEXT_SOURCE_PREFIX.length);
10
+ return name.length > 0 ? { kind: 'context', name } : { kind: 'invalid' };
11
+ }
12
+ if (!trimmed.toLowerCase().startsWith(USER_SOURCE_PREFIX))
13
+ return { kind: 'invalid' };
14
+ const field = trimmed.slice(USER_SOURCE_PREFIX.length);
15
+ if (field.length === 0 || field.includes('.'))
16
+ return { kind: 'invalid' };
17
+ return field.toLowerCase() === 'id' ? { kind: 'userId' } : { kind: 'userField', field };
18
+ };
19
+ export const isSourceExpr = (value) => {
20
+ if (!value || typeof value !== 'object' || Array.isArray(value))
21
+ return false;
22
+ const entry = value;
23
+ const hasFrom = 'from' in entry;
24
+ const hasValue = 'value' in entry;
25
+ return Object.keys(entry).length === 1 && hasFrom !== hasValue;
26
+ };
27
+ /**
28
+ * A value is "absent" only when it is literally undefined, null, or the empty string.
29
+ * `0` and `false` are values, not absences, so this must never be written as a falsy test.
30
+ */
31
+ const isAbsent = (value) => value === undefined || value === null || value === '';
32
+ /**
33
+ * Resolve one configured field source against a canonicalized user.
34
+ *
35
+ * Syntax problems and unknown `User` fields are caught during catalog validation, so
36
+ * anything reported here is per-user: a known source whose effective value is absent.
37
+ */
38
+ export const resolveSource = (expr, ctx) => {
39
+ if ('value' in expr)
40
+ return { value: expr.value };
41
+ const parsed = parseSource(expr.from);
42
+ if (parsed.kind === 'userId') {
43
+ return ctx.savedUserId ? { value: ctx.savedUserId } : { pending: true };
44
+ }
45
+ if (parsed.kind !== 'userField') {
46
+ return {
47
+ error: {
48
+ code: 'errorRelatedInvalidSourceValue',
49
+ messageArgs: [ctx.relationship, ctx.fieldName, String(expr.from)],
50
+ },
51
+ };
52
+ }
53
+ const canonical = ctx.userFieldMap.get(parsed.field.toLowerCase())?.name ?? parsed.field;
54
+ const value = ctx.userFields[canonical];
55
+ if (isAbsent(value)) {
56
+ return {
57
+ error: {
58
+ code: 'errorRelatedSourceEmpty',
59
+ messageArgs: [ctx.relationship, ctx.fieldName, canonical],
60
+ },
61
+ };
62
+ }
63
+ return { value };
64
+ };
65
+ //# sourceMappingURL=sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.js","sourceRoot":"","sources":["../../src/relatedRecords/sources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Catalog, plan, and result shapes for `--related-def` relationships.
3
+ *
4
+ * `phase` is typed as the full union even though v1 only accepts `'after'`, so
5
+ * adding `'before'` support later is a validator change rather than a type change.
6
+ */
7
+ export type { RelatedCatalog, RelationshipDef, RelationshipMode, RelationshipPhase, SourceExpr, } from '../spec/relatedCatalog.js';
8
+ import type { RelationshipMode } from '../spec/relatedCatalog.js';
9
+ /** A source expression parsed into the shape the resolver dispatches on. */
10
+ export type ParsedSource = {
11
+ kind: 'userId';
12
+ } | {
13
+ kind: 'userField';
14
+ field: string;
15
+ } | {
16
+ kind: 'context';
17
+ name: string;
18
+ } | {
19
+ kind: 'invalid';
20
+ };
21
+ export type RelatedRecordPlan = {
22
+ relationship: string;
23
+ phase: 'after';
24
+ sobject: string;
25
+ matchField: string;
26
+ matchValue?: string;
27
+ existingId?: string;
28
+ existingValues?: Record<string, unknown>;
29
+ fields: Record<string, unknown>;
30
+ pendingUserIdFields: string[];
31
+ recordTypeId?: string;
32
+ mode: RelationshipMode;
33
+ status: 'planned' | 'skipped' | 'failed';
34
+ errors: string[];
35
+ };
36
+ export type RelatedRecordResult = {
37
+ relationship: string;
38
+ phase: 'after';
39
+ sobject: string;
40
+ recordId?: string;
41
+ action: 'created' | 'updated' | 'matched' | 'skipped' | 'wouldCreate' | 'wouldUpdate' | 'wouldSkip';
42
+ status: 'applied' | 'planned' | 'skipped' | 'failed';
43
+ detail?: string;
44
+ error?: string;
45
+ };
46
+ export type RelatedMessage = (key: string, args?: string[]) => string;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map