@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,393 @@
1
+ import { validateAndCanonicalizeUsers, validateExternalIdFieldForFlag, validatePersonaModes, } from '../provisioning/planner.js';
2
+ import { getExistingUsers } from '../provisioning/provisionUserUseCase.js';
3
+ import { buildTarget } from '../provisioning/userPlan.js';
4
+ import { resolveReferences } from '../provisioning/referenceResolution.js';
5
+ import { computeAssignmentDeltaFromState, extractCurrentIds, } from '../provisioning/assignmentPlan.js';
6
+ import { batch, soqlIn } from '../shared/sfUtils.js';
7
+ import { describeUserFields } from '../shared/userFields.js';
8
+ import { loadValidatedDefinitions, } from '../provisioning/definitionReader.js';
9
+ import { matchKey } from '../matching/index.js';
10
+ import { groupMemberLabel, loadAssignmentState, permissionSetAssignmentLabel, } from './assignmentState.js';
11
+ import { parseUserFlag, resolveTargetField, resolveTargets } from './targeting.js';
12
+ import { LifecycleError } from './errors.js';
13
+ import { lifecycleMessage } from './messages.js';
14
+ const diffDefinitionMessages = {
15
+ invalidPersonaDefinition: () => lifecycleMessage('errorInvalidPersonaDefinition'),
16
+ personasWithoutDefinition: (userKey) => lifecycleMessage('errorPersonasWithoutDefinition', [userKey]),
17
+ invalidJson: (path, error) => lifecycleMessage('errorInvalidJson', [path, error]),
18
+ };
19
+ const QUERY_BATCH_SIZE = 100;
20
+ const emptyCategory = (mode) => ({
21
+ adds: [],
22
+ removes: [],
23
+ inBoth: [],
24
+ onlyInOrg: [],
25
+ ...(mode ? { mode } : {}),
26
+ });
27
+ const emptyAssignments = () => ({
28
+ permissionSets: emptyCategory(),
29
+ permissionSetGroups: emptyCategory(),
30
+ publicGroups: emptyCategory(),
31
+ queues: emptyCategory(),
32
+ });
33
+ const summarize = (users) => ({
34
+ total: users.length,
35
+ compared: users.filter((user) => user.status === 'compared').length,
36
+ wouldCreate: users.filter((user) => user.status === 'would-create').length,
37
+ failed: users.filter((user) => user.status === 'failed').length,
38
+ changed: users.filter(hasChanges).length,
39
+ });
40
+ const hasCategoryChanges = (category) => category.adds.length > 0 || category.removes.length > 0;
41
+ const hasChanges = (user) => user.status !== 'failed' &&
42
+ (!user.profile.matches ||
43
+ !user.role.matches ||
44
+ hasCategoryChanges(user.assignments.permissionSets) ||
45
+ hasCategoryChanges(user.assignments.permissionSetGroups) ||
46
+ hasCategoryChanges(user.assignments.publicGroups) ||
47
+ hasCategoryChanges(user.assignments.queues));
48
+ const rowsForUser = (user) => {
49
+ const rows = [];
50
+ const identity = { userName: user.userName ?? '', username: user.username ?? '' };
51
+ const pushCategory = (category, delta) => {
52
+ for (const kind of ['adds', 'removes', 'inBoth', 'onlyInOrg']) {
53
+ const rowKind = kind === 'adds' ? 'add' : kind === 'removes' ? 'remove' : kind;
54
+ for (const value of delta[kind]) {
55
+ rows.push({
56
+ userKey: user.key,
57
+ userId: user.id ?? '',
58
+ ...identity,
59
+ category,
60
+ kind: rowKind,
61
+ value,
62
+ mode: delta.mode,
63
+ });
64
+ }
65
+ }
66
+ };
67
+ pushCategory('permissionSets', user.assignments.permissionSets);
68
+ pushCategory('permissionSetGroups', user.assignments.permissionSetGroups);
69
+ pushCategory('publicGroups', user.assignments.publicGroups);
70
+ pushCategory('queues', user.assignments.queues);
71
+ if (!user.profile.matches) {
72
+ rows.push({
73
+ userKey: user.key,
74
+ userId: user.id ?? '',
75
+ ...identity,
76
+ category: 'profile',
77
+ kind: 'profile',
78
+ value: `${user.profile.current ?? ''} -> ${user.profile.intended ?? ''}`,
79
+ valueBefore: user.profile.current ?? '',
80
+ valueAfter: user.profile.intended ?? '',
81
+ });
82
+ }
83
+ if (!user.role.matches) {
84
+ rows.push({
85
+ userKey: user.key,
86
+ userId: user.id ?? '',
87
+ ...identity,
88
+ category: 'role',
89
+ kind: 'role',
90
+ value: `${user.role.current ?? ''} -> ${user.role.intended ?? ''}`,
91
+ valueBefore: user.role.current ?? '',
92
+ valueAfter: user.role.intended ?? '',
93
+ });
94
+ }
95
+ for (const error of user.errors) {
96
+ rows.push({
97
+ ...identity,
98
+ userKey: user.key,
99
+ userId: user.id ?? '',
100
+ category: 'error',
101
+ kind: 'error',
102
+ value: error,
103
+ });
104
+ }
105
+ return rows;
106
+ };
107
+ const buildResult = (users, warnings = [], labels) => ({
108
+ summary: summarize(users),
109
+ users,
110
+ rows: users.flatMap(rowsForUser),
111
+ warnings,
112
+ labels,
113
+ });
114
+ const addSourceContext = (user, errors) => {
115
+ if (!user.source)
116
+ return errors;
117
+ const source = user.source;
118
+ return errors.map((error) => `${source.path}:${String(source.line)} — ${error}`);
119
+ };
120
+ const validationErrorsFor = (user) => addSourceContext(user, (user.validationErrors ?? []).map((error) => lifecycleMessage(error.code, error.messageArgs)));
121
+ const findExisting = (user, target, defaultExternalIdField, existingByField) => {
122
+ const matchedBy = user.matchField ?? defaultExternalIdField ?? null;
123
+ const matchValue = matchedBy ? target[matchedBy] : undefined;
124
+ const existing = matchedBy && typeof matchValue === 'string' ? existingByField.get(matchedBy)?.get(matchValue) : undefined;
125
+ return { matchedBy, existing };
126
+ };
127
+ const makeProfileRole = (existing, target) => {
128
+ const intendedProfile = typeof target.ProfileId === 'string' ? target.ProfileId : null;
129
+ const intendedRole = typeof target.UserRoleId === 'string' ? target.UserRoleId : null;
130
+ return {
131
+ profile: {
132
+ current: existing?.ProfileId ?? null,
133
+ intended: intendedProfile,
134
+ matches: intendedProfile === null || (existing?.ProfileId ?? null) === intendedProfile,
135
+ },
136
+ role: {
137
+ current: existing?.UserRoleId ?? null,
138
+ intended: intendedRole,
139
+ matches: intendedRole === null || (existing?.UserRoleId ?? null) === intendedRole,
140
+ },
141
+ };
142
+ };
143
+ const addLabel = (labels, bundle) => {
144
+ const current = labels[bundle.id];
145
+ const merged = {
146
+ ...current,
147
+ ...bundle,
148
+ id: bundle.id,
149
+ };
150
+ if (bundle.apiName ?? current?.apiName)
151
+ merged.apiName = bundle.apiName ?? current?.apiName;
152
+ if (bundle.label ?? current?.label)
153
+ merged.label = bundle.label ?? current?.label;
154
+ if (bundle.type ?? current?.type)
155
+ merged.type = bundle.type ?? current?.type;
156
+ labels[bundle.id] = merged;
157
+ };
158
+ const addAssignmentLabels = (labels, psaRows, groupRows) => {
159
+ for (const row of psaRows) {
160
+ const bundle = permissionSetAssignmentLabel(row);
161
+ if (bundle)
162
+ addLabel(labels, bundle);
163
+ }
164
+ for (const row of groupRows)
165
+ addLabel(labels, groupMemberLabel(row));
166
+ };
167
+ export const displayName = (id, relationship) => relationship?.Name ?? id ?? '';
168
+ const addProfileRoleLabels = (labels, states) => {
169
+ for (const state of states.values()) {
170
+ if (state.ProfileId)
171
+ addLabel(labels, { id: state.ProfileId, label: state.profileName, type: 'Profile' });
172
+ if (state.UserRoleId)
173
+ addLabel(labels, { id: state.UserRoleId, label: state.roleName, type: 'UserRole' });
174
+ }
175
+ };
176
+ const buildLabelMap = (refs, assignmentState, profileRoles) => {
177
+ const labels = {};
178
+ if (refs?.labels)
179
+ Object.assign(labels, refs.labels);
180
+ addAssignmentLabels(labels, [...assignmentState.psaByUserId.values()].flat(), [...assignmentState.groupByUserId.values()].flat());
181
+ addProfileRoleLabels(labels, profileRoles);
182
+ return labels;
183
+ };
184
+ const diffForMissingUser = (user, refs, target, matchedBy) => ({
185
+ key: user.inputKey,
186
+ userName: [user.fields.FirstName, user.fields.LastName]
187
+ .filter((value) => typeof value === 'string' && value.length > 0)
188
+ .join(' '),
189
+ username: typeof user.fields.Username === 'string' ? user.fields.Username : undefined,
190
+ personas: user.personas,
191
+ matchedBy,
192
+ status: 'would-create',
193
+ ...makeProfileRole(undefined, target),
194
+ assignments: computeAssignmentDeltaFromState(user.effectivePersona, refs, [], []),
195
+ errors: [],
196
+ });
197
+ export const executePersonaDiff = async (request) => {
198
+ const { connection: conn } = request;
199
+ let fieldMap;
200
+ let definitions;
201
+ if (request.usersDoc) {
202
+ definitions = await loadValidatedDefinitions(request, new Map(), diffDefinitionMessages);
203
+ fieldMap = await describeUserFields(conn);
204
+ }
205
+ else {
206
+ fieldMap = await describeUserFields(conn);
207
+ definitions = await loadValidatedDefinitions(request, fieldMap, diffDefinitionMessages);
208
+ }
209
+ const { usersDoc, personasDoc } = definitions;
210
+ const personasSupplied = request.personasSupplied ?? definitions.personasSupplied;
211
+ const personas = personasDoc.personas;
212
+ validatePersonaModes(personas);
213
+ validateExternalIdFieldForFlag(request.externalId, fieldMap);
214
+ const users = validateAndCanonicalizeUsers(usersDoc.users, personas, fieldMap, personasSupplied);
215
+ const defaultExternalIdField = request.externalId ? fieldMap.get(request.externalId.toLowerCase())?.name : undefined;
216
+ const validUsers = users.filter((user) => !user.validationErrors || user.validationErrors.length === 0);
217
+ const [refs, existingResolution] = await Promise.all([
218
+ resolveReferences(conn, personas, validUsers),
219
+ getExistingUsers(conn, validUsers, { defaultExternalIdField, fieldMap }),
220
+ ]);
221
+ const existingIds = [...existingResolution.existingByField.values()].flatMap((byValue) => [...byValue.values()].map((user) => user.Id));
222
+ const uniqueExistingIds = [...new Set(existingIds)];
223
+ const [existingProfileRoles, assignmentState] = await Promise.all([
224
+ queryUserRoles(conn, uniqueExistingIds),
225
+ loadAssignmentState(conn, uniqueExistingIds, { permissionSetAssignments: true, groupMemberships: true }),
226
+ ]);
227
+ const results = users.map((user) => {
228
+ const validationErrors = validationErrorsFor(user);
229
+ if (validationErrors.length > 0) {
230
+ return {
231
+ key: user.inputKey,
232
+ userName: [user.fields.FirstName, user.fields.LastName]
233
+ .filter((value) => typeof value === 'string' && value.length > 0)
234
+ .join(' '),
235
+ username: typeof user.fields.Username === 'string' ? user.fields.Username : undefined,
236
+ personas: user.personas,
237
+ matchedBy: user.matchField ?? null,
238
+ status: 'failed',
239
+ profile: { matches: true },
240
+ role: { matches: true },
241
+ assignments: emptyAssignments(),
242
+ errors: validationErrors,
243
+ };
244
+ }
245
+ const errors = [];
246
+ const target = buildTarget(user, refs, errors);
247
+ const { matchedBy, existing: existingMatch } = findExisting(user, target, defaultExternalIdField, existingResolution.existingByField);
248
+ const profileRole = existingMatch ? existingProfileRoles.get(existingMatch.Id) : undefined;
249
+ const existing = existingMatch ? { ...existingMatch, ...profileRole } : undefined;
250
+ const matchValue = matchedBy ? target[matchedBy] : undefined;
251
+ if (matchedBy &&
252
+ typeof matchValue === 'string' &&
253
+ existingResolution.duplicates.has(matchKey(matchedBy, matchValue))) {
254
+ errors.push(lifecycleMessage('errorDuplicateExternalIdMatch', [matchedBy, matchValue]));
255
+ }
256
+ if (errors.length > 0) {
257
+ return {
258
+ key: user.inputKey,
259
+ id: existing?.Id,
260
+ userName: existing?.Name,
261
+ username: existing?.Username,
262
+ personas: user.personas,
263
+ matchedBy,
264
+ status: 'failed',
265
+ ...makeProfileRole(existing, target),
266
+ assignments: emptyAssignments(),
267
+ errors: addSourceContext(user, errors),
268
+ };
269
+ }
270
+ if (!existing) {
271
+ return diffForMissingUser(user, refs, target, matchedBy);
272
+ }
273
+ const assignments = computeAssignmentDeltaFromState(user.effectivePersona, refs, assignmentState.psaByUserId.get(existing.Id) ?? [], assignmentState.groupByUserId.get(existing.Id) ?? []);
274
+ return {
275
+ key: user.inputKey,
276
+ id: existing.Id,
277
+ userName: existing.Name,
278
+ username: existing.Username,
279
+ personas: user.personas,
280
+ matchedBy,
281
+ status: 'compared',
282
+ ...makeProfileRole(existing, target),
283
+ assignments,
284
+ errors: [],
285
+ };
286
+ });
287
+ return buildResult(results, refs.warnings, buildLabelMap(refs, assignmentState, existingProfileRoles));
288
+ };
289
+ const queryUserRoles = async (conn, ids) => {
290
+ if (ids.length === 0)
291
+ return new Map();
292
+ const rowBatches = await Promise.all(batch([...new Set(ids)], QUERY_BATCH_SIZE).map(async (idBatch) => (await conn.query(`SELECT Id, ProfileId, Profile.Name, UserRoleId, UserRole.Name FROM User WHERE Id IN (${soqlIn(idBatch)})`)).records));
293
+ return new Map(rowBatches.flat().map((row) => [
294
+ row.Id,
295
+ {
296
+ ProfileId: row.ProfileId,
297
+ UserRoleId: row.UserRoleId,
298
+ profileName: displayName(row.ProfileId, row.Profile),
299
+ roleName: displayName(row.UserRoleId, row.UserRole),
300
+ },
301
+ ]));
302
+ };
303
+ const partitionIds = (currentIds, intendedIds, mode) => {
304
+ const current = new Set(currentIds);
305
+ const intended = new Set(intendedIds);
306
+ const extras = [...current].filter((id) => !intended.has(id));
307
+ const sorted = (ids) => ids.sort((a, b) => a.localeCompare(b));
308
+ const removes = mode === 'additive' ? [] : sorted(extras);
309
+ return {
310
+ adds: sorted([...intended].filter((id) => !current.has(id))),
311
+ removes,
312
+ inBoth: sorted([...intended].filter((id) => current.has(id))),
313
+ onlyInOrg: sorted(extras).filter((id) => !removes.includes(id)),
314
+ ...(mode ? { mode } : {}),
315
+ };
316
+ };
317
+ const loadCurrentAssignmentIds = (state, userId) => extractCurrentIds(state.psaByUserId.get(userId) ?? [], state.groupByUserId.get(userId) ?? []);
318
+ const parseUserFlagOrThrow = (raw, code) => {
319
+ try {
320
+ return parseUserFlag(raw);
321
+ }
322
+ catch {
323
+ throw new LifecycleError(code, lifecycleMessage(code, [raw]), { raw });
324
+ }
325
+ };
326
+ export const executeUserToUserDiff = async (request) => {
327
+ const { connection: conn } = request;
328
+ const fieldMap = await describeUserFields(conn);
329
+ const parsedUser = parseUserFlagOrThrow(request.user, 'errorInvalidUserValue');
330
+ const parsedAgainst = parseUserFlagOrThrow(request.against, 'errorInvalidAgainstValue');
331
+ const userField = resolveTargetField(parsedUser.field, fieldMap);
332
+ const againstField = resolveTargetField(parsedAgainst.field, fieldMap);
333
+ if (!userField)
334
+ throw new LifecycleError('errorInvalidUserMatchField', lifecycleMessage('errorInvalidUserMatchField', [parsedUser.field]));
335
+ if (!againstField)
336
+ throw new LifecycleError('errorInvalidAgainstMatchField', lifecycleMessage('errorInvalidAgainstMatchField', [parsedAgainst.field]));
337
+ const { targets, errors } = await resolveTargets(conn, [
338
+ { key: `${userField}:${parsedUser.value}`, field: userField, value: parsedUser.value, order: 0 },
339
+ { key: `${againstField}:${parsedAgainst.value}`, field: againstField, value: parsedAgainst.value, order: 1 },
340
+ ], fieldMap);
341
+ if (errors.length > 0) {
342
+ return buildResult(errors.map((error) => ({
343
+ key: error.key,
344
+ id: undefined,
345
+ userName: '',
346
+ username: '',
347
+ matchedBy: error.field,
348
+ status: 'failed',
349
+ profile: { matches: true },
350
+ role: { matches: true },
351
+ assignments: emptyAssignments(),
352
+ errors: [error.message],
353
+ })), [], {});
354
+ }
355
+ const target = targets[0];
356
+ const against = targets[1];
357
+ const state = await loadAssignmentState(conn, [target.Id, against.Id], {
358
+ permissionSetAssignments: true,
359
+ groupMemberships: true,
360
+ });
361
+ const profilesById = await queryUserRoles(conn, [target.Id, against.Id]);
362
+ const targetAssignments = loadCurrentAssignmentIds(state, target.Id);
363
+ const againstAssignments = loadCurrentAssignmentIds(state, against.Id);
364
+ const userProfile = profilesById.get(target.Id);
365
+ const againstProfile = profilesById.get(against.Id);
366
+ const result = {
367
+ key: target.key,
368
+ id: target.Id,
369
+ userName: target.name,
370
+ username: target.username,
371
+ matchedBy: target.field,
372
+ status: 'compared',
373
+ profile: {
374
+ current: userProfile?.ProfileId ?? null,
375
+ intended: againstProfile?.ProfileId ?? null,
376
+ matches: (userProfile?.ProfileId ?? null) === (againstProfile?.ProfileId ?? null),
377
+ },
378
+ role: {
379
+ current: userProfile?.UserRoleId ?? null,
380
+ intended: againstProfile?.UserRoleId ?? null,
381
+ matches: (userProfile?.UserRoleId ?? null) === (againstProfile?.UserRoleId ?? null),
382
+ },
383
+ assignments: {
384
+ permissionSets: partitionIds(targetAssignments.permissionSets, againstAssignments.permissionSets),
385
+ permissionSetGroups: partitionIds(targetAssignments.permissionSetGroups, againstAssignments.permissionSetGroups),
386
+ publicGroups: partitionIds(targetAssignments.publicGroups, againstAssignments.publicGroups),
387
+ queues: partitionIds(targetAssignments.queues, againstAssignments.queues),
388
+ },
389
+ errors: [],
390
+ };
391
+ return buildResult([result], [], buildLabelMap(undefined, state, profilesById));
392
+ };
393
+ //# sourceMappingURL=userDiff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userDiff.js","sourceRoot":"","sources":["../../src/lifecycle/userDiff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { Connection } from '@salesforce/core';
2
+ export type UserFieldMeta = {
3
+ name: string;
4
+ createable: boolean;
5
+ updateable: boolean;
6
+ filterable: boolean;
7
+ /** Field-read access when describe metadata supplies it. */
8
+ readable?: boolean;
9
+ externalId?: boolean;
10
+ /** Salesforce `unique` field metadata. Paired with `externalId` when validating match fields. */
11
+ unique?: boolean;
12
+ /** Whether Salesforce compares values for this field with case sensitivity. */
13
+ caseSensitive?: boolean;
14
+ isBoolean?: boolean;
15
+ };
16
+ export type ExistingUser = {
17
+ Id: string;
18
+ IsActive?: boolean;
19
+ Name?: string;
20
+ Username?: string;
21
+ Email?: string;
22
+ ProfileId?: string | null;
23
+ Profile?: {
24
+ Name?: string;
25
+ } | null;
26
+ UserRoleId?: string | null;
27
+ UserRole?: {
28
+ Name?: string;
29
+ } | null;
30
+ };
31
+ export type UserMatchRequest = {
32
+ field: string;
33
+ value: string;
34
+ fuzzy?: boolean;
35
+ key?: string;
36
+ };
37
+ export type ExistingUserResolution = {
38
+ existingByField: Map<string, Map<string, ExistingUser>>;
39
+ duplicates: Set<string>;
40
+ matchesByRequest: Map<string, ExistingUser[]>;
41
+ };
42
+ export declare const matchKey: (field: string, value: string) => string;
43
+ /**
44
+ * The value a match request would actually be issued under, or `null` when there is none.
45
+ *
46
+ * `getExistingUsers` issues no request for a non-string or empty value, so reporting one as
47
+ * a `matchValue` would name a lookup that never happened. Whitespace is deliberately not
48
+ * trimmed: a whitespace-only value *is* queried, and can match.
49
+ */
50
+ export declare const usableMatchValue: (value: unknown) => string | null;
51
+ export declare const validateMatchField: (field: string, fieldMap: Map<string, UserFieldMeta>) => UserFieldMeta;
52
+ export declare const escapeSoqlLike: (value: string) => string;
53
+ export declare const resolveExistingUsers: (conn: Connection, requests: UserMatchRequest[], fieldMap: Map<string, UserFieldMeta>) => Promise<ExistingUserResolution>;
@@ -0,0 +1,181 @@
1
+ import { esc, soqlIn } from '../shared/sfUtils.js';
2
+ const MATCH_QUERY_MAX_LENGTH = 18_000;
3
+ export const matchKey = (field, value) => `${field}:${value}`;
4
+ /**
5
+ * The value a match request would actually be issued under, or `null` when there is none.
6
+ *
7
+ * `getExistingUsers` issues no request for a non-string or empty value, so reporting one as
8
+ * a `matchValue` would name a lookup that never happened. Whitespace is deliberately not
9
+ * trimmed: a whitespace-only value *is* queried, and can match.
10
+ */
11
+ export const usableMatchValue = (value) => typeof value === 'string' && value.length > 0 ? value : null;
12
+ export const validateMatchField = (field, fieldMap) => {
13
+ const meta = fieldMap.get(field.toLowerCase());
14
+ if (!meta || !meta.filterable)
15
+ throw new Error(`Invalid match field "${field}".`);
16
+ return meta;
17
+ };
18
+ export const escapeSoqlLike = (value) => value.replaceAll('\\', '\\\\\\\\').replaceAll('%', '\\%').replaceAll('_', '\\_').replaceAll("'", "\\'");
19
+ const batchesByQueryLength = (values, render, prefixLength, suffixLength = 0) => {
20
+ const batches = [];
21
+ let current = [];
22
+ let currentLength = prefixLength + suffixLength;
23
+ for (const value of values) {
24
+ const renderedLength = render(value).length;
25
+ const nextLength = currentLength + (current.length > 0 ? 1 : 0) + renderedLength;
26
+ if (current.length > 0 && nextLength > MATCH_QUERY_MAX_LENGTH) {
27
+ batches.push(current);
28
+ current = [];
29
+ currentLength = prefixLength + suffixLength;
30
+ }
31
+ current.push(value);
32
+ currentLength += (current.length > 1 ? 1 : 0) + renderedLength;
33
+ }
34
+ if (current.length > 0)
35
+ batches.push(current);
36
+ return batches;
37
+ };
38
+ const distinctUsers = (rows) => {
39
+ const seen = new Set();
40
+ return rows.filter((row) => {
41
+ if (seen.has(row.Id))
42
+ return false;
43
+ seen.add(row.Id);
44
+ return true;
45
+ });
46
+ };
47
+ const requestKey = (request) => request.key ?? matchKey(request.field, request.value);
48
+ const selectUserFields = (matchField) => {
49
+ const fields = [
50
+ 'Id',
51
+ 'IsActive',
52
+ 'Name',
53
+ 'Username',
54
+ 'Email',
55
+ 'ProfileId',
56
+ 'Profile.Name',
57
+ 'UserRoleId',
58
+ 'UserRole.Name',
59
+ ];
60
+ if (!fields.some((field) => field.toLowerCase() === matchField.toLowerCase()))
61
+ fields.push(matchField);
62
+ return fields;
63
+ };
64
+ const toExistingUser = (row) => ({
65
+ Id: row.Id,
66
+ IsActive: row.IsActive,
67
+ Name: row.Name,
68
+ Username: row.Username,
69
+ Email: row.Email,
70
+ ProfileId: row.ProfileId,
71
+ Profile: row.Profile,
72
+ UserRoleId: row.UserRoleId,
73
+ UserRole: row.UserRole,
74
+ });
75
+ const addRequestMatches = (matchesByRequest, request, matches) => {
76
+ matchesByRequest.set(requestKey(request), matches);
77
+ };
78
+ export const resolveExistingUsers = async (conn, requests, fieldMap) => {
79
+ const existingByField = new Map();
80
+ const duplicates = new Set();
81
+ const matchesByRequest = new Map();
82
+ const exactByField = new Map();
83
+ const fuzzyUsernameRequests = requests.filter((request) => request.fuzzy === true && request.field === 'Username');
84
+ for (const request of requests) {
85
+ if (request.field !== 'Id')
86
+ validateMatchField(request.field, fieldMap);
87
+ if (request.fuzzy === true && request.field === 'Username')
88
+ continue;
89
+ const group = exactByField.get(request.field) ?? [];
90
+ group.push(request);
91
+ exactByField.set(request.field, group);
92
+ }
93
+ const exactQueries = Promise.all([...exactByField.entries()].map(async ([field, fieldRequests]) => {
94
+ const values = [...new Set(fieldRequests.map((request) => request.value))];
95
+ if (values.length === 0)
96
+ return;
97
+ const prefix = `SELECT ${selectUserFields(field).join(', ')} FROM User WHERE ${field} IN (`;
98
+ const chunks = batchesByQueryLength(values, (value) => `'${esc(value)}'`, prefix.length, 1);
99
+ const rows = (await Promise.all(chunks.map(async (chunk) => (await conn.query(`${prefix}${soqlIn(chunk)})`)).records))).flat();
100
+ const fieldMatches = new Map();
101
+ const exactMatchesByRequest = new Map();
102
+ const exactDuplicates = new Set();
103
+ for (const request of fieldRequests) {
104
+ const matches = distinctUsers(rows
105
+ .filter((row) => String(row[field] ?? '').toLowerCase() === request.value.toLowerCase())
106
+ .map(toExistingUser));
107
+ addRequestMatches(exactMatchesByRequest, request, matches);
108
+ if (matches.length > 1)
109
+ exactDuplicates.add(matchKey(field, request.value));
110
+ else if (matches.length === 1)
111
+ fieldMatches.set(request.value, matches[0]);
112
+ }
113
+ return {
114
+ existingByField: new Map([[field, fieldMatches]]),
115
+ duplicates: exactDuplicates,
116
+ matchesByRequest: exactMatchesByRequest,
117
+ };
118
+ }));
119
+ const fuzzyQuery = (async () => {
120
+ if (fuzzyUsernameRequests.length === 0)
121
+ return;
122
+ const bases = [...new Set(fuzzyUsernameRequests.map((request) => request.value))];
123
+ const renderClause = (base) => `(Username = '${esc(base)}' OR Username LIKE '${escapeSoqlLike(base)}.%')`;
124
+ const prefix = `SELECT ${selectUserFields('Username').join(', ')} FROM User WHERE `;
125
+ const chunks = batchesByQueryLength(bases, renderClause, prefix.length);
126
+ const rows = (await Promise.all(chunks.map(async (chunk) => (await conn.query(`${prefix}${chunk.map(renderClause).join(' OR ')}`)).records))).flat();
127
+ const fieldMatches = new Map();
128
+ const fuzzyMatchesByRequest = new Map();
129
+ const fuzzyDuplicates = new Set();
130
+ const rowsByBase = new Map();
131
+ const basesByRowId = new Map();
132
+ for (const base of bases) {
133
+ const normalizedBase = base.toLowerCase();
134
+ const matches = distinctUsers(rows
135
+ .filter((row) => {
136
+ const username = row.Username?.toLowerCase() ?? '';
137
+ return username === normalizedBase || username.startsWith(`${normalizedBase}.`);
138
+ })
139
+ .map(toExistingUser));
140
+ rowsByBase.set(base, matches);
141
+ for (const match of matches) {
142
+ const matchingBases = basesByRowId.get(match.Id) ?? new Set();
143
+ matchingBases.add(base);
144
+ basesByRowId.set(match.Id, matchingBases);
145
+ }
146
+ }
147
+ for (const base of bases) {
148
+ const matches = rowsByBase.get(base) ?? [];
149
+ for (const request of fuzzyUsernameRequests.filter((candidate) => candidate.value === base)) {
150
+ addRequestMatches(fuzzyMatchesByRequest, request, matches);
151
+ }
152
+ const matchesAnotherBase = matches.some((match) => (basesByRowId.get(match.Id)?.size ?? 0) > 1);
153
+ if (matches.length > 1 || matchesAnotherBase)
154
+ fuzzyDuplicates.add(matchKey('Username', base));
155
+ else if (matches.length === 1)
156
+ fieldMatches.set(base, matches[0]);
157
+ }
158
+ return {
159
+ existingByField: new Map([['Username', fieldMatches]]),
160
+ duplicates: fuzzyDuplicates,
161
+ matchesByRequest: fuzzyMatchesByRequest,
162
+ };
163
+ })();
164
+ const [exactResolutions, fuzzyResolution] = await Promise.all([exactQueries, fuzzyQuery]);
165
+ for (const resolution of [...exactResolutions, fuzzyResolution]) {
166
+ if (!resolution)
167
+ continue;
168
+ for (const [field, fieldMatches] of resolution.existingByField) {
169
+ const mergedFieldMatches = existingByField.get(field) ?? new Map();
170
+ for (const [value, user] of fieldMatches)
171
+ mergedFieldMatches.set(value, user);
172
+ existingByField.set(field, mergedFieldMatches);
173
+ }
174
+ for (const duplicate of resolution.duplicates)
175
+ duplicates.add(duplicate);
176
+ for (const [key, matches] of resolution.matchesByRequest)
177
+ matchesByRequest.set(key, matches);
178
+ }
179
+ return { existingByField, duplicates, matchesByRequest };
180
+ };
181
+ //# sourceMappingURL=index.js.map