@salesforce/plugin-bre-to-cml 1.3.0 → 1.3.2

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 (50) hide show
  1. package/README.md +117 -4
  2. package/lib/commands/cml/convert/surcharge-rules.d.ts +12 -0
  3. package/lib/commands/cml/convert/surcharge-rules.js +79 -5
  4. package/lib/commands/cml/convert/surcharge-rules.js.map +1 -1
  5. package/lib/commands/cml/convert/underwriting-rules.d.ts +41 -2
  6. package/lib/commands/cml/convert/underwriting-rules.js +141 -17
  7. package/lib/commands/cml/convert/underwriting-rules.js.map +1 -1
  8. package/lib/commands/insurance/import/record-updates.d.ts +66 -0
  9. package/lib/commands/insurance/import/record-updates.js +239 -0
  10. package/lib/commands/insurance/import/record-updates.js.map +1 -0
  11. package/lib/shared/cml-operators.d.ts +9 -1
  12. package/lib/shared/cml-operators.js +23 -5
  13. package/lib/shared/cml-operators.js.map +1 -1
  14. package/lib/shared/insurance/confirm-org-changes.d.ts +49 -0
  15. package/lib/shared/insurance/confirm-org-changes.js +43 -0
  16. package/lib/shared/insurance/confirm-org-changes.js.map +1 -0
  17. package/lib/shared/insurance/insurance-cml-merge.d.ts +100 -13
  18. package/lib/shared/insurance/insurance-cml-merge.js +355 -54
  19. package/lib/shared/insurance/insurance-cml-merge.js.map +1 -1
  20. package/lib/shared/insurance/insurance-context-tags.d.ts +124 -0
  21. package/lib/shared/insurance/insurance-context-tags.js +210 -0
  22. package/lib/shared/insurance/insurance-context-tags.js.map +1 -0
  23. package/lib/shared/insurance/insurance-org.d.ts +12 -0
  24. package/lib/shared/insurance/insurance-org.js +38 -2
  25. package/lib/shared/insurance/insurance-org.js.map +1 -1
  26. package/lib/shared/insurance/insurance-rule-convert-command.d.ts +27 -0
  27. package/lib/shared/insurance/insurance-rule-convert-command.js +57 -4
  28. package/lib/shared/insurance/insurance-rule-convert-command.js.map +1 -1
  29. package/lib/shared/insurance/insurance-rule-generator.d.ts +101 -8
  30. package/lib/shared/insurance/insurance-rule-generator.js +293 -42
  31. package/lib/shared/insurance/insurance-rule-generator.js.map +1 -1
  32. package/lib/shared/insurance/models.d.ts +2 -1
  33. package/lib/shared/insurance/planned-change-mapper.d.ts +15 -0
  34. package/lib/shared/insurance/planned-change-mapper.js +51 -0
  35. package/lib/shared/insurance/planned-change-mapper.js.map +1 -0
  36. package/lib/shared/insurance/planned-change.d.ts +83 -0
  37. package/lib/shared/insurance/planned-change.js +74 -0
  38. package/lib/shared/insurance/planned-change.js.map +1 -0
  39. package/lib/shared/insurance/record-update-apply.d.ts +100 -0
  40. package/lib/shared/insurance/record-update-apply.js +303 -0
  41. package/lib/shared/insurance/record-update-apply.js.map +1 -0
  42. package/lib/shared/insurance/record-update-plan.d.ts +104 -0
  43. package/lib/shared/insurance/record-update-plan.js +397 -0
  44. package/lib/shared/insurance/record-update-plan.js.map +1 -0
  45. package/messages/cml.convert.surcharge-rules.md +3 -1
  46. package/messages/cml.convert.underwriting-rules.md +1 -1
  47. package/messages/insurance.import.record-updates.md +176 -0
  48. package/oclif.lock +28 -28
  49. package/oclif.manifest.json +127 -35
  50. package/package.json +16 -8
@@ -0,0 +1,83 @@
1
+ /**
2
+ * The "what is about to change in the org" preview for the insurance import commands
3
+ * (export/review/import design, work item W-23654540 §4): an org-mutating import builds the
4
+ * complete PlannedChange[] from read-only operations, renders it, and only then prompts — so an
5
+ * operator always sees the exact field-level changes before anything is written.
6
+ *
7
+ * Used today by `insurance import record-updates`. Nothing here is specific to record updates, so
8
+ * `cml import as-expression-set` can render its own plan through it when its gate lands (§7 step 12).
9
+ */
10
+ /** Column values are rendered verbatim, so keep the vocabulary closed and stable. */
11
+ export type PlannedChangeOperation = 'Create' | 'Update' | 'Reuse' | 'Skip (already current)' | 'Create (UNRESOLVED FK)';
12
+ export type PlannedChange = {
13
+ operation: PlannedChangeOperation;
14
+ /** sObject type, e.g. 'ProductSurcharge'. */
15
+ object: string;
16
+ /** Record id, or `NO_ID` for a create (the id does not exist yet). */
17
+ id: string;
18
+ name: string;
19
+ field: string;
20
+ /** `old → new`, truncated (and, for JSON blobs, reduced to the mutated fields) for display. */
21
+ change: string;
22
+ /**
23
+ * Untruncated current org value, from the same fresh re-read `change` was built from. `change`
24
+ * is a display string, so `--json` consumers need the real values to diff or audit against.
25
+ * Absent for operations that have no current value, e.g. a create.
26
+ */
27
+ currentValue?: string | null;
28
+ /** Untruncated value that will be written. Absent when the operation writes no single value. */
29
+ newValue?: string;
30
+ };
31
+ /** Placeholder shown in the Id column for records that do not exist yet. */
32
+ export declare const NO_ID = "\u2014";
33
+ /** Placeholder shown when a field currently has no value in the org. */
34
+ export declare const NO_VALUE = "(none)";
35
+ /**
36
+ * Minimal surface the renderer needs, so this module is unit-testable without oclif. Declared with
37
+ * method syntax so an `SfCommand` (whose `table` is generic) satisfies it.
38
+ */
39
+ export type PlannedChangeRenderer = {
40
+ styledHeader(text: string): void;
41
+ table(options: {
42
+ data: Array<Record<string, unknown>>;
43
+ }): void;
44
+ log(message: string): void;
45
+ warn(message: string): unknown;
46
+ };
47
+ export declare function truncateCell(value: string, max?: number): string;
48
+ /** Renders a single field-level change as `old → new`, with both sides truncated. */
49
+ export declare function formatChange(currentValue: string | null | undefined, newValue: string): string;
50
+ export type PlannedChangeCounts = {
51
+ creates: number;
52
+ updates: number;
53
+ reuses: number;
54
+ skips: number;
55
+ };
56
+ export declare function countPlannedChanges(changes: PlannedChange[]): PlannedChangeCounts;
57
+ export type PlannedChangeText = {
58
+ /** Header line, e.g. `These changes will be applied to <username>`. */
59
+ header: string;
60
+ /** One-line count summary. */
61
+ summary: string;
62
+ /**
63
+ * The explicit non-transactional notice (§4). Changes are applied in order and are NOT rolled
64
+ * back, so a mid-apply failure can leave the org partially migrated — the operator must be told
65
+ * this before confirming, not after a failure.
66
+ *
67
+ * Omit on a path that will not write (e.g. `--dry-run`). A caution about a hazard that cannot
68
+ * occur is noise, and it dilutes the warnings that describe real ones.
69
+ */
70
+ notTransactional?: string;
71
+ };
72
+ /**
73
+ * Renders the preview: styled header, one row per field-level change, the count summary, and — only
74
+ * when the caller is on a path that will write — the non-transactional notice.
75
+ *
76
+ * The summary goes to `log`, not `warn`, on purpose. `warn` is not merely a louder `log`: it writes
77
+ * to stderr, so under `--dry-run` (whose entire output IS the summary) redirecting stdout to a file
78
+ * drops it; and `SfCommand.warn` pushes unconditionally to the `warnings` array, so emitting
79
+ * boilerplate through it makes every successful `--json` run return a non-empty `warnings`, which
80
+ * both trips consumers that treat `warnings.length > 0` as a problem signal and buries the genuine
81
+ * warnings (ProductCode drift, per-record save failures) among the routine ones.
82
+ */
83
+ export declare function renderPlannedChanges(renderer: PlannedChangeRenderer, changes: PlannedChange[], text: PlannedChangeText): void;
@@ -0,0 +1,74 @@
1
+ /*
2
+ * Copyright 2026, Salesforce, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /** Placeholder shown in the Id column for records that do not exist yet. */
17
+ export const NO_ID = '—';
18
+ /** Placeholder shown when a field currently has no value in the org. */
19
+ export const NO_VALUE = '(none)';
20
+ /** Table cells are truncated so an opaque blob (e.g. DynamicRuleDefinition) stays readable. */
21
+ const MAX_CELL_LENGTH = 60;
22
+ export function truncateCell(value, max = MAX_CELL_LENGTH) {
23
+ if (value.length <= max)
24
+ return value;
25
+ // `max - 1` goes negative for max < 1, which would slice from the END of the string and return
26
+ // something longer than the budget. The ellipsis alone is the smallest honest rendering.
27
+ const keep = Math.max(max - 1, 0);
28
+ let head = value.slice(0, keep);
29
+ // Never emit the high half of a surrogate pair on its own — it renders as a replacement glyph.
30
+ if (/[\uD800-\uDBFF]$/.test(head))
31
+ head = head.slice(0, -1);
32
+ return `${head}…`;
33
+ }
34
+ /** Renders a single field-level change as `old → new`, with both sides truncated. */
35
+ export function formatChange(currentValue, newValue) {
36
+ const before = currentValue == null || currentValue === '' ? NO_VALUE : currentValue;
37
+ return `${truncateCell(before)} → ${truncateCell(newValue)}`;
38
+ }
39
+ export function countPlannedChanges(changes) {
40
+ return {
41
+ creates: changes.filter((c) => c.operation.startsWith('Create')).length,
42
+ updates: changes.filter((c) => c.operation === 'Update').length,
43
+ reuses: changes.filter((c) => c.operation === 'Reuse').length,
44
+ skips: changes.filter((c) => c.operation === 'Skip (already current)').length,
45
+ };
46
+ }
47
+ /**
48
+ * Renders the preview: styled header, one row per field-level change, the count summary, and — only
49
+ * when the caller is on a path that will write — the non-transactional notice.
50
+ *
51
+ * The summary goes to `log`, not `warn`, on purpose. `warn` is not merely a louder `log`: it writes
52
+ * to stderr, so under `--dry-run` (whose entire output IS the summary) redirecting stdout to a file
53
+ * drops it; and `SfCommand.warn` pushes unconditionally to the `warnings` array, so emitting
54
+ * boilerplate through it makes every successful `--json` run return a non-empty `warnings`, which
55
+ * both trips consumers that treat `warnings.length > 0` as a problem signal and buries the genuine
56
+ * warnings (ProductCode drift, per-record save failures) among the routine ones.
57
+ */
58
+ export function renderPlannedChanges(renderer, changes, text) {
59
+ renderer.styledHeader(text.header);
60
+ renderer.table({
61
+ data: changes.map((c) => ({
62
+ Operation: c.operation,
63
+ Object: c.object,
64
+ Id: c.id,
65
+ Name: c.name,
66
+ Field: c.field,
67
+ Change: c.change,
68
+ })),
69
+ });
70
+ renderer.log(text.summary);
71
+ if (text.notTransactional !== undefined)
72
+ renderer.warn(text.notTransactional);
73
+ }
74
+ //# sourceMappingURL=planned-change.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planned-change.js","sourceRoot":"","sources":["../../../src/shared/insurance/planned-change.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAwCH,4EAA4E;AAC5E,MAAM,CAAC,MAAM,KAAK,GAAG,GAAG,CAAC;AAEzB,wEAAwE;AACxE,MAAM,CAAC,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAEjC,+FAA+F;AAC/F,MAAM,eAAe,GAAG,EAAE,CAAC;AAa3B,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,GAAG,GAAG,eAAe;IAC/D,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,KAAK,CAAC;IACtC,+FAA+F;IAC/F,yFAAyF;IACzF,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAClC,IAAI,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAChC,+FAA+F;IAC/F,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5D,OAAO,GAAG,IAAI,GAAG,CAAC;AACpB,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,YAAY,CAAC,YAAuC,EAAE,QAAgB;IACpF,MAAM,MAAM,GAAG,YAAY,IAAI,IAAI,IAAI,YAAY,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC;IACrF,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC/D,CAAC;AASD,MAAM,UAAU,mBAAmB,CAAC,OAAwB;IAC1D,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM;QACvE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,MAAM;QAC/D,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,MAAM;QAC7D,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,wBAAwB,CAAC,CAAC,MAAM;KAC9E,CAAC;AACJ,CAAC;AAkBD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAA+B,EAC/B,OAAwB,EACxB,IAAuB;IAEvB,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC;QACb,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,MAAM,EAAE,CAAC,CAAC,MAAM;SACjB,CAAC,CAAC;KACJ,CAAC,CAAC;IACH,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3B,IAAI,IAAI,CAAC,gBAAgB,KAAK,SAAS;QAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAChF,CAAC"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Org-facing half of `sf insurance import record-updates`
3
+ * (export/review/import design, work item W-23654540 §5).
4
+ *
5
+ * Split into a read phase and an apply phase on purpose: the command must be able to compute and
6
+ * render every planned change using read-only operations, then prompt, and only then write. Keeping
7
+ * both phases here (rather than in the oclif command) makes them unit-testable against a stub
8
+ * Connection.
9
+ */
10
+ import { Connection } from '@salesforce/core';
11
+ import { RecordUpdate, RecordUpdateField, RecordUpdatePlan } from './models.js';
12
+ /**
13
+ * Why the read phase refused a record. These are not shades of one problem: they need different
14
+ * things from the operator, so the kind travels with the message and the command selects the
15
+ * remediation from it.
16
+ *
17
+ * `recordIdentityMismatch`: the file names a record the org disagrees with (a missing record, or a
18
+ * Name/blob-apiName that does not match). Correcting the file, or regenerating it, is the fix.
19
+ *
20
+ * `unreadableOrgBlob`: the value stored in the org is not parseable JSON. Nothing in the file is
21
+ * wrong and regenerating cannot help — convert would fail to parse the same bytes.
22
+ *
23
+ * `identityCheckUnavailable`: the re-read did not return a field the guard needs. That is a defect
24
+ * in this plugin; no edit to the file can affect it.
25
+ */
26
+ export type IdentityProblemKind = 'recordIdentityMismatch' | 'unreadableOrgBlob' | 'identityCheckUnavailable';
27
+ /** A blocking problem found before any write, tagged with the kind of remediation it needs. */
28
+ export type IdentityProblem = {
29
+ kind: IdentityProblemKind;
30
+ message: string;
31
+ };
32
+ /** One field-level change, joined to the org's current value from a fresh re-read. */
33
+ export type PlannedRecordChange = {
34
+ update: RecordUpdate;
35
+ field: RecordUpdateField;
36
+ /** Current org value, from this invocation's re-read. Null when the field is empty. */
37
+ currentValue: string | null;
38
+ /** True when the org already holds the desired value, so the apply skips this field. */
39
+ alreadyCurrent: boolean;
40
+ };
41
+ export type RecordUpdateReadPhase = {
42
+ changes: PlannedRecordChange[];
43
+ /**
44
+ * Blocking problems found before any write: a record that no longer exists, or whose Name (or UW
45
+ * blob apiName) disagrees with the file. Refusing here is what stops an edited id from silently
46
+ * retargeting a valid-but-wrong record.
47
+ */
48
+ identityErrors: IdentityProblem[];
49
+ /** Non-blocking notices, e.g. ProductCode drift that would desync the platform-generated RuleKey. */
50
+ advisories: string[];
51
+ };
52
+ /**
53
+ * Re-reads current org state for every record in the plan and returns the resolved field-level
54
+ * changes. Read-only: safe to run under `--dry-run` and before the confirmation prompt.
55
+ *
56
+ * Only regex-validated ids are ever interpolated into SOQL (via `quoteSoqlIdList`); free text from
57
+ * the file — `name`, `value` — never is.
58
+ */
59
+ export declare function planRecordUpdates(conn: Connection, plan: RecordUpdatePlan): Promise<RecordUpdateReadPhase>;
60
+ export type RecordUpdateFailure = {
61
+ id: string;
62
+ name: string;
63
+ errors: string[];
64
+ /**
65
+ * True when the request failed *after* it was sent, so whether the org applied this record is
66
+ * genuinely unknown — a timeout or a 500 can arrive after the server committed. Distinct from a
67
+ * rejection, where the org is known not to have written it.
68
+ */
69
+ outcomeUnknown: boolean;
70
+ };
71
+ export type ApplyRecordUpdatesResult = {
72
+ /** Records (not fields) successfully written. */
73
+ applied: number;
74
+ failures: RecordUpdateFailure[];
75
+ };
76
+ /**
77
+ * Writes the non-skipped changes, one `update` call per sObject type, groups issued in
78
+ * `SOBJECT_APPLY_ORDER`. There is no transaction: successful writes are not rolled back when a
79
+ * later one fails, which is why failures are collected and reported rather than thrown from here.
80
+ */
81
+ export declare function applyRecordUpdates(conn: Connection, changes: PlannedRecordChange[]): Promise<ApplyRecordUpdatesResult>;
82
+ export type SurchargeVerification = {
83
+ Id: string;
84
+ Name: string;
85
+ RuleEngineType: string | null;
86
+ RuleKey: string | null;
87
+ RuleApiName: string | null;
88
+ };
89
+ export type SurchargeVerificationResult = {
90
+ records: SurchargeVerification[];
91
+ /** Loud but non-fatal: the flip succeeded, yet the surcharge will not fire. */
92
+ warnings: string[];
93
+ };
94
+ /**
95
+ * Post-flip verification (§5.4). `expectedRuleKey` is never written — the platform regenerates
96
+ * `ProductSurcharge.RuleKey` when `RuleEngineType` flips — so the only way to know the surcharge
97
+ * will actually fire is to read the regenerated key back and compare it to the key the CML rule was
98
+ * emitted under.
99
+ */
100
+ export declare function verifySurchargeUpdates(conn: Connection, updates: RecordUpdate[]): Promise<SurchargeVerificationResult>;
@@ -0,0 +1,303 @@
1
+ /*
2
+ * Copyright 2026, Salesforce, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { fetchProductCodes, quoteSoqlIdList } from './insurance-org.js';
17
+ import { splitProductPath } from './insurance-cml-merge.js';
18
+ import { JSON_BLOB_FIELD, SOBJECT_APPLY_ORDER, dynamicRuleDefinitionApiName, isAlreadyCurrent, } from './record-update-plan.js';
19
+ /**
20
+ * Salesforce rejects a `/composite/sobjects` request carrying more than 200 records, and jsforce
21
+ * only splits the batch itself when `allowRecursive` is set (which `sobject().update()` does not
22
+ * pass). Without chunking here, a 201-record plan fails wholesale and is then misreported as a
23
+ * partial migration.
24
+ */
25
+ const MAX_DML_CHUNK = 200;
26
+ /** Keeps a generated `Id IN (...)` clause comfortably inside the SOQL statement length limit. */
27
+ const MAX_SOQL_ID_CHUNK = 500;
28
+ function chunk(items, size) {
29
+ return Array.from({ length: Math.ceil(items.length / size) }, (_, i) => items.slice(i * size, i * size + size));
30
+ }
31
+ const asString = (value) => value == null ? null : typeof value === 'string' ? value : String(value);
32
+ /** Groups updates by sObject, in the order the apply must issue them. */
33
+ function groupBySobject(updates) {
34
+ return SOBJECT_APPLY_ORDER.map((sobject) => [sobject, updates.filter((u) => u.sobject === sobject)]).filter(([, group]) => group.length > 0);
35
+ }
36
+ /**
37
+ * Re-reads current org state for every record in the plan and returns the resolved field-level
38
+ * changes. Read-only: safe to run under `--dry-run` and before the confirmation prompt.
39
+ *
40
+ * Only regex-validated ids are ever interpolated into SOQL (via `quoteSoqlIdList`); free text from
41
+ * the file — `name`, `value` — never is.
42
+ */
43
+ export async function planRecordUpdates(conn, plan) {
44
+ const changes = [];
45
+ const identityErrors = [];
46
+ const advisories = [];
47
+ for (const [sobject, updates] of groupBySobject(plan.updates)) {
48
+ const fieldNames = [...new Set(updates.flatMap((u) => u.fields.map((f) => f.field)))];
49
+ // ProductPath backs the advisory ProductCode drift check below; it is read, never written.
50
+ const extraFields = sobject === 'ProductSurcharge' ? ['ProductPath'] : [];
51
+ // eslint-disable-next-line no-await-in-loop
52
+ const current = await queryCurrentRecords(conn, sobject, updates, [...fieldNames, ...extraFields]);
53
+ for (const update of updates) {
54
+ const record = current.get(update.id);
55
+ if (!record) {
56
+ identityErrors.push({
57
+ kind: 'recordIdentityMismatch',
58
+ message: `${update.sobject} ${update.id} (${update.name}) was not found in the org`,
59
+ });
60
+ continue;
61
+ }
62
+ const orgName = asString(record.Name);
63
+ if (orgName !== update.name) {
64
+ identityErrors.push({
65
+ kind: 'recordIdentityMismatch',
66
+ message: `${update.sobject} ${update.id} is named '${orgName ?? '<none>'}' in the org but the file expected '${update.name}' — refusing to write to a possibly-wrong record`,
67
+ });
68
+ continue;
69
+ }
70
+ const blobCheck = findBlobApiNameMismatch(update, record);
71
+ if (blobCheck?.error) {
72
+ identityErrors.push(blobCheck.error);
73
+ continue;
74
+ }
75
+ if (blobCheck?.advisory)
76
+ advisories.push(blobCheck.advisory);
77
+ for (const field of update.fields) {
78
+ const currentValue = asString(record[field.field]);
79
+ changes.push({
80
+ update,
81
+ field,
82
+ currentValue,
83
+ alreadyCurrent: isAlreadyCurrent(field.field, currentValue, field.value),
84
+ });
85
+ }
86
+ }
87
+ if (sobject === 'ProductSurcharge') {
88
+ // eslint-disable-next-line no-await-in-loop
89
+ advisories.push(...(await findProductCodeDrift(conn, updates, current)));
90
+ }
91
+ }
92
+ return { changes, identityErrors, advisories };
93
+ }
94
+ async function queryCurrentRecords(conn, sobject, updates, fields) {
95
+ const byId = new Map();
96
+ const selected = ['Id', 'Name', ...fields.filter((f) => f !== 'Id' && f !== 'Name')];
97
+ for (const batch of chunk(updates, MAX_SOQL_ID_CHUNK)) {
98
+ const idList = quoteSoqlIdList(batch.map((u) => u.id));
99
+ if (!idList)
100
+ continue;
101
+ // eslint-disable-next-line no-await-in-loop
102
+ const result = await conn.query(`SELECT ${selected.join(', ')} FROM ${sobject} WHERE Id IN (${idList})`);
103
+ for (const record of result.records) {
104
+ const id = asString(record.Id);
105
+ if (id)
106
+ byId.set(id, record);
107
+ }
108
+ }
109
+ return byId;
110
+ }
111
+ /**
112
+ * For a `DynamicRuleDefinition` rewrite, the org blob's own `apiName` is a second identity key
113
+ * alongside Name.
114
+ *
115
+ * The guard fails closed. Previously anything it could not read — a blob the re-read did not
116
+ * select, or one it could not parse — returned "no name" and was indistinguishable from "the names
117
+ * agree", so the second identity key silently stopped protecting the operator. The one case that
118
+ * is genuinely benign is a readable blob that simply carries no `apiName` (convert takes that
119
+ * value from the record's ApiName field, which the blob need not repeat); that is surfaced as an
120
+ * advisory rather than blocking a legitimate migration.
121
+ */
122
+ function findBlobApiNameMismatch(update, record) {
123
+ if (update.sobject !== 'UnderwritingRule' || !update.apiName)
124
+ return undefined;
125
+ const refusing = 'refusing to write to a possibly-wrong record';
126
+ const prefix = `UnderwritingRule ${update.id} (${update.name})`;
127
+ if (!(JSON_BLOB_FIELD in record)) {
128
+ return {
129
+ error: {
130
+ kind: 'identityCheckUnavailable',
131
+ message: `${prefix}: the org re-read did not return ${JSON_BLOB_FIELD}, so the apiName identity check could not run — ${refusing}`,
132
+ },
133
+ };
134
+ }
135
+ const orgApiName = dynamicRuleDefinitionApiName(asString(record[JSON_BLOB_FIELD]));
136
+ if ('failure' in orgApiName) {
137
+ if (orgApiName.failure === 'unparseable') {
138
+ return {
139
+ error: {
140
+ kind: 'unreadableOrgBlob',
141
+ message: `${prefix}: the org's ${JSON_BLOB_FIELD} is not readable JSON, so the apiName identity check could not run — ${refusing}`,
142
+ },
143
+ };
144
+ }
145
+ return {
146
+ advisory: `${prefix}: the org's ${JSON_BLOB_FIELD} carries no apiName, so only the record Name could be verified`,
147
+ };
148
+ }
149
+ if (orgApiName.apiName === update.apiName)
150
+ return undefined;
151
+ return {
152
+ error: {
153
+ kind: 'recordIdentityMismatch',
154
+ message: `${prefix} has apiName '${orgApiName.apiName}' in the org but the file expected '${update.apiName}' — ${refusing}`,
155
+ },
156
+ };
157
+ }
158
+ /**
159
+ * Advisory ProductCode drift check. Convert computes the pathed rule key from each product's Code
160
+ * at convert time; the platform regenerates `ProductSurcharge.RuleKey` from the *current*
161
+ * ProductCode/ProductPath when `RuleEngineType` flips. If they drifted in between, the keys diverge
162
+ * silently and the surcharge never fires — so the divergence is surfaced, never blocked on.
163
+ */
164
+ async function findProductCodeDrift(conn, updates, current) {
165
+ const withCodes = updates.filter((u) => u.productCodes?.length);
166
+ if (withCodes.length === 0)
167
+ return [];
168
+ const productIds = new Set();
169
+ for (const update of withCodes) {
170
+ for (const id of splitProductPath(asString(current.get(update.id)?.ProductPath) ?? ''))
171
+ productIds.add(id);
172
+ }
173
+ if (productIds.size === 0)
174
+ return [];
175
+ // A null ProductCode resolves to Name (then Id), which yields a key that cannot match the
176
+ // platform-generated RuleKey — so the comparison below can be spurious in either direction.
177
+ // The hook exists precisely to make that observable; ignoring it hid the signal.
178
+ const fellBack = new Set();
179
+ const idToCode = await fetchProductCodes(conn, productIds, { onFallback: (id) => fellBack.add(id) });
180
+ const advisories = [];
181
+ if (fellBack.size > 0) {
182
+ advisories.push(`products ${[...fellBack].join(', ')} have no ProductCode; their code was derived from Name or Id, so the ` +
183
+ 'ProductCode drift check below cannot be relied on for surcharges on those products');
184
+ }
185
+ for (const update of withCodes) {
186
+ const orgPath = splitProductPath(asString(current.get(update.id)?.ProductPath) ?? '');
187
+ const orgCodes = orgPath.map((id) => idToCode.get(id) ?? id);
188
+ const fileCodes = update.productCodes ?? [];
189
+ if (orgCodes.join('/') !== fileCodes.join('/')) {
190
+ advisories.push(`${update.name} (${update.id}): ProductCodes drifted since convert — file has '${fileCodes.join('/')}', org now resolves '${orgCodes.join('/')}'; the platform-generated RuleKey may not match the converted CML rule key`);
191
+ }
192
+ }
193
+ return advisories;
194
+ }
195
+ /**
196
+ * Writes the non-skipped changes, one `update` call per sObject type, groups issued in
197
+ * `SOBJECT_APPLY_ORDER`. There is no transaction: successful writes are not rolled back when a
198
+ * later one fails, which is why failures are collected and reported rather than thrown from here.
199
+ */
200
+ export async function applyRecordUpdates(conn, changes) {
201
+ const pending = changes.filter((c) => !c.alreadyCurrent);
202
+ let applied = 0;
203
+ const failures = [];
204
+ for (const [sobject, updates] of groupBySobject([...new Set(pending.map((c) => c.update))])) {
205
+ const payloads = updates.map((update) => {
206
+ const fields = pending.filter((c) => c.update === update).map((c) => c.field);
207
+ return { Id: update.id, ...Object.fromEntries(fields.map((f) => [f.field, f.value])) };
208
+ });
209
+ // eslint-disable-next-line no-await-in-loop
210
+ const results = await saveAll(conn, sobject, payloads);
211
+ // Indexed by payload, never by result: a result list that does not line up with what was sent
212
+ // must not throw here, because by this point the writes have already landed and the operator
213
+ // would lose the failure report for an org that is now partially migrated.
214
+ updates.forEach((update, i) => {
215
+ const result = results[i];
216
+ if (result?.success)
217
+ applied += 1;
218
+ else {
219
+ failures.push({
220
+ id: update.id,
221
+ name: update.name,
222
+ errors: result?.errors ?? [UNACCOUNTED_RESULT],
223
+ outcomeUnknown: result?.outcomeUnknown ?? true,
224
+ });
225
+ }
226
+ });
227
+ }
228
+ return { applied, failures };
229
+ }
230
+ /** Used when the org returned fewer results than the records that were sent. */
231
+ const UNACCOUNTED_RESULT = 'the org returned no result for this record, so whether it was written is unknown';
232
+ /**
233
+ * Issues the update and normalizes jsforce's per-record results. A thrown error (network, invalid
234
+ * session, whole-request rejection) is attributed to every record in the chunk, and marked
235
+ * `outcomeUnknown`: the call site cannot tell a rejected request from a timeout or a 500 that
236
+ * arrived after the server had already committed, and claiming the records were not written is
237
+ * precisely wrong in the second case.
238
+ */
239
+ async function saveAll(conn, sobject, payloads) {
240
+ const results = [];
241
+ for (const batch of chunk(payloads, MAX_DML_CHUNK)) {
242
+ // Sequential, not parallel: a failing chunk must not race writes the operator may want to stop.
243
+ // eslint-disable-next-line no-await-in-loop
244
+ results.push(...(await saveChunk(conn, sobject, batch)));
245
+ }
246
+ return results;
247
+ }
248
+ async function saveChunk(conn, sobject, payloads) {
249
+ try {
250
+ const raw = await conn.sobject(sobject).update(payloads);
251
+ // A single-record update returns the bare result rather than a one-element array.
252
+ const results = Array.isArray(raw) ? raw : [raw];
253
+ return results.map((r) => ({
254
+ success: Boolean(r.success),
255
+ errors: normalizeErrors(r.errors),
256
+ outcomeUnknown: false,
257
+ }));
258
+ }
259
+ catch (e) {
260
+ return payloads.map(() => ({ success: false, errors: [e.message], outcomeUnknown: true }));
261
+ }
262
+ }
263
+ function normalizeErrors(errors) {
264
+ if (!errors)
265
+ return [];
266
+ const list = Array.isArray(errors) ? errors : [errors];
267
+ return list.map((e) => {
268
+ if (typeof e === 'string')
269
+ return e;
270
+ const message = e?.message;
271
+ return typeof message === 'string' ? message : JSON.stringify(e);
272
+ });
273
+ }
274
+ /**
275
+ * Post-flip verification (§5.4). `expectedRuleKey` is never written — the platform regenerates
276
+ * `ProductSurcharge.RuleKey` when `RuleEngineType` flips — so the only way to know the surcharge
277
+ * will actually fire is to read the regenerated key back and compare it to the key the CML rule was
278
+ * emitted under.
279
+ */
280
+ export async function verifySurchargeUpdates(conn, updates) {
281
+ const surcharges = updates.filter((u) => u.sobject === 'ProductSurcharge');
282
+ const records = [];
283
+ for (const batch of chunk(surcharges, MAX_SOQL_ID_CHUNK)) {
284
+ const idList = quoteSoqlIdList(batch.map((u) => u.id));
285
+ if (!idList)
286
+ continue;
287
+ // eslint-disable-next-line no-await-in-loop
288
+ const result = await conn.query(`SELECT Id, Name, RuleEngineType, RuleKey, RuleApiName FROM ProductSurcharge WHERE Id IN (${idList})`);
289
+ records.push(...result.records);
290
+ }
291
+ const byId = new Map(records.map((r) => [r.Id, r]));
292
+ const warnings = [];
293
+ for (const update of surcharges) {
294
+ if (!update.expectedRuleKey)
295
+ continue;
296
+ const actual = byId.get(update.id)?.RuleKey ?? null;
297
+ if (actual !== update.expectedRuleKey) {
298
+ warnings.push(`surcharge ${update.name} RuleKey '${actual ?? '<none>'}' does not match the converted CML rule key '${update.expectedRuleKey}'; the surcharge will not fire`);
299
+ }
300
+ }
301
+ return { records, warnings };
302
+ }
303
+ //# sourceMappingURL=record-update-apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-update-apply.js","sourceRoot":"","sources":["../../../src/shared/insurance/record-update-apply.ts"],"names":[],"mappings":"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"}