@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
package/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.0] - 2026-09-26
11
+
12
+ ### Added
13
+
14
+ - Warden domain logic extracted as a reusable core library for use across Warden CLI, VS Code extension, and SFDX package
15
+ - Zod file-format schemas and generated JSON Schema artifacts for validation and type-safety
16
+
17
+ ## [0.1.0] - 2026-09-26
18
+
19
+ ### Changed
20
+
21
+ - Internal maintenance and tooling updates
22
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jake Richter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # warden-core
2
+
3
+ Shared Warden engine: the user-lifecycle library behind the
4
+ [`warden`](https://github.com/Syntax-Syllogism/warden) Salesforce CLI plugin,
5
+ the Warden VS Code extension, and the Warden SFDX package.
6
+
7
+ warden-core is a plain Node/TypeScript library with no CLI framework
8
+ dependency. Call its functions directly from a script, an editor extension, a
9
+ CI job, or any other Node codebase.
10
+
11
+ The [domain guides](docs/) describe the implemented workflows and data
12
+ contracts for [access auditing](docs/access.md),
13
+ [lifecycle operations](docs/lifecycle.md), [provisioning](docs/provisioning.md),
14
+ [related records](docs/related-records.md), and [user matching](docs/matching.md).
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ npm install @syntax-syllogism/warden-core
20
+ ```
21
+
22
+ Requires Node.js 22 or later.
23
+
24
+ ## API
25
+
26
+ | Export | Purpose |
27
+ | --- | --- |
28
+ | `WardenError` | Base class for every error warden-core throws on purpose. Carries a stable `code`, optional structured `data`, and a default English `message`. |
29
+ | `isWardenError(error)` | Structural type guard for `WardenError`; safe across duplicate copies of this package. |
30
+ | `AccessError`, `UserAccessError` | Typed access-audit errors. |
31
+ | `LifecycleError` | Typed lifecycle-operation errors. |
32
+ | `ProvisioningError`, `DefinitionError` | Typed provisioning and definition-reading errors. |
33
+ | `RelatedRecordsError` | Typed related-record catalog errors. |
34
+ | File-format schemas and parsers | Zod schemas, JSON-text validators, and inferred types for persona, users, related-catalog, and snapshot files. |
35
+ | Lifecycle, access, provisioning, CSV, snapshot, and rendering functions | Framework-free domain operations used by Warden consumers. |
36
+
37
+ ```ts
38
+ import { isWardenError } from '@syntax-syllogism/warden-core';
39
+
40
+ try {
41
+ // call a warden-core function
42
+ } catch (error) {
43
+ if (isWardenError(error)) {
44
+ console.error(`${error.code}: ${error.message}`);
45
+ } else {
46
+ throw error;
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Errors
52
+
53
+ Errors are reported as `WardenError` instances (or area-specific subclasses).
54
+ The `code` and the shape of `data` are part of the public API; the `message`
55
+ text is not and may be reworded in any release.
56
+
57
+ | Code | Thrown by |
58
+ | --- | --- |
59
+ | `errorUnsupportedAccessType`, `errorInvalidTarget`, `errorFieldTargetMustBeQualified`, `errorObjectNotFound`, `errorFieldNotFound`, `errorApexClassNotFound`, `errorVisualforcePageNotFound`, `errorCustomPermissionNotFound`, `errorTabNotFound`, `errorRecordTypeTargetMustBeQualified`, `errorMasterRecordTypeUnsupported`, `errorRecordTypeNotFound`, `errorRecordTypeAmbiguous`, `errorRecordTypeInactive`, `errorRecordTypeMetadataReadFailed`, `errorAccessQueryFailed` | Access audit and target resolution. |
60
+ | `errorInvalidCsv`, `errorInvalidJson`, `errorInvalidPersonaDefinition`, `errorMissingUserFieldMap`, `errorPersonasWithoutDefinition` | Definition readers. |
61
+ | `errorInvalidJson`, `errorInvalidUserMatchField`, `errorInvalidUserValue`, `errorInvalidAgainstValue`, `errorInvalidAgainstMatchField`, `errorInvalidSnapshot`, `errorPromptDeclined` | Lifecycle targeting, snapshot validation, and operations. |
62
+ | `errorInvalidRelatedCatalog`, `errorRelationshipInvalidDefinition`, `errorRelationshipInvalidSobject`, `errorRelationshipMissingPhase`, `errorRelationshipInvalidPhase`, `errorPhaseBeforeUnsupported`, `errorLinkUserUnsupported`, `errorRelatedContextUnsupported`, `errorRelationshipInvalidMatch`, `errorRelationshipMatchFromUserId`, `errorRelationshipInvalidFields`, `errorRelationshipInvalidSource`, `errorRelationshipInvalidFrom`, `errorRelationshipUnknownUserField`, `errorRelationshipUnwritableField`, `errorRelationshipInvalidMode`, `errorRelationshipInvalidRecordType` | Related-record catalog validation. |
63
+ | `errorDuplicateExternalIdMatch`, `errorMissingRequiredFields`, `errorMissingSaveId`, `errorPromptDeclined`, `errorInvalidJson`, `errorInvalidPersonaDefinition`, `errorPersonasWithoutDefinition` | Provisioning execution and planning. |
64
+ | `schema-invalid`, `schema-version-unsupported` | Structural file-format validation. `data.issues` contains `{ path, message }` entries. |
65
+
66
+ ## File formats and schemas
67
+
68
+ The four JSON file formats are defined by the exported Zod schemas and the
69
+ generated Draft 2020-12 schemas. See the detailed
70
+ [file-format schema guide](docs/spec-schemas.md)
71
+ for the full structural contract, parser results, versioning behavior, and
72
+ artifact-generation workflow.
73
+
74
+ - [persona definitions](schemas/persona-definitions.schema.json):
75
+ `{ personas: Record<string, Persona> }`.
76
+ - [users definitions](schemas/users-definition.schema.json):
77
+ `{ users: UserInput[] }`, where User fields are an open record and
78
+ `personas` is an optional string array.
79
+ - [related catalog](schemas/related-catalog.schema.json):
80
+ `{ relationships: Record<string, RelationshipDef> }`.
81
+ - [snapshot](schemas/snapshot.schema.json): the lifecycle snapshot with
82
+ `snapshotVersion: 1`.
83
+
84
+ ## Versioning
85
+
86
+ warden-core follows [Semantic Versioning](https://semver.org/). Removing or
87
+ renaming an export, changing a signature or result shape, changing an error
88
+ `code`, or rejecting input that was previously valid is a major change.
89
+ Consumers should pin an exact version and upgrade deliberately.
90
+
91
+ ## Development
92
+
93
+ ```bash
94
+ npm install
95
+ npm run build
96
+ npm test # typecheck, lint, prettier, mocha + coverage
97
+ npm run pack:check
98
+ ```
99
+
100
+ ## Contributing
101
+
102
+ See [CONTRIBUTING.md](CONTRIBUTING.md) and the
103
+ [Code of Conduct](CODE_OF_CONDUCT.md).
104
+
105
+ ## Security
106
+
107
+ See [SECURITY.md](SECURITY.md) for how to report vulnerabilities.
108
+
109
+ ## License
110
+
111
+ [MIT](LICENSE) © Jake Richter
@@ -0,0 +1,27 @@
1
+ import type { Connection } from '@salesforce/core';
2
+ import type { AccessTargetType, UserAccessResult, UserAccessRow, UserAccessStats } from './types.js';
3
+ export type PermissionSetParent = {
4
+ Id: string;
5
+ Name?: string;
6
+ DeveloperName?: string;
7
+ Label?: string;
8
+ MasterLabel?: string;
9
+ Type?: string;
10
+ IsOwnedByProfile?: boolean;
11
+ ProfileId?: string;
12
+ Profile?: {
13
+ Name?: string;
14
+ };
15
+ };
16
+ export type AccessBuildContext = {
17
+ assignmentType: 'PermissionSet' | 'PermissionSetGroup';
18
+ permissionSetId: string;
19
+ psgId?: string;
20
+ };
21
+ export type BuildAccess<TGrant, TAccess extends UserAccessRow['access']> = (grant: TGrant, context: AccessBuildContext) => TAccess | undefined;
22
+ export type AssigneeResolutionOptions = {
23
+ preparePsg?: (psgIds: string[]) => Promise<void>;
24
+ };
25
+ export declare const computeStats: (rows: UserAccessRow[]) => UserAccessStats;
26
+ export declare function resolveAssignees<TGrant, TAccess extends UserAccessRow['access']>(conn: Connection, targetType: AccessTargetType, targetName: string, grantByPermissionSetId: Map<string, TGrant>, permissionSetById: Map<string, PermissionSetParent>, buildAccess: BuildAccess<TGrant, TAccess>, options?: AssigneeResolutionOptions): Promise<UserAccessRow[]>;
27
+ export declare const resultFor: (targetType: AccessTargetType, targetName: string, rows: UserAccessRow[], warnings?: string[], extras?: Pick<UserAccessResult, "sobjectType" | "fieldApiName">) => UserAccessResult;
@@ -0,0 +1,139 @@
1
+ import { queryAllInChunks, soqlIn } from './soql.js';
2
+ export const computeStats = (rows) => ({
3
+ totalActiveUsersWithAccess: new Set(rows.map((row) => row.userId)).size,
4
+ profileGrants: new Set(rows.filter((row) => row.assignmentType === 'Profile').map((row) => row.sourceId)).size,
5
+ permissionSetGrants: new Set(rows.filter((row) => row.assignmentType === 'PermissionSet').map((row) => row.sourceId))
6
+ .size,
7
+ permissionSetGroupGrants: new Set(rows.filter((row) => row.assignmentType === 'PermissionSetGroup').map((row) => row.sourceId)).size,
8
+ });
9
+ const keyFor = (row) => [row.userId, row.assignmentType, row.sourceId, row.viaPermissionSetId ?? ''].join('|');
10
+ // eslint-disable-next-line complexity
11
+ export async function resolveAssignees(conn, targetType, targetName, grantByPermissionSetId, permissionSetById, buildAccess, options = {}) {
12
+ const directPermissionSetIds = [...grantByPermissionSetId.keys()].filter((id) => permissionSetById.get(id)?.Type !== 'Group');
13
+ const componentPermissionSetIds = directPermissionSetIds.filter((id) => !permissionSetById.get(id)?.IsOwnedByProfile);
14
+ const psgComponentRows = await queryAllInChunks(conn, componentPermissionSetIds, (chunk) => [
15
+ 'SELECT PermissionSetGroupId, PermissionSetGroup.DeveloperName, PermissionSetGroup.MasterLabel, PermissionSetId, PermissionSet.Name, PermissionSet.Type',
16
+ 'FROM PermissionSetGroupComponent',
17
+ `WHERE PermissionSetId IN (${soqlIn(chunk)})`,
18
+ ].join(' '));
19
+ const psgByPermissionSetId = new Map();
20
+ const psgNameById = new Map();
21
+ const psgApiNameById = new Map();
22
+ const psgLabelById = new Map();
23
+ for (const row of psgComponentRows) {
24
+ if (row.PermissionSetGroup?.DeveloperName) {
25
+ psgApiNameById.set(row.PermissionSetGroupId, row.PermissionSetGroup.DeveloperName);
26
+ }
27
+ if (row.PermissionSetGroup?.MasterLabel) {
28
+ psgLabelById.set(row.PermissionSetGroupId, row.PermissionSetGroup.MasterLabel);
29
+ }
30
+ const psgName = row.PermissionSetGroup?.MasterLabel ??
31
+ row.PermissionSetGroup?.DeveloperName ??
32
+ psgNameById.get(row.PermissionSetGroupId) ??
33
+ '(Unnamed Permission Set Group)';
34
+ psgNameById.set(row.PermissionSetGroupId, psgName);
35
+ const entries = psgByPermissionSetId.get(row.PermissionSetId) ?? [];
36
+ entries.push({ psgId: row.PermissionSetGroupId, psgName });
37
+ psgByPermissionSetId.set(row.PermissionSetId, entries);
38
+ }
39
+ const psgIds = [...new Set(psgComponentRows.map((row) => row.PermissionSetGroupId))];
40
+ await options.preparePsg?.(psgIds);
41
+ if (directPermissionSetIds.length === 0 && psgIds.length === 0)
42
+ return [];
43
+ const assignmentRowsById = new Map();
44
+ const assignmentSelect = [
45
+ 'SELECT Id, AssigneeId, Assignee.Name, Assignee.Username, Assignee.IsActive, PermissionSetId, PermissionSet.Name, PermissionSet.IsOwnedByProfile, PermissionSet.ProfileId, PermissionSet.Profile.Name, PermissionSet.Type, PermissionSetGroupId, PermissionSetGroup.DeveloperName, PermissionSetGroup.MasterLabel',
46
+ 'FROM PermissionSetAssignment',
47
+ 'WHERE Assignee.IsActive = true',
48
+ ];
49
+ const assignmentRowsByPermissionSet = await queryAllInChunks(conn, directPermissionSetIds, (chunk) => [...assignmentSelect, `AND PermissionSetId IN (${soqlIn(chunk)})`, 'ORDER BY Assignee.Name, Id'].join(' '));
50
+ for (const row of assignmentRowsByPermissionSet)
51
+ assignmentRowsById.set(row.Id, row);
52
+ const assignmentRowsByPsg = await queryAllInChunks(conn, psgIds, (chunk) => [...assignmentSelect, `AND PermissionSetGroupId IN (${soqlIn(chunk)})`, 'ORDER BY Assignee.Name, Id'].join(' '));
53
+ for (const row of assignmentRowsByPsg)
54
+ assignmentRowsById.set(row.Id, row);
55
+ const rowsByKey = new Map();
56
+ for (const row of assignmentRowsById.values()) {
57
+ if (row.Assignee?.IsActive === false)
58
+ continue;
59
+ const userName = row.Assignee?.Name ?? row.AssigneeId;
60
+ const username = row.Assignee?.Username ?? '';
61
+ if (row.PermissionSetId && grantByPermissionSetId.has(row.PermissionSetId)) {
62
+ const parent = permissionSetById.get(row.PermissionSetId) ?? row.PermissionSet;
63
+ if (parent?.Type !== 'Group') {
64
+ const context = { assignmentType: 'PermissionSet', permissionSetId: row.PermissionSetId };
65
+ const grant = grantByPermissionSetId.get(row.PermissionSetId);
66
+ const access = grant === undefined ? undefined : buildAccess(grant, context);
67
+ if (access !== undefined) {
68
+ const isProfile = parent?.IsOwnedByProfile === true;
69
+ const resolvedRow = {
70
+ userId: row.AssigneeId,
71
+ userName,
72
+ username,
73
+ targetType,
74
+ targetName,
75
+ assignmentType: isProfile ? 'Profile' : 'PermissionSet',
76
+ sourceId: isProfile ? parent?.ProfileId ?? row.PermissionSetId : row.PermissionSetId,
77
+ sourceName: isProfile
78
+ ? parent?.Profile?.Name ?? parent?.Name ?? 'Profile'
79
+ : parent?.Name ?? row.PermissionSetId,
80
+ sourceApiName: parent?.DeveloperName ?? parent?.Name ?? row.PermissionSetId,
81
+ sourceLabel: parent?.MasterLabel ?? parent?.Label ?? parent?.Profile?.Name ?? parent?.Name ?? row.PermissionSetId,
82
+ access,
83
+ };
84
+ rowsByKey.set(keyFor(resolvedRow), resolvedRow);
85
+ }
86
+ }
87
+ }
88
+ if (row.PermissionSetGroupId) {
89
+ const entries = [...psgByPermissionSetId.entries()]
90
+ .filter(([, psgEntries]) => psgEntries.some((entry) => entry.psgId === row.PermissionSetGroupId))
91
+ .flatMap(([permissionSetId, psgEntries]) => psgEntries.filter((entry) => entry.psgId === row.PermissionSetGroupId).map(() => permissionSetId));
92
+ for (const permissionSetId of entries) {
93
+ const grantingAccess = grantByPermissionSetId.get(permissionSetId);
94
+ if (grantingAccess === undefined)
95
+ continue;
96
+ const context = {
97
+ assignmentType: 'PermissionSetGroup',
98
+ permissionSetId,
99
+ psgId: row.PermissionSetGroupId,
100
+ };
101
+ const access = buildAccess(grantingAccess, context);
102
+ if (access === undefined)
103
+ continue;
104
+ const sourceName = row.PermissionSetGroup?.MasterLabel ??
105
+ row.PermissionSetGroup?.DeveloperName ??
106
+ psgNameById.get(row.PermissionSetGroupId) ??
107
+ row.PermissionSetGroupId;
108
+ const resolvedRow = {
109
+ userId: row.AssigneeId,
110
+ userName,
111
+ username,
112
+ targetType,
113
+ targetName,
114
+ assignmentType: 'PermissionSetGroup',
115
+ sourceId: row.PermissionSetGroupId,
116
+ sourceName,
117
+ sourceApiName: row.PermissionSetGroup?.DeveloperName ??
118
+ psgApiNameById.get(row.PermissionSetGroupId) ??
119
+ row.PermissionSetGroupId,
120
+ sourceLabel: row.PermissionSetGroup?.MasterLabel ?? psgLabelById.get(row.PermissionSetGroupId) ?? sourceName,
121
+ viaPermissionSetId: permissionSetId,
122
+ viaPermissionSetName: permissionSetById.get(permissionSetId)?.Name ?? permissionSetId,
123
+ access,
124
+ };
125
+ rowsByKey.set(keyFor(resolvedRow), resolvedRow);
126
+ }
127
+ }
128
+ }
129
+ return [...rowsByKey.values()];
130
+ }
131
+ export const resultFor = (targetType, targetName, rows, warnings = [], extras = {}) => ({
132
+ targetType,
133
+ targetName,
134
+ ...extras,
135
+ rows,
136
+ stats: computeStats(rows),
137
+ warnings,
138
+ });
139
+ //# sourceMappingURL=assignees.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assignees.js","sourceRoot":"","sources":["../../src/access/assignees.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const accessMessage: (code: string, args?: string[]) => string;
@@ -0,0 +1,24 @@
1
+ const TEXT = {
2
+ errorUnsupportedAccessType: 'Unsupported access type: %s.',
3
+ errorInvalidTarget: 'Invalid target value: %s.',
4
+ errorFieldTargetMustBeQualified: 'Field target must be qualified as ObjectApiName.FieldApiName: %s.',
5
+ errorObjectNotFound: 'Object not found: %s.',
6
+ errorFieldNotFound: 'Object %s does not have field %s.',
7
+ errorApexClassNotFound: 'Apex class not found: %s.',
8
+ errorVisualforcePageNotFound: 'Visualforce page not found: %s.',
9
+ errorCustomPermissionNotFound: 'Custom permission not found: %s.',
10
+ errorTabNotFound: 'Tab not found: %s.',
11
+ errorRecordTypeTargetMustBeQualified: 'Record type target must be qualified as SObject.DeveloperName for an active, non-master record type: %s.',
12
+ errorMasterRecordTypeUnsupported: 'The Master record type is not supported. Specify an active non-master record type as SObject.DeveloperName: %s.',
13
+ errorRecordTypeNotFound: 'Record type not found or ambiguous: %s.',
14
+ errorRecordTypeAmbiguous: 'Record type target matched multiple records and cannot be selected safely: %s.',
15
+ errorRecordTypeInactive: 'Record type is inactive: %s.',
16
+ errorRecordTypeMetadataReadFailed: 'Unable to read complete %s metadata for record-type access audit (%s). No partial audit result was returned. Record-type auditing reads every profile and permission set through the Metadata API, so the authenticated user needs org-wide metadata read access. Grant these system permissions: "API Enabled", "View Setup and Configuration", and either "Modify Metadata Through Metadata API Functions" or "Modify All Data". On large orgs a user missing "Modify All Data" (or the granular "Modify Metadata" permission) is silently served an incomplete metadata set rather than an error, which is the usual cause of this failure.',
17
+ errorAccessQueryFailed: 'Failed to resolve access for %s target %s.',
18
+ };
19
+ export const accessMessage = (code, args = []) => {
20
+ const template = TEXT[code] ?? code;
21
+ let index = 0;
22
+ return template.replaceAll('%s', () => args[index++] ?? '');
23
+ };
24
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/access/messages.ts"],"names":[],"mappings":"AAAA,MAAM,IAAI,GAA2B;IACnC,0BAA0B,EAAE,8BAA8B;IAC1D,kBAAkB,EAAE,2BAA2B;IAC/C,+BAA+B,EAAE,mEAAmE;IACpG,mBAAmB,EAAE,uBAAuB;IAC5C,kBAAkB,EAAE,mCAAmC;IACvD,sBAAsB,EAAE,2BAA2B;IACnD,4BAA4B,EAAE,iCAAiC;IAC/D,6BAA6B,EAAE,kCAAkC;IACjE,gBAAgB,EAAE,oBAAoB;IACtC,oCAAoC,EAClC,0GAA0G;IAC5G,gCAAgC,EAC9B,iHAAiH;IACnH,uBAAuB,EAAE,yCAAyC;IAClE,wBAAwB,EAAE,gFAAgF;IAC1G,uBAAuB,EAAE,8BAA8B;IACvD,iCAAiC,EAC/B,gnBAAgnB;IAClnB,sBAAsB,EAAE,4CAA4C;CACrE,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,OAAiB,EAAE,EAAU,EAAE;IACzE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IACpC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC9D,CAAC,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { Connection } from '@salesforce/core';
2
+ export declare const METADATA_BATCH_SIZE = 10;
3
+ export declare const METADATA_CONCURRENCY = 2;
4
+ type MetadataComponent = {
5
+ fullName: string;
6
+ } & Record<string, unknown>;
7
+ export type MetadataType = 'Profile' | 'PermissionSet' | 'MutingPermissionSet';
8
+ export type MetadataReadResult<T> = {
9
+ metadata: Map<string, T>;
10
+ missing: string[];
11
+ };
12
+ /**
13
+ * Warning shown when a record-type audit could not read every profile,
14
+ * permission set, or muting permission set because the running user lacks
15
+ * org-wide metadata read access. The audit continues with what it could read.
16
+ */
17
+ export declare const partialMetadataWarning: (missingNames: string[]) => string;
18
+ /**
19
+ * Read components in bounded batches.
20
+ *
21
+ * Fails closed for genuinely broken responses (a rejected read, a non-object
22
+ * response, or a malformed, unexpected, or duplicated component) — those signal
23
+ * a misconfiguration the caller should not paper over. It fails *open* for a
24
+ * merely incomplete response: on large orgs the Metadata API silently omits
25
+ * components the running user cannot read rather than erroring, so the omitted
26
+ * fullNames are returned in `missing` for the caller to report as a partial
27
+ * result instead of aborting the whole audit.
28
+ */
29
+ export declare function readMetadataInBatches<T>(conn: Connection, type: MetadataType, fullNames: string[], options?: {
30
+ batchSize?: number;
31
+ concurrency?: number;
32
+ }): Promise<MetadataReadResult<T>>;
33
+ export declare const profileMetadataNamesById: (conn: Connection) => Promise<Map<string, string>>;
34
+ export declare const mutingPermissionSetMetadataNamesById: (conn: Connection) => Promise<Map<string, string>>;
35
+ export type RecordTypeVisibility = {
36
+ recordType: string;
37
+ visible: boolean;
38
+ default?: boolean;
39
+ };
40
+ export declare const recordTypeVisibilities: (metadata: MetadataComponent, type: MetadataType) => RecordTypeVisibility[];
41
+ export {};
@@ -0,0 +1,168 @@
1
+ import { UserAccessError } from './types.js';
2
+ export const METADATA_BATCH_SIZE = 10;
3
+ export const METADATA_CONCURRENCY = 2;
4
+ const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
5
+ const responseItems = (response) => {
6
+ if (response === null || response === undefined)
7
+ return [];
8
+ if (Array.isArray(response))
9
+ return response;
10
+ if (isRecord(response))
11
+ return [response];
12
+ throw new Error('Metadata API returned a non-object response.');
13
+ };
14
+ const metadataFailure = (type, names, cause) => new UserAccessError('errorRecordTypeMetadataReadFailed', [type, names.join(', ')], cause);
15
+ const validateBatch = (type, requestedNames, response) => {
16
+ let items;
17
+ try {
18
+ items = responseItems(response);
19
+ }
20
+ catch (error) {
21
+ throw metadataFailure(type, requestedNames, error);
22
+ }
23
+ const requested = new Set(requestedNames);
24
+ const seen = new Set();
25
+ const components = [];
26
+ for (const item of items) {
27
+ if (!isRecord(item)) {
28
+ throw metadataFailure(type, requestedNames, new Error('Metadata API returned a non-object component.'));
29
+ }
30
+ // Large orgs return an empty placeholder component (a well-formed object with
31
+ // no usable fullName) for a requested component the running user cannot read,
32
+ // instead of omitting it from the response array. Treat that as unreadable:
33
+ // skip it so it surfaces below as a partial `missing` result rather than
34
+ // failing the whole audit closed.
35
+ if (typeof item.fullName !== 'string' || !item.fullName) {
36
+ continue;
37
+ }
38
+ if (!requested.has(item.fullName)) {
39
+ throw metadataFailure(type, requestedNames, new Error(`Unexpected component ${item.fullName}.`));
40
+ }
41
+ if (seen.has(item.fullName)) {
42
+ throw metadataFailure(type, requestedNames, new Error(`Duplicate component ${item.fullName}.`));
43
+ }
44
+ seen.add(item.fullName);
45
+ components.push(item);
46
+ }
47
+ return components;
48
+ };
49
+ /**
50
+ * Warning shown when a record-type audit could not read every profile,
51
+ * permission set, or muting permission set because the running user lacks
52
+ * org-wide metadata read access. The audit continues with what it could read.
53
+ */
54
+ export const partialMetadataWarning = (missingNames) => {
55
+ const examples = missingNames.slice(0, 5);
56
+ const suffix = missingNames.length > examples.length ? ', …' : '';
57
+ return (`Partial response: ${missingNames.length} metadata component(s) could not be read through the Metadata API ` +
58
+ `(${examples.join(', ')}${suffix}). Affected profiles and permission sets are omitted, and any muting they define ` +
59
+ 'is not applied, so this audit may be incomplete. Grant the running user "API Enabled", ' +
60
+ '"View Setup and Configuration", and either "Modify Metadata Through Metadata API Functions" or "Modify All Data" ' +
61
+ 'for a full accounting.');
62
+ };
63
+ /**
64
+ * Read components in bounded batches.
65
+ *
66
+ * Fails closed for genuinely broken responses (a rejected read, a non-object
67
+ * response, or a malformed, unexpected, or duplicated component) — those signal
68
+ * a misconfiguration the caller should not paper over. It fails *open* for a
69
+ * merely incomplete response: on large orgs the Metadata API silently omits
70
+ * components the running user cannot read rather than erroring, so the omitted
71
+ * fullNames are returned in `missing` for the caller to report as a partial
72
+ * result instead of aborting the whole audit.
73
+ */
74
+ export async function readMetadataInBatches(conn, type, fullNames, options = {}) {
75
+ const batchSize = options.batchSize ?? METADATA_BATCH_SIZE;
76
+ const concurrency = options.concurrency ?? METADATA_CONCURRENCY;
77
+ if (!Number.isInteger(batchSize) || batchSize <= 0)
78
+ throw new Error('Metadata batchSize must be greater than 0.');
79
+ if (!Number.isInteger(concurrency) || concurrency <= 0)
80
+ throw new Error('Metadata concurrency must be greater than 0.');
81
+ const uniqueNames = [...new Set(fullNames)];
82
+ if (uniqueNames.length === 0)
83
+ return { metadata: new Map(), missing: [] };
84
+ const batches = [];
85
+ for (let index = 0; index < uniqueNames.length; index += batchSize) {
86
+ batches.push(uniqueNames.slice(index, index + batchSize));
87
+ }
88
+ const batchResults = Array.from({ length: batches.length }, () => []);
89
+ let nextBatch = 0;
90
+ const worker = async () => {
91
+ while (nextBatch < batches.length) {
92
+ const batchIndex = nextBatch;
93
+ nextBatch += 1;
94
+ const batch = batches[batchIndex];
95
+ try {
96
+ // eslint-disable-next-line no-await-in-loop
97
+ const response = await conn.metadata.read(type, batch);
98
+ batchResults[batchIndex] = validateBatch(type, batch, response);
99
+ }
100
+ catch (error) {
101
+ if (error instanceof UserAccessError)
102
+ throw error;
103
+ throw metadataFailure(type, batch, error);
104
+ }
105
+ }
106
+ };
107
+ await Promise.all(Array.from({ length: Math.min(concurrency, batches.length) }, () => worker()));
108
+ const result = new Map();
109
+ for (const components of batchResults) {
110
+ for (const component of components) {
111
+ if (result.has(component.fullName)) {
112
+ throw metadataFailure(type, [component.fullName], new Error(`Duplicate component ${component.fullName}.`));
113
+ }
114
+ result.set(component.fullName, component);
115
+ }
116
+ }
117
+ const missing = uniqueNames.filter((name) => !result.has(name));
118
+ return { metadata: result, missing };
119
+ }
120
+ /**
121
+ * Map each component's record Id (15- and 18-char) to the fullName the Metadata
122
+ * API expects, using a metadata listing.
123
+ *
124
+ * This solves two record-type audit problems that only appear against real orgs.
125
+ * Standard profiles expose a metadata name that differs from the SOQL Name/label
126
+ * (for example "Contract Manager" is "ContractManager" and "Standard User" is
127
+ * "Standard"), and non-auditable system profiles such as Automated Process are
128
+ * omitted from the listing entirely. Muting permission sets are a separate object
129
+ * whose Ids are not returned by a PermissionSet SOQL query and whose
130
+ * PermissionSetGroupComponent.PermissionSet relationship is null; the listing is
131
+ * the reliable Id to fullName source. Callers translate through this map and skip
132
+ * Ids it does not contain.
133
+ */
134
+ const metadataNamesById = async (conn, type) => {
135
+ const response = await conn.metadata.list([{ type }], conn.getApiVersion());
136
+ const items = Array.isArray(response) ? response : response ? [response] : [];
137
+ const byId = new Map();
138
+ for (const item of items) {
139
+ if (typeof item?.id === 'string' && item.id && typeof item.fullName === 'string' && item.fullName) {
140
+ // Key on the canonical 15-char Id so lookups work whether the listing and
141
+ // the SOQL Id come back 15- or 18-char.
142
+ byId.set(item.id.substring(0, 15), item.fullName);
143
+ }
144
+ }
145
+ return byId;
146
+ };
147
+ export const profileMetadataNamesById = (conn) => metadataNamesById(conn, 'Profile');
148
+ export const mutingPermissionSetMetadataNamesById = (conn) => metadataNamesById(conn, 'MutingPermissionSet');
149
+ export const recordTypeVisibilities = (metadata, type) => {
150
+ const raw = metadata.recordTypeVisibilities;
151
+ const entries = raw === undefined || raw === null ? [] : Array.isArray(raw) ? raw : [raw];
152
+ const normalized = [];
153
+ for (const entry of entries) {
154
+ if (!isRecord(entry) || typeof entry.recordType !== 'string' || typeof entry.visible !== 'boolean') {
155
+ throw metadataFailure(type, [metadata.fullName], new Error('Malformed recordTypeVisibilities entry.'));
156
+ }
157
+ if (entry.default !== undefined && typeof entry.default !== 'boolean') {
158
+ throw metadataFailure(type, [metadata.fullName], new Error('Malformed record type default value.'));
159
+ }
160
+ normalized.push({
161
+ recordType: entry.recordType,
162
+ visible: entry.visible,
163
+ ...(entry.default === undefined ? {} : { default: entry.default }),
164
+ });
165
+ }
166
+ return normalized;
167
+ };
168
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/access/metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Connection } from '@salesforce/core';
2
+ export type PsgMutingState<TMask> = {
3
+ permissionSetIdsByGroup: Map<string, string[]>;
4
+ masksByPermissionSetId: Map<string, TMask>;
5
+ };
6
+ export declare function loadPsgMuting<TMask>(conn: Connection, psgIds: string[], loadMasks: (permissionSetIds: string[]) => Promise<Map<string, TMask>>): Promise<PsgMutingState<TMask>>;
7
+ export declare const combinePsgMuting: <TMask>(psgId: string | undefined, state: PsgMutingState<TMask>, emptyMask: TMask, combine: (left: TMask, right: TMask) => TMask) => TMask;
@@ -0,0 +1,22 @@
1
+ import { queryAllInChunks, soqlIn } from './soql.js';
2
+ export async function loadPsgMuting(conn, psgIds, loadMasks) {
3
+ if (psgIds.length === 0) {
4
+ return { permissionSetIdsByGroup: new Map(), masksByPermissionSetId: new Map() };
5
+ }
6
+ const components = await queryAllInChunks(conn, psgIds, (chunk) => [
7
+ 'SELECT PermissionSetGroupId, PermissionSetId',
8
+ 'FROM PermissionSetGroupComponent',
9
+ `WHERE PermissionSetGroupId IN (${soqlIn(chunk)})`,
10
+ "AND PermissionSet.Type = 'Muting'",
11
+ ].join(' '));
12
+ const permissionSetIdsByGroup = new Map();
13
+ for (const component of components) {
14
+ const ids = permissionSetIdsByGroup.get(component.PermissionSetGroupId) ?? [];
15
+ ids.push(component.PermissionSetId);
16
+ permissionSetIdsByGroup.set(component.PermissionSetGroupId, ids);
17
+ }
18
+ const permissionSetIds = [...new Set(components.map((component) => component.PermissionSetId))];
19
+ return { permissionSetIdsByGroup, masksByPermissionSetId: await loadMasks(permissionSetIds) };
20
+ }
21
+ export const combinePsgMuting = (psgId, state, emptyMask, combine) => (state.permissionSetIdsByGroup.get(psgId ?? '') ?? []).reduce((muted, permissionSetId) => combine(muted, state.masksByPermissionSetId.get(permissionSetId) ?? emptyMask), emptyMask);
22
+ //# sourceMappingURL=muting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"muting.js","sourceRoot":"","sources":["../../src/access/muting.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AASrD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAgB,EAChB,MAAgB,EAChB,SAAsE;IAEtE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,uBAAuB,EAAE,IAAI,GAAG,EAAE,EAAE,sBAAsB,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;IACnF,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAqB,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CACpF;QACE,8CAA8C;QAC9C,kCAAkC;QAClC,kCAAkC,MAAM,CAAC,KAAK,CAAC,GAAG;QAClD,mCAAmC;KACpC,CAAC,IAAI,CAAC,GAAG,CAAC,CACZ,CAAC;IACF,MAAM,uBAAuB,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC5D,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,uBAAuB,CAAC,GAAG,CAAC,SAAS,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC;QAC9E,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QACpC,uBAAuB,CAAC,GAAG,CAAC,SAAS,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,gBAAgB,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAChG,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC,gBAAgB,CAAC,EAAE,CAAC;AAChG,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,KAAyB,EACzB,KAA4B,EAC5B,SAAgB,EAChB,OAA6C,EACtC,EAAE,CACT,CAAC,KAAK,CAAC,uBAAuB,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAC3D,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,sBAAsB,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,SAAS,CAAC,EAC1G,SAAS,CACV,CAAC"}