sf-plugin-permission-sets 0.0.0-dev.8 → 0.0.0-dev.80

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 (132) hide show
  1. package/LICENSE.md +28 -0
  2. package/README.md +335 -97
  3. package/lib/adapters/connection-org-client.d.ts +23 -0
  4. package/lib/adapters/connection-org-client.d.ts.map +1 -0
  5. package/lib/adapters/connection-org-client.js +370 -0
  6. package/lib/adapters/connection-org-client.js.map +1 -0
  7. package/lib/adapters/index.d.ts +2 -0
  8. package/lib/adapters/index.d.ts.map +1 -0
  9. package/lib/adapters/index.js +2 -0
  10. package/lib/adapters/index.js.map +1 -0
  11. package/lib/commands/ps/apply.d.ts +41 -0
  12. package/lib/commands/ps/apply.d.ts.map +1 -0
  13. package/lib/commands/ps/apply.js +179 -0
  14. package/lib/commands/ps/apply.js.map +1 -0
  15. package/lib/commands/ps/check.d.ts +21 -0
  16. package/lib/commands/ps/check.d.ts.map +1 -0
  17. package/lib/commands/ps/check.js +55 -0
  18. package/lib/commands/ps/check.js.map +1 -0
  19. package/lib/commands/ps/export.d.ts +26 -0
  20. package/lib/commands/ps/export.d.ts.map +1 -0
  21. package/lib/commands/ps/export.js +74 -0
  22. package/lib/commands/ps/export.js.map +1 -0
  23. package/lib/commands/ps/plan.d.ts +61 -0
  24. package/lib/commands/ps/plan.d.ts.map +1 -0
  25. package/lib/commands/ps/plan.js +193 -0
  26. package/lib/commands/ps/plan.js.map +1 -0
  27. package/lib/commands/ps/validate.d.ts +21 -0
  28. package/lib/commands/ps/validate.d.ts.map +1 -0
  29. package/lib/commands/ps/validate.js +56 -0
  30. package/lib/commands/ps/validate.js.map +1 -0
  31. package/lib/core/diff.d.ts +46 -0
  32. package/lib/core/diff.d.ts.map +1 -0
  33. package/lib/core/diff.js +118 -0
  34. package/lib/core/diff.js.map +1 -0
  35. package/lib/core/finding.d.ts +43 -0
  36. package/lib/core/finding.d.ts.map +1 -0
  37. package/lib/core/finding.js +76 -0
  38. package/lib/core/finding.js.map +1 -0
  39. package/lib/core/index.d.ts +11 -0
  40. package/lib/core/index.d.ts.map +1 -0
  41. package/lib/core/index.js +10 -0
  42. package/lib/core/index.js.map +1 -0
  43. package/lib/core/load.d.ts +4 -0
  44. package/lib/core/load.d.ts.map +1 -0
  45. package/lib/core/load.js +60 -0
  46. package/lib/core/load.js.map +1 -0
  47. package/lib/core/model.d.ts +77 -0
  48. package/lib/core/model.d.ts.map +1 -0
  49. package/lib/core/model.js +2 -0
  50. package/lib/core/model.js.map +1 -0
  51. package/lib/core/normalize.d.ts +17 -0
  52. package/lib/core/normalize.d.ts.map +1 -0
  53. package/lib/core/normalize.js +74 -0
  54. package/lib/core/normalize.js.map +1 -0
  55. package/lib/core/parse.d.ts +10 -0
  56. package/lib/core/parse.d.ts.map +1 -0
  57. package/lib/core/parse.js +20 -0
  58. package/lib/core/parse.js.map +1 -0
  59. package/lib/core/report.d.ts +16 -0
  60. package/lib/core/report.d.ts.map +1 -0
  61. package/lib/core/report.js +138 -0
  62. package/lib/core/report.js.map +1 -0
  63. package/lib/core/resolve.d.ts +22 -0
  64. package/lib/core/resolve.d.ts.map +1 -0
  65. package/lib/core/resolve.js +92 -0
  66. package/lib/core/resolve.js.map +1 -0
  67. package/lib/core/schema.d.ts +23 -0
  68. package/lib/core/schema.d.ts.map +1 -0
  69. package/lib/core/schema.js +35 -0
  70. package/lib/core/schema.js.map +1 -0
  71. package/lib/core/serialize.d.ts +9 -0
  72. package/lib/core/serialize.d.ts.map +1 -0
  73. package/lib/core/serialize.js +50 -0
  74. package/lib/core/serialize.js.map +1 -0
  75. package/lib/core/target-name.d.ts +20 -0
  76. package/lib/core/target-name.d.ts.map +1 -0
  77. package/lib/core/target-name.js +32 -0
  78. package/lib/core/target-name.js.map +1 -0
  79. package/lib/core/username.d.ts +23 -0
  80. package/lib/core/username.d.ts.map +1 -0
  81. package/lib/core/username.js +35 -0
  82. package/lib/core/username.js.map +1 -0
  83. package/lib/index.d.ts +1 -0
  84. package/lib/index.d.ts.map +1 -0
  85. package/lib/services/adapters/index.d.ts +2 -0
  86. package/lib/services/adapters/index.d.ts.map +1 -0
  87. package/lib/services/adapters/index.js +2 -0
  88. package/lib/services/adapters/index.js.map +1 -0
  89. package/lib/services/adapters/org-client.d.ts +26 -0
  90. package/lib/services/adapters/org-client.d.ts.map +1 -0
  91. package/lib/services/adapters/org-client.js +2 -0
  92. package/lib/services/adapters/org-client.js.map +1 -0
  93. package/lib/services/apply.d.ts +33 -0
  94. package/lib/services/apply.d.ts.map +1 -0
  95. package/lib/services/apply.js +82 -0
  96. package/lib/services/apply.js.map +1 -0
  97. package/lib/services/check.d.ts +14 -0
  98. package/lib/services/check.d.ts.map +1 -0
  99. package/lib/services/check.js +18 -0
  100. package/lib/services/check.js.map +1 -0
  101. package/lib/services/export.d.ts +19 -0
  102. package/lib/services/export.d.ts.map +1 -0
  103. package/lib/services/export.js +30 -0
  104. package/lib/services/export.js.map +1 -0
  105. package/lib/services/index.d.ts +6 -0
  106. package/lib/services/index.d.ts.map +1 -0
  107. package/lib/services/index.js +6 -0
  108. package/lib/services/index.js.map +1 -0
  109. package/lib/services/plan.d.ts +22 -0
  110. package/lib/services/plan.d.ts.map +1 -0
  111. package/lib/services/plan.js +44 -0
  112. package/lib/services/plan.js.map +1 -0
  113. package/lib/services/resolution.d.ts +25 -0
  114. package/lib/services/resolution.d.ts.map +1 -0
  115. package/lib/services/resolution.js +78 -0
  116. package/lib/services/resolution.js.map +1 -0
  117. package/lib/services/validate.d.ts +22 -0
  118. package/lib/services/validate.d.ts.map +1 -0
  119. package/lib/services/validate.js +62 -0
  120. package/lib/services/validate.js.map +1 -0
  121. package/messages/ps.apply.md +85 -0
  122. package/messages/ps.check.md +33 -0
  123. package/messages/ps.export.md +45 -0
  124. package/messages/ps.plan.md +85 -0
  125. package/messages/ps.validate.md +29 -0
  126. package/package.json +119 -180
  127. package/lib/commands/ps/info.d.ts +0 -11
  128. package/lib/commands/ps/info.js +0 -17
  129. package/lib/commands/ps/info.js.map +0 -1
  130. package/messages/ps.info.md +0 -17
  131. package/oclif.lock +0 -7781
  132. package/oclif.manifest.json +0 -51
@@ -0,0 +1,33 @@
1
+ import { AssignmentOutcome, Diff, Finding } from '../core/index.js';
2
+ import { OrgClient } from './adapters/index.js';
3
+ export type ApplyMode = 'additive' | 'destructive' | 'sync';
4
+ /** How the service asks its caller to approve a destructive batch before applying it. */
5
+ export type ConfirmDeletions = (count: number) => Promise<boolean>;
6
+ export type ApplyInput = {
7
+ mode: ApplyMode;
8
+ maxDeletes: number;
9
+ dryRun: boolean;
10
+ };
11
+ /** How a run ended, so the command can report and set the exit code. */
12
+ export type ApplyStatus = 'applied' | 'dry-run' | 'declined' | 'max-deletes-exceeded' | 'invalid';
13
+ export type ApplyResult = {
14
+ files: string[];
15
+ findings: Finding[];
16
+ diff: Diff;
17
+ outcomes: AssignmentOutcome[];
18
+ status: ApplyStatus;
19
+ failed: boolean;
20
+ };
21
+ /**
22
+ * Load the files, resolve every reference to an org id, diff against the org's
23
+ * current state, then add and/or remove per the mode. Deletions are capped by
24
+ * maxDeletes and gated by an injected confirmation.
25
+ */
26
+ export declare class ApplyService {
27
+ private readonly org;
28
+ private readonly confirmDeletions;
29
+ constructor(org: OrgClient, confirmDeletions: ConfirmDeletions);
30
+ run(files: string[], input: ApplyInput): Promise<ApplyResult>;
31
+ private executeResolved;
32
+ }
33
+ //# sourceMappingURL=apply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/services/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,iBAAiB,EAEjB,IAAI,EAEJ,OAAO,EAEV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,aAAa,GAAG,MAAM,CAAC;AAE5D,yFAAyF;AACzF,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEnE,MAAM,MAAM,UAAU,GAAG;IACrB,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,sBAAsB,GAAG,SAAS,CAAC;AAElG,MAAM,MAAM,WAAW,GAAG;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CACnB,CAAC;AAcF;;;;GAIG;AACH,qBAAa,YAAY;IAEjB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBADhB,GAAG,EAAE,SAAS,EACd,gBAAgB,EAAE,gBAAgB;IAG1C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;YAoD5D,eAAe;CAiBhC"}
@@ -0,0 +1,82 @@
1
+ import { loadFiles, diffAssignments, Diff, countFindings, } from '../core/index.js';
2
+ import { ResolutionService } from './resolution.js';
3
+ /** An aborted-before-any-change result, carrying the findings that explain why. */
4
+ function invalidResult(files, findings) {
5
+ return {
6
+ files,
7
+ findings,
8
+ diff: Diff.empty(),
9
+ outcomes: [],
10
+ status: 'invalid',
11
+ failed: true,
12
+ };
13
+ }
14
+ /**
15
+ * Load the files, resolve every reference to an org id, diff against the org's
16
+ * current state, then add and/or remove per the mode. Deletions are capped by
17
+ * maxDeletes and gated by an injected confirmation.
18
+ */
19
+ export class ApplyService {
20
+ org;
21
+ confirmDeletions;
22
+ constructor(org, confirmDeletions) {
23
+ this.org = org;
24
+ this.confirmDeletions = confirmDeletions;
25
+ }
26
+ async run(files, input) {
27
+ const loaded = await loadFiles(files);
28
+ const loadCounts = countFindings(loaded.findings);
29
+ if (loadCounts.errors > 0) {
30
+ return invalidResult(loaded.files, loaded.findings);
31
+ }
32
+ const resolutionService = new ResolutionService(this.org);
33
+ const resolution = await resolutionService.run(loaded.assignments);
34
+ const findings = [
35
+ ...loaded.findings,
36
+ ...resolution.findings,
37
+ ];
38
+ const findingCounts = countFindings(findings);
39
+ if (findingCounts.errors > 0) {
40
+ return invalidResult(loaded.files, findings);
41
+ }
42
+ const actual = await this.org.listCurrentAssignments(resolution.managedTargets());
43
+ const diff = diffAssignments(loaded.assignments, actual);
44
+ const { mode, maxDeletes, dryRun } = input;
45
+ const { additions, updates, removals } = diff.scopeTo(mode);
46
+ if (removals.length > maxDeletes) {
47
+ return {
48
+ files: loaded.files,
49
+ findings,
50
+ diff,
51
+ outcomes: [],
52
+ status: 'max-deletes-exceeded',
53
+ failed: true,
54
+ };
55
+ }
56
+ if (dryRun) {
57
+ return { files: loaded.files, findings, diff, outcomes: [], status: 'dry-run', failed: false };
58
+ }
59
+ if (removals.length > 0) {
60
+ const confirmed = await this.confirmDeletions(removals.length);
61
+ if (!confirmed) {
62
+ return { files: loaded.files, findings, diff, outcomes: [], status: 'declined', failed: false };
63
+ }
64
+ }
65
+ const outcomes = await this.executeResolved(resolution.resolveAdditions(additions), updates, removals);
66
+ const failed = outcomes.some((outcome) => !outcome.success);
67
+ return { files: loaded.files, findings, diff, outcomes, status: 'applied', failed };
68
+ }
69
+ async executeResolved(additions, updates, removals) {
70
+ const [added, updated, removed] = await Promise.all([
71
+ additions.length > 0 ? this.org.addAssignments(additions) : Promise.resolve([]),
72
+ updates.length > 0 ? this.org.updateAssignments(updates) : Promise.resolve([]),
73
+ removals.length > 0 ? this.org.removeAssignments(removals) : Promise.resolve([]),
74
+ ]);
75
+ return [
76
+ ...added,
77
+ ...updated,
78
+ ...removed,
79
+ ];
80
+ }
81
+ }
82
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/services/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,SAAS,EACT,eAAe,EAIf,IAAI,EAGJ,aAAa,GAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAyBpD,mFAAmF;AACnF,SAAS,aAAa,CAAC,KAAe,EAAE,QAAmB;IACvD,OAAO;QACH,KAAK;QACL,QAAQ;QACR,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;QAClB,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,IAAI;KACf,CAAC;AACN,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,YAAY;IAEA;IACA;IAFrB,YACqB,GAAc,EACd,gBAAkC;QADlC,QAAG,GAAH,GAAG,CAAW;QACd,qBAAgB,GAAhB,gBAAgB,CAAkB;IACpD,CAAC;IAEG,KAAK,CAAC,GAAG,CAAC,KAAe,EAAE,KAAiB;QAC/C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1D,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACnE,MAAM,QAAQ,GAAG;YACb,GAAG,MAAM,CAAC,QAAQ;YAClB,GAAG,UAAU,CAAC,QAAQ;SACzB,CAAC;QACF,MAAM,aAAa,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,sBAAsB,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC,CAAC;QAClF,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAEzD,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;QAC3C,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAE5D,IAAI,QAAQ,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;YAC/B,OAAO;gBACH,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ;gBACR,IAAI;gBACJ,QAAQ,EAAE,EAAE;gBACZ,MAAM,EAAE,sBAAsB;gBAC9B,MAAM,EAAE,IAAI;aACf,CAAC;QACN,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACT,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QACnG,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC/D,IAAI,CAAC,SAAS,EAAE,CAAC;gBACb,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;YACpG,CAAC;QACL,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QACvG,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE5D,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IACxF,CAAC;IAEO,KAAK,CAAC,eAAe,CACzB,SAA6B,EAC7B,OAA2B,EAC3B,QAA4B;QAE5B,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAChD,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAsB,EAAE,CAAC;YACpG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAsB,EAAE,CAAC;YACnG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAsB,EAAE,CAAC;SACxG,CAAC,CAAC;QAEH,OAAO;YACH,GAAG,KAAK;YACR,GAAG,OAAO;YACV,GAAG,OAAO;SACb,CAAC;IACN,CAAC;CACJ"}
@@ -0,0 +1,14 @@
1
+ import { DesiredAssignment, Finding } from '../core/index.js';
2
+ export type CheckResult = {
3
+ files: string[];
4
+ assignments: DesiredAssignment[];
5
+ findings: Finding[];
6
+ errors: number;
7
+ warnings: number;
8
+ failed: boolean;
9
+ };
10
+ /** Load the files, validate them, and summarize the findings. No org needed. */
11
+ export declare class CheckService {
12
+ run(files: string[], strict: boolean): Promise<CheckResult>;
13
+ }
14
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/services/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,iBAAiB,EAAE,OAAO,EAAiB,MAAM,kBAAkB,CAAC;AAExF,MAAM,MAAM,WAAW,GAAG;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,gFAAgF;AAChF,qBAAa,YAAY;IACR,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;CAc3E"}
@@ -0,0 +1,18 @@
1
+ import { loadFiles, countFindings } from '../core/index.js';
2
+ /** Load the files, validate them, and summarize the findings. No org needed. */
3
+ export class CheckService {
4
+ async run(files, strict) {
5
+ const loaded = await loadFiles(files);
6
+ const { errors, warnings } = countFindings(loaded.findings);
7
+ const failed = errors > 0 || (strict && warnings > 0);
8
+ return {
9
+ files: loaded.files,
10
+ assignments: loaded.assignments,
11
+ findings: loaded.findings,
12
+ errors,
13
+ warnings,
14
+ failed,
15
+ };
16
+ }
17
+ }
18
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/services/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAA8B,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAWxF,gFAAgF;AAChF,MAAM,OAAO,YAAY;IACd,KAAK,CAAC,GAAG,CAAC,KAAe,EAAE,MAAe;QAC7C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;QAEtD,OAAO;YACH,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM;YACN,QAAQ;YACR,MAAM;SACT,CAAC;IACN,CAAC;CACJ"}
@@ -0,0 +1,19 @@
1
+ import { AssignmentFilter } from '../core/index.js';
2
+ import { OrgClient } from './adapters/index.js';
3
+ export type ExportResult = {
4
+ /** The path written, or null when the document was returned for stdout instead of a file. */
5
+ outputFile: string | null;
6
+ /** The serialized YAML document, exactly as written to the file. */
7
+ content: string;
8
+ users: number;
9
+ assignments: number;
10
+ /** Requested users (from the filter) that matched no assignments in scope. */
11
+ unmatchedUsers: string[];
12
+ };
13
+ /** Read the org's current assignments and serialize them as YAML. */
14
+ export declare class ExportService {
15
+ private readonly org;
16
+ constructor(org: OrgClient);
17
+ run(outputFile: string | undefined, filter?: AssignmentFilter): Promise<ExportResult>;
18
+ }
19
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/services/export.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAwB,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,MAAM,YAAY,GAAG;IACvB,6FAA6F;IAC7F,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,cAAc,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF,qEAAqE;AACrE,qBAAa,aAAa;IACH,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,SAAS;IAErC,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;CAsBrG"}
@@ -0,0 +1,30 @@
1
+ import { writeFile, mkdir } from 'node:fs/promises';
2
+ import { dirname } from 'node:path';
3
+ import { serializeAssignments } from '../core/index.js';
4
+ /** Read the org's current assignments and serialize them as YAML. */
5
+ export class ExportService {
6
+ org;
7
+ constructor(org) {
8
+ this.org = org;
9
+ }
10
+ async run(outputFile, filter) {
11
+ const assignments = await this.org.listAssignments(filter);
12
+ const content = serializeAssignments(assignments);
13
+ if (outputFile) {
14
+ await mkdir(dirname(outputFile), { recursive: true });
15
+ await writeFile(outputFile, content, 'utf8');
16
+ }
17
+ const assignees = new Set(assignments.map((assignment) => assignment.assignee.asKey()));
18
+ const requested = filter?.usernames ?? [];
19
+ const unmatched = requested.filter((username) => !assignees.has(username.asKey()));
20
+ const unmatchedUsers = unmatched.map((username) => username.toString());
21
+ return {
22
+ outputFile: outputFile ?? null,
23
+ content,
24
+ users: assignees.size,
25
+ assignments: assignments.length,
26
+ unmatchedUsers,
27
+ };
28
+ }
29
+ }
30
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/services/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAoB,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAc1E,qEAAqE;AACrE,MAAM,OAAO,aAAa;IACc;IAApC,YAAoC,GAAc;QAAd,QAAG,GAAH,GAAG,CAAW;IAAG,CAAC;IAE/C,KAAK,CAAC,GAAG,CAAC,UAA8B,EAAE,MAAyB;QACtE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;QAElD,IAAI,UAAU,EAAE,CAAC;YACb,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,MAAM,SAAS,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACxF,MAAM,SAAS,GAAG,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC;QAC1C,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACnF,MAAM,cAAc,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;QAExE,OAAO;YACH,UAAU,EAAE,UAAU,IAAI,IAAI;YAC9B,OAAO;YACP,KAAK,EAAE,SAAS,CAAC,IAAI;YACrB,WAAW,EAAE,WAAW,CAAC,MAAM;YAC/B,cAAc;SACjB,CAAC;IACN,CAAC;CACJ"}
@@ -0,0 +1,6 @@
1
+ export { ApplyService, ConfirmDeletions, ApplyResult } from './apply.js';
2
+ export { CheckService } from './check.js';
3
+ export { ExportService } from './export.js';
4
+ export { PlanService } from './plan.js';
5
+ export { ValidateService } from './validate.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { ApplyService } from './apply.js';
2
+ export { CheckService } from './check.js';
3
+ export { ExportService } from './export.js';
4
+ export { PlanService } from './plan.js';
5
+ export { ValidateService } from './validate.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAiC,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { Diff, Finding } from '../core/index.js';
2
+ import { OrgClient } from './adapters/index.js';
3
+ /** How a run ended, so the command can report and set the exit code. */
4
+ export type PlanStatus = 'planned' | 'invalid';
5
+ export type PlanResult = {
6
+ files: string[];
7
+ findings: Finding[];
8
+ diff: Diff;
9
+ status: PlanStatus;
10
+ };
11
+ /**
12
+ * Read-only preview: load the files, resolve every reference to an org id, fetch the
13
+ * current state, and diff. The whole diff comes back, adds and would-be removes alike:
14
+ * narrowing it to a mode is the caller's call, through Diff.scopeTo. Never changes the
15
+ * org. This is the apply pipeline stopping before any DML.
16
+ */
17
+ export declare class PlanService {
18
+ private readonly org;
19
+ constructor(org: OrgClient);
20
+ run(files: string[]): Promise<PlanResult>;
21
+ }
22
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/services/plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,IAAI,EAAE,OAAO,EAAiB,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,wEAAwE;AACxE,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;CACtB,CAAC;AAYF;;;;;GAKG;AACH,qBAAa,WAAW;IACD,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,SAAS;IAErC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;CAuBzD"}
@@ -0,0 +1,44 @@
1
+ import { loadFiles, diffAssignments, Diff, countFindings } from '../core/index.js';
2
+ import { ResolutionService } from './resolution.js';
3
+ /** An aborted-before-the-diff result, carrying the findings that explain why. */
4
+ function invalidResult(files, findings) {
5
+ return {
6
+ files,
7
+ findings,
8
+ diff: Diff.empty(),
9
+ status: 'invalid',
10
+ };
11
+ }
12
+ /**
13
+ * Read-only preview: load the files, resolve every reference to an org id, fetch the
14
+ * current state, and diff. The whole diff comes back, adds and would-be removes alike:
15
+ * narrowing it to a mode is the caller's call, through Diff.scopeTo. Never changes the
16
+ * org. This is the apply pipeline stopping before any DML.
17
+ */
18
+ export class PlanService {
19
+ org;
20
+ constructor(org) {
21
+ this.org = org;
22
+ }
23
+ async run(files) {
24
+ const loaded = await loadFiles(files);
25
+ const loadCounts = countFindings(loaded.findings);
26
+ if (loadCounts.errors > 0) {
27
+ return invalidResult(loaded.files, loaded.findings);
28
+ }
29
+ const resolutionService = new ResolutionService(this.org);
30
+ const resolution = await resolutionService.run(loaded.assignments);
31
+ const findings = [
32
+ ...loaded.findings,
33
+ ...resolution.findings,
34
+ ];
35
+ const findingCounts = countFindings(findings);
36
+ if (findingCounts.errors > 0) {
37
+ return invalidResult(loaded.files, findings);
38
+ }
39
+ const actual = await this.org.listCurrentAssignments(resolution.managedTargets());
40
+ const diff = diffAssignments(loaded.assignments, actual);
41
+ return { files: loaded.files, findings, diff, status: 'planned' };
42
+ }
43
+ }
44
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/services/plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAW,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAYpD,iFAAiF;AACjF,SAAS,aAAa,CAAC,KAAe,EAAE,QAAmB;IACvD,OAAO;QACH,KAAK;QACL,QAAQ;QACR,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;QAClB,MAAM,EAAE,SAAS;KACpB,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,WAAW;IACgB;IAApC,YAAoC,GAAc;QAAd,QAAG,GAAH,GAAG,CAAW;IAAG,CAAC;IAE/C,KAAK,CAAC,GAAG,CAAC,KAAe;QAC5B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1D,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACnE,MAAM,QAAQ,GAAG;YACb,GAAG,MAAM,CAAC,QAAQ;YAClB,GAAG,UAAU,CAAC,QAAQ;SACzB,CAAC;QACF,MAAM,aAAa,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,sBAAsB,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC,CAAC;QAClF,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAEzD,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACtE,CAAC;CACJ"}
@@ -0,0 +1,25 @@
1
+ import { DesiredAssignment, Kind, OrgTarget, ResolvedAddition, TargetName, TargetRef, Finding } from '../core/index.js';
2
+ import { OrgClient } from './adapters/index.js';
3
+ /**
4
+ * What the org answered for every declared reference: the findings, plus the org ids of
5
+ * the references that did resolve. The indexes stay private because they are keyed by the
6
+ * identifiers' comparison key, and that rule belongs here rather than at every lookup.
7
+ */
8
+ export declare class Resolution {
9
+ readonly findings: Finding[];
10
+ private readonly userIds;
11
+ private readonly targetIds;
12
+ constructor(findings: Finding[], userIds: Map<string, string>, targetIds: Record<Kind, Map<string, string>>);
13
+ /** Every target that resolved, as the managed set to compare the org's state against. */
14
+ managedTargets(): TargetRef[];
15
+ /** Attach the resolved assignee and target ids to each addition, so it can be inserted. */
16
+ resolveAdditions(additions: DesiredAssignment[]): ResolvedAddition[];
17
+ }
18
+ /** Look every declared reference up in the org, returning findings and the resolved id maps. */
19
+ export declare class ResolutionService {
20
+ private readonly org;
21
+ constructor(org: OrgClient);
22
+ run(assignments: DesiredAssignment[]): Promise<Resolution>;
23
+ findTargetsOfKind(kind: Kind, names: TargetName[]): Promise<OrgTarget[]>;
24
+ }
25
+ //# sourceMappingURL=resolution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolution.d.ts","sourceRoot":"","sources":["../../src/services/resolution.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,iBAAiB,EACjB,IAAI,EACJ,SAAS,EAET,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,OAAO,EAQV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD;;;;GAIG;AACH,qBAAa,UAAU;aAEC,QAAQ,EAAE,OAAO,EAAE;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAFV,QAAQ,EAAE,OAAO,EAAE,EAClB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAGjE,yFAAyF;IAClF,cAAc,IAAI,SAAS,EAAE;IAUpC,2FAA2F;IACpF,gBAAgB,CAAC,SAAS,EAAE,iBAAiB,EAAE,GAAG,gBAAgB,EAAE;CAO9E;AAED,gGAAgG;AAChG,qBAAa,iBAAiB;IACP,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,SAAS;IAErC,GAAG,CAAC,WAAW,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAyCvE,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;CAU3E"}
@@ -0,0 +1,78 @@
1
+ import { kinds, distinctAssignees, distinctTargets, evaluateUsers, evaluateTargets, indexUsersById, indexTargetsById, } from '../core/index.js';
2
+ /**
3
+ * What the org answered for every declared reference: the findings, plus the org ids of
4
+ * the references that did resolve. The indexes stay private because they are keyed by the
5
+ * identifiers' comparison key, and that rule belongs here rather than at every lookup.
6
+ */
7
+ export class Resolution {
8
+ findings;
9
+ userIds;
10
+ targetIds;
11
+ constructor(findings, userIds, targetIds) {
12
+ this.findings = findings;
13
+ this.userIds = userIds;
14
+ this.targetIds = targetIds;
15
+ }
16
+ /** Every target that resolved, as the managed set to compare the org's state against. */
17
+ managedTargets() {
18
+ const refs = [];
19
+ for (const kind of kinds) {
20
+ for (const id of this.targetIds[kind].values()) {
21
+ refs.push({ kind, id });
22
+ }
23
+ }
24
+ return refs;
25
+ }
26
+ /** Attach the resolved assignee and target ids to each addition, so it can be inserted. */
27
+ resolveAdditions(additions) {
28
+ return additions.map((addition) => ({
29
+ ...addition,
30
+ assigneeId: this.userIds.get(addition.assignee.asKey()) ?? '',
31
+ targetId: this.targetIds[addition.kind].get(addition.target.asKey()) ?? '',
32
+ }));
33
+ }
34
+ }
35
+ /** Look every declared reference up in the org, returning findings and the resolved id maps. */
36
+ export class ResolutionService {
37
+ org;
38
+ constructor(org) {
39
+ this.org = org;
40
+ }
41
+ async run(assignments) {
42
+ const usernames = distinctAssignees(assignments);
43
+ const targetsByKind = kinds.map((kind) => ({ kind, targets: distinctTargets(assignments, kind) }));
44
+ const usersTask = usernames.length > 0 ? this.org.findUsers(usernames) : Promise.resolve([]);
45
+ const targetsTask = Promise.all(targetsByKind.map(async ({ kind, targets }) => {
46
+ if (targets.length === 0)
47
+ return { kind, targets, found: [] };
48
+ const found = await this.findTargetsOfKind(kind, targets);
49
+ return { kind, targets, found };
50
+ }));
51
+ const [foundUsers, perKind] = await Promise.all([
52
+ usersTask,
53
+ targetsTask,
54
+ ]);
55
+ const findings = [...evaluateUsers(usernames, foundUsers)];
56
+ for (const { kind, targets, found } of perKind) {
57
+ findings.push(...evaluateTargets(kind, targets, found.map((target) => target.name)));
58
+ }
59
+ const targetIds = {};
60
+ for (const { kind, found } of perKind) {
61
+ targetIds[kind] = indexTargetsById(found);
62
+ }
63
+ return new Resolution(findings, indexUsersById(foundUsers), targetIds);
64
+ }
65
+ // No default case on purpose: a new Kind then fails to compile here, which is a
66
+ // better guard than a runtime throw the type system already proves unreachable.
67
+ findTargetsOfKind(kind, names) {
68
+ switch (kind) {
69
+ case 'permissionSet':
70
+ return this.org.findPermissionSets(names);
71
+ case 'permissionSetGroup':
72
+ return this.org.findPermissionSetGroups(names);
73
+ case 'permissionSetLicense':
74
+ return this.org.findPermissionSetLicenses(names);
75
+ }
76
+ }
77
+ }
78
+ //# sourceMappingURL=resolution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolution.js","sourceRoot":"","sources":["../../src/services/resolution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { DesiredAssignment, Finding, Kind, OrgTarget, TargetName } from '../core/index.js';
2
+ import { OrgClient } from './adapters/index.js';
3
+ export type ValidateResult = {
4
+ files: string[];
5
+ assignments: DesiredAssignment[];
6
+ findings: Finding[];
7
+ errors: number;
8
+ warnings: number;
9
+ failed: boolean;
10
+ };
11
+ /** Load the files, then resolve every reference against the org. */
12
+ export declare class ValidateService {
13
+ private readonly org;
14
+ constructor(org: OrgClient);
15
+ run(files: string[]): Promise<ValidateResult>;
16
+ /** Look every reference up in the org (in parallel) and evaluate the results. */
17
+ private resolve;
18
+ private evaluateUserRefs;
19
+ private evaluateTargetRefs;
20
+ findTargetsOfKind(kind: Kind, names: TargetName[]): Promise<OrgTarget[]>;
21
+ }
22
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/services/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAOH,iBAAiB,EACjB,OAAO,EACP,IAAI,EAEJ,SAAS,EACT,UAAU,EAEb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,MAAM,cAAc,GAAG;IACzB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,oEAAoE;AACpE,qBAAa,eAAe;IACL,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,SAAS;IAErC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IAoB1D,iFAAiF;YACnE,OAAO;YAmBP,gBAAgB;YAKhB,kBAAkB;IAWhC,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;CAU3E"}
@@ -0,0 +1,62 @@
1
+ import { loadFiles, kinds, distinctAssignees, distinctTargets, evaluateUsers, evaluateTargets, countFindings, } from '../core/index.js';
2
+ /** Load the files, then resolve every reference against the org. */
3
+ export class ValidateService {
4
+ org;
5
+ constructor(org) {
6
+ this.org = org;
7
+ }
8
+ async run(files) {
9
+ const loaded = await loadFiles(files);
10
+ const resolved = await this.resolve(loaded.assignments);
11
+ const findings = [
12
+ ...loaded.findings,
13
+ ...resolved,
14
+ ];
15
+ const { errors, warnings } = countFindings(findings);
16
+ return {
17
+ files: loaded.files,
18
+ assignments: loaded.assignments,
19
+ findings,
20
+ errors,
21
+ warnings,
22
+ failed: errors > 0,
23
+ };
24
+ }
25
+ /** Look every reference up in the org (in parallel) and evaluate the results. */
26
+ async resolve(assignments) {
27
+ const tasks = [];
28
+ const usernames = distinctAssignees(assignments);
29
+ if (usernames.length > 0) {
30
+ tasks.push(this.evaluateUserRefs(usernames));
31
+ }
32
+ for (const kind of kinds) {
33
+ const targets = distinctTargets(assignments, kind);
34
+ if (targets.length > 0) {
35
+ tasks.push(this.evaluateTargetRefs(kind, targets));
36
+ }
37
+ }
38
+ const results = await Promise.all(tasks);
39
+ return results.flat();
40
+ }
41
+ async evaluateUserRefs(usernames) {
42
+ const found = await this.org.findUsers(usernames);
43
+ return evaluateUsers(usernames, found);
44
+ }
45
+ async evaluateTargetRefs(kind, targets) {
46
+ const found = await this.findTargetsOfKind(kind, targets);
47
+ return evaluateTargets(kind, targets, found.map((target) => target.name));
48
+ }
49
+ // No default case on purpose: a new Kind then fails to compile here, which is a
50
+ // better guard than a runtime throw the type system already proves unreachable.
51
+ findTargetsOfKind(kind, names) {
52
+ switch (kind) {
53
+ case 'permissionSet':
54
+ return this.org.findPermissionSets(names);
55
+ case 'permissionSetGroup':
56
+ return this.org.findPermissionSetGroups(names);
57
+ case 'permissionSetLicense':
58
+ return this.org.findPermissionSetLicenses(names);
59
+ }
60
+ }
61
+ }
62
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/services/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,SAAS,EACT,KAAK,EACL,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,eAAe,EAIf,aAAa,GAIhB,MAAM,kBAAkB,CAAC;AAY1B,oEAAoE;AACpE,MAAM,OAAO,eAAe;IACY;IAApC,YAAoC,GAAc;QAAd,QAAG,GAAH,GAAG,CAAW;IAAI,CAAC;IAEhD,KAAK,CAAC,GAAG,CAAC,KAAe;QAC5B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAExD,MAAM,QAAQ,GAAG;YACb,GAAG,MAAM,CAAC,QAAQ;YAClB,GAAG,QAAQ;SACd,CAAC;QACF,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QAErD,OAAO;YACH,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,QAAQ;YACR,MAAM;YACN,QAAQ;YACR,MAAM,EAAE,MAAM,GAAG,CAAC;SACrB,CAAC;IACN,CAAC;IAED,iFAAiF;IACzE,KAAK,CAAC,OAAO,CAAC,WAAgC;QAClD,MAAM,KAAK,GAAyB,EAAE,CAAC;QAEvC,MAAM,SAAS,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;QACjD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,MAAM,OAAO,GAAG,eAAe,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACnD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;YACvD,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,SAAqB;QAChD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAClD,OAAO,aAAa,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,IAAU,EAAE,OAAqB;QAC9D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1D,OAAO,eAAe,CAClB,IAAI,EACJ,OAAO,EACP,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CACrC,CAAC;IACN,CAAC;IAED,gFAAgF;IAChF,gFAAgF;IAChF,iBAAiB,CAAC,IAAU,EAAE,KAAmB;QAC7C,QAAQ,IAAI,EAAE,CAAC;YACX,KAAK,eAAe;gBAChB,OAAO,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC9C,KAAK,oBAAoB;gBACrB,OAAO,IAAI,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;YACnD,KAAK,sBAAsB;gBACvB,OAAO,IAAI,CAAC,GAAG,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;QACzD,CAAC;IACL,CAAC;CACJ"}
@@ -0,0 +1,85 @@
1
+ # summary
2
+
3
+ Reconcile a target org to match the permission set assignment files.
4
+
5
+ # description
6
+
7
+ Load the files, resolve every user and target against the org, diff the desired state against what the org currently has, then add, update expirations, and/or remove assignments per the mode. Additions, expiration updates, and removals run through the sObject Collections API with partial success, so one bad record does not roll back the rest. Deletions are capped by --max-deletes and confirmed before they run. Run validate and a --dry-run first.
8
+
9
+ # flags.file.summary
10
+
11
+ YAML file or glob to apply. Repeatable.
12
+
13
+ # flags.mode.summary
14
+
15
+ Which half of the reconcile to run: additive adds missing assignments and updates expirations, destructive removes only, sync does both.
16
+
17
+ # flags.max-deletes.summary
18
+
19
+ Abort before any change if the run would remove more than this many assignments.
20
+
21
+ # flags.dry-run.summary
22
+
23
+ Resolve and diff, print the plan, and change nothing.
24
+
25
+ # flags.show-unchanged.summary
26
+
27
+ List assignments that already match, instead of only counting them.
28
+
29
+ # flags.no-prompt.summary
30
+
31
+ Skip the deletion confirmation prompt. Required to delete in JSON or other non-interactive runs.
32
+
33
+ # confirm.delete
34
+
35
+ This will remove %s assignment(s) from the org. Continue?
36
+
37
+ # summary.dryRun
38
+
39
+ Dry run: %s to add, %s to update, %s to remove. Nothing was changed.
40
+
41
+ # summary.applied
42
+
43
+ Applied: %s added, %s updated, %s removed.
44
+
45
+ # summary.declined
46
+
47
+ Aborted at the confirmation prompt. Nothing was changed.
48
+
49
+ # drift.note
50
+
51
+ %s change(s) the %s mode does not act on were skipped (drift). Run plan to see them.
52
+
53
+ # failure.line
54
+
55
+ failed to %s %s on %s: %s
56
+
57
+ # error.invalid
58
+
59
+ The files do not resolve cleanly against the org. Fix the errors above, then re-run.
60
+
61
+ # error.maxDeletes
62
+
63
+ Refusing to remove %s assignment(s): over the --max-deletes limit of %s. Raise the limit or narrow the change.
64
+
65
+ # error.promptInJson
66
+
67
+ Refusing to delete without confirmation in a non-interactive run. Re-run with --no-prompt.
68
+
69
+ # error.failed
70
+
71
+ Some changes failed. See the per-record errors above.
72
+
73
+ # examples
74
+
75
+ - Preview a full reconcile of the dev org without changing anything:
76
+
77
+ <%= config.bin %> <%= command.id %> --file "permissions/*.yml" --target-org dev --mode sync --dry-run
78
+
79
+ - Grant any missing assignments (additive, the default):
80
+
81
+ <%= config.bin %> <%= command.id %> --file "permissions/*.yml" --target-org dev
82
+
83
+ - Full reconcile of production in CI, without prompts:
84
+
85
+ <%= config.bin %> <%= command.id %> --file "permissions/*.yml" --target-org prod --mode sync --no-prompt