permcraft 0.1.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.
- package/LICENSE +21 -0
- package/README.md +350 -0
- package/dist/dependencies.d.ts +9 -0
- package/dist/dependencies.js +51 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.js +54 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +320 -0
- package/dist/index.js.map +1 -0
- package/dist/org-fetch.d.ts +4 -0
- package/dist/org-fetch.js +59 -0
- package/dist/org-fetch.js.map +1 -0
- package/dist/prompts.d.ts +15 -0
- package/dist/prompts.js +358 -0
- package/dist/prompts.js.map +1 -0
- package/dist/search.d.ts +3 -0
- package/dist/search.js +17 -0
- package/dist/search.js.map +1 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/dist/xml-mutator.d.ts +32 -0
- package/dist/xml-mutator.js +223 -0
- package/dist/xml-mutator.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Akif
|
|
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,350 @@
|
|
|
1
|
+
# Permcraft
|
|
2
|
+
|
|
3
|
+
Interactive CLI tool that lets Salesforce developers manage permission set XML files without manually editing XML. Express your permission intent once, and Permcraft applies it across multiple permission sets.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
- Fetches objects and fields from your connected Salesforce org
|
|
8
|
+
- Lets you search and select objects/fields using fuzzy search
|
|
9
|
+
- Assigns object permissions (Read, Create, Edit, Delete, View All, Modify All) and field permissions (Read, Edit)
|
|
10
|
+
- Applies selected permissions to one or more local `.permissionset-meta.xml` files
|
|
11
|
+
- Automatically enforces permission dependencies (e.g., selecting Edit auto-enables Read)
|
|
12
|
+
- Supports two permission modes: **Bulk** (same permissions across all selections) and **Granular** (different permissions per object/field)
|
|
13
|
+
- Never downgrades existing permissions — only adds or upgrades
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- **Node.js** (LTS version)
|
|
18
|
+
- **Salesforce CLI (`sf`)** installed and available in your PATH
|
|
19
|
+
- An **authenticated Salesforce org** connected via `sf org login web`
|
|
20
|
+
- Must be run inside a **Salesforce DX project** (directory containing `sfdx-project.json`)
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Clone the repository
|
|
26
|
+
git clone <repo-url>
|
|
27
|
+
cd salesforce-permission-cli
|
|
28
|
+
|
|
29
|
+
# Install dependencies
|
|
30
|
+
npm install
|
|
31
|
+
|
|
32
|
+
# Build
|
|
33
|
+
npm run build
|
|
34
|
+
|
|
35
|
+
# Link globally so "permcraft" is available anywhere
|
|
36
|
+
npm link
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
Navigate to your SFDX project directory and run:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
permcraft
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Options
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
-h, --help Show help message
|
|
51
|
+
-v, --version Show version number
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Uninstalling
|
|
55
|
+
|
|
56
|
+
To remove the global `permcraft` command:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
cd /path/to/salesforce-permission-cli
|
|
60
|
+
npm unlink permcraft
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Walkthrough
|
|
64
|
+
|
|
65
|
+
### Example 1: Bulk mode — same permissions for multiple objects
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
$ permcraft
|
|
69
|
+
|
|
70
|
+
Permcraft — Salesforce Permission Set Editor
|
|
71
|
+
|
|
72
|
+
Checking environment...
|
|
73
|
+
Project: /Users/dev/my-sfdx-project
|
|
74
|
+
Org: admin@myorg.com
|
|
75
|
+
|
|
76
|
+
Fetching objects from org...
|
|
77
|
+
Found 847 objects.
|
|
78
|
+
|
|
79
|
+
Start typing to search for an object. Select it to add.
|
|
80
|
+
|
|
81
|
+
? Search for an object: acc
|
|
82
|
+
Account
|
|
83
|
+
AccountContactRole
|
|
84
|
+
AccountTeamMember
|
|
85
|
+
> Account # user selects Account
|
|
86
|
+
|
|
87
|
+
Added: Account
|
|
88
|
+
? Add another object? Yes
|
|
89
|
+
|
|
90
|
+
? Selected: [Account] — Search for another object (or type "done"): cas
|
|
91
|
+
> Case # user selects Case
|
|
92
|
+
|
|
93
|
+
Added: Case
|
|
94
|
+
? Add another object? No
|
|
95
|
+
|
|
96
|
+
Selected objects: Account, Case
|
|
97
|
+
|
|
98
|
+
Fetching fields for Account...
|
|
99
|
+
Found 72 fields.
|
|
100
|
+
|
|
101
|
+
Start typing to search for a field on Account.
|
|
102
|
+
|
|
103
|
+
? Search for a field on Account: indus
|
|
104
|
+
> Account.Industry # user selects Industry
|
|
105
|
+
|
|
106
|
+
Added: Account.Industry
|
|
107
|
+
? Add another field? No
|
|
108
|
+
|
|
109
|
+
Fetching fields for Case...
|
|
110
|
+
Found 58 fields.
|
|
111
|
+
|
|
112
|
+
Start typing to search for a field on Case.
|
|
113
|
+
|
|
114
|
+
? Search for a field on Case: stat
|
|
115
|
+
> Case.Status # user selects Status
|
|
116
|
+
|
|
117
|
+
Added: Case.Status
|
|
118
|
+
? Add another field? No
|
|
119
|
+
|
|
120
|
+
? How would you like to assign permissions?
|
|
121
|
+
> Bulk — same permissions for all selected objects/fields
|
|
122
|
+
|
|
123
|
+
? Permissions for 2 objects (Account, Case) (Press <space> to select)
|
|
124
|
+
[x] Read
|
|
125
|
+
[x] Create
|
|
126
|
+
[x] Edit
|
|
127
|
+
[ ] Delete
|
|
128
|
+
[ ] View All
|
|
129
|
+
[ ] Modify All
|
|
130
|
+
|
|
131
|
+
? Permissions for 2 fields (Press <space> to select)
|
|
132
|
+
[x] Read
|
|
133
|
+
[ ] Edit
|
|
134
|
+
|
|
135
|
+
Scanning local permission sets...
|
|
136
|
+
Found 3 permission sets.
|
|
137
|
+
|
|
138
|
+
? Select permission sets to update (press <space> to select, <enter> to confirm)
|
|
139
|
+
[x] Sales_User
|
|
140
|
+
[x] Support_User
|
|
141
|
+
[ ] Admin
|
|
142
|
+
|
|
143
|
+
--- Preview ---
|
|
144
|
+
|
|
145
|
+
Permission Set: Sales_User
|
|
146
|
+
+ Account: Read, Create, Edit
|
|
147
|
+
+ Case: Read, Create, Edit
|
|
148
|
+
+ Account.Industry: Read
|
|
149
|
+
+ Case.Status: Read
|
|
150
|
+
|
|
151
|
+
Permission Set: Support_User
|
|
152
|
+
+ Account: Read, Create, Edit
|
|
153
|
+
+ Case: Read, Create, Edit
|
|
154
|
+
+ Account.Industry: Read
|
|
155
|
+
+ Case.Status: Read
|
|
156
|
+
|
|
157
|
+
? Apply these changes? Yes
|
|
158
|
+
|
|
159
|
+
Applying changes...
|
|
160
|
+
|
|
161
|
+
Updating /Users/dev/my-sfdx-project/force-app/main/default/permissionsets/Sales_User.permissionset-meta.xml
|
|
162
|
+
Updating /Users/dev/my-sfdx-project/force-app/main/default/permissionsets/Support_User.permissionset-meta.xml
|
|
163
|
+
|
|
164
|
+
All changes applied successfully!
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Example 2: Granular mode — different permissions per object/field
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
$ permcraft
|
|
171
|
+
|
|
172
|
+
Permcraft — Salesforce Permission Set Editor
|
|
173
|
+
|
|
174
|
+
Checking environment...
|
|
175
|
+
Project: /Users/dev/my-sfdx-project
|
|
176
|
+
Org: admin@myorg.com
|
|
177
|
+
|
|
178
|
+
Fetching objects from org...
|
|
179
|
+
Found 847 objects.
|
|
180
|
+
|
|
181
|
+
Start typing to search for an object. Select it to add.
|
|
182
|
+
|
|
183
|
+
? Search for an object: Account
|
|
184
|
+
Added: Account
|
|
185
|
+
? Add another object? Yes
|
|
186
|
+
? Selected: [Account] — Search for another object (or type "done"): Case
|
|
187
|
+
Added: Case
|
|
188
|
+
? Add another object? No
|
|
189
|
+
|
|
190
|
+
Selected objects: Account, Case
|
|
191
|
+
|
|
192
|
+
Fetching fields for Account...
|
|
193
|
+
Found 72 fields.
|
|
194
|
+
|
|
195
|
+
Start typing to search for a field on Account.
|
|
196
|
+
|
|
197
|
+
? Search for a field on Account: Revenue
|
|
198
|
+
Added: Account.AnnualRevenue
|
|
199
|
+
? Add another field? No
|
|
200
|
+
|
|
201
|
+
Fetching fields for Case...
|
|
202
|
+
Found 58 fields.
|
|
203
|
+
|
|
204
|
+
Start typing to search for a field on Case.
|
|
205
|
+
|
|
206
|
+
? Search for a field on Case: Priority
|
|
207
|
+
Added: Case.Priority
|
|
208
|
+
? Add another field? No
|
|
209
|
+
|
|
210
|
+
? How would you like to assign permissions?
|
|
211
|
+
> Granular — different permissions for each object/field
|
|
212
|
+
|
|
213
|
+
? Permissions for Account
|
|
214
|
+
[x] Read
|
|
215
|
+
[x] Create
|
|
216
|
+
[x] Edit
|
|
217
|
+
[x] Delete
|
|
218
|
+
[ ] View All
|
|
219
|
+
[ ] Modify All
|
|
220
|
+
|
|
221
|
+
? Permissions for Case
|
|
222
|
+
[x] Read
|
|
223
|
+
[x] Create
|
|
224
|
+
[ ] Edit
|
|
225
|
+
[ ] Delete
|
|
226
|
+
[ ] View All
|
|
227
|
+
[ ] Modify All
|
|
228
|
+
|
|
229
|
+
? Permissions for Account.AnnualRevenue
|
|
230
|
+
[x] Read
|
|
231
|
+
[x] Edit
|
|
232
|
+
|
|
233
|
+
? Permissions for Case.Priority
|
|
234
|
+
[x] Read
|
|
235
|
+
[ ] Edit
|
|
236
|
+
|
|
237
|
+
Scanning local permission sets...
|
|
238
|
+
Found 2 permission sets.
|
|
239
|
+
|
|
240
|
+
? Select permission sets to update (press <space> to select, <enter> to confirm)
|
|
241
|
+
[x] Sales_User
|
|
242
|
+
|
|
243
|
+
--- Preview ---
|
|
244
|
+
|
|
245
|
+
Permission Set: Sales_User
|
|
246
|
+
+ Account: Read, Create, Edit, Delete
|
|
247
|
+
+ Case: Read, Create
|
|
248
|
+
+ Account.AnnualRevenue: Read, Edit
|
|
249
|
+
+ Case.Priority: Read
|
|
250
|
+
|
|
251
|
+
? Apply these changes? Yes
|
|
252
|
+
|
|
253
|
+
Applying changes...
|
|
254
|
+
|
|
255
|
+
Updating /Users/dev/my-sfdx-project/force-app/main/default/permissionsets/Sales_User.permissionset-meta.xml
|
|
256
|
+
|
|
257
|
+
All changes applied successfully!
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Example 3: Generated XML output
|
|
261
|
+
|
|
262
|
+
After running permcraft, the permission set XML file is updated cleanly:
|
|
263
|
+
|
|
264
|
+
```xml
|
|
265
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
266
|
+
<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
267
|
+
<hasActivationRequired>false</hasActivationRequired>
|
|
268
|
+
<label>Sales_User</label>
|
|
269
|
+
<objectPermissions>
|
|
270
|
+
<allowCreate>true</allowCreate>
|
|
271
|
+
<allowDelete>false</allowDelete>
|
|
272
|
+
<allowEdit>true</allowEdit>
|
|
273
|
+
<allowRead>true</allowRead>
|
|
274
|
+
<modifyAllRecords>false</modifyAllRecords>
|
|
275
|
+
<object>Account</object>
|
|
276
|
+
<viewAllRecords>false</viewAllRecords>
|
|
277
|
+
</objectPermissions>
|
|
278
|
+
<objectPermissions>
|
|
279
|
+
<allowCreate>true</allowCreate>
|
|
280
|
+
<allowDelete>false</allowDelete>
|
|
281
|
+
<allowEdit>false</allowEdit>
|
|
282
|
+
<allowRead>true</allowRead>
|
|
283
|
+
<modifyAllRecords>false</modifyAllRecords>
|
|
284
|
+
<object>Case</object>
|
|
285
|
+
<viewAllRecords>false</viewAllRecords>
|
|
286
|
+
</objectPermissions>
|
|
287
|
+
<fieldPermissions>
|
|
288
|
+
<editable>false</editable>
|
|
289
|
+
<field>Account.Industry</field>
|
|
290
|
+
<readable>true</readable>
|
|
291
|
+
</fieldPermissions>
|
|
292
|
+
</PermissionSet>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Permission dependency rules
|
|
296
|
+
|
|
297
|
+
Permcraft automatically enforces Salesforce permission dependencies. When you select a permission, all its prerequisites are auto-enabled:
|
|
298
|
+
|
|
299
|
+
**Object permissions** (each implies all below it):
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
Modify All → View All → Delete → Edit → Read
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Field permissions:**
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
Edit → Read
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Auto-enabled dependencies are shown in the preview before applying.
|
|
312
|
+
|
|
313
|
+
## What it supports
|
|
314
|
+
|
|
315
|
+
- Fuzzy search across all org objects and fields
|
|
316
|
+
- Object-level permissions: Read, Create, Edit, Delete, View All, Modify All
|
|
317
|
+
- Field-level permissions: Read, Edit
|
|
318
|
+
- Bulk and granular permission assignment modes
|
|
319
|
+
- Updating existing permission set XML files
|
|
320
|
+
- Creating new permission set XML files (for permission sets that exist in the org but not locally)
|
|
321
|
+
- Preserving existing permissions (never downgrades)
|
|
322
|
+
- Preserving XML formatting and indentation style of existing files
|
|
323
|
+
- Applying permissions across multiple permission sets in a single session
|
|
324
|
+
|
|
325
|
+
## What it does not support (yet)
|
|
326
|
+
|
|
327
|
+
- Non-interactive / CI mode (flags and arguments for scripting)
|
|
328
|
+
- Tab permissions (TabVisibility)
|
|
329
|
+
- Apex class and Visualforce page access
|
|
330
|
+
- Record type assignments
|
|
331
|
+
- Application visibility
|
|
332
|
+
- Custom permission assignments
|
|
333
|
+
- Removing or revoking permissions
|
|
334
|
+
- Profile metadata editing (only permission sets)
|
|
335
|
+
- Deploying changes to the org (use `sf project deploy start` after running permcraft)
|
|
336
|
+
|
|
337
|
+
## Development
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
npm install # install dependencies
|
|
341
|
+
npm run build # compile TypeScript
|
|
342
|
+
npm run dev # run without building (uses tsx)
|
|
343
|
+
npm test # run test suite
|
|
344
|
+
npm run lint # lint source files
|
|
345
|
+
npm run format # format source files
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## License
|
|
349
|
+
|
|
350
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ObjectPermissions, FieldPermissions } from './types.js';
|
|
2
|
+
export declare function resolveObjectDependencies(perms: ObjectPermissions): {
|
|
3
|
+
resolved: ObjectPermissions;
|
|
4
|
+
autoEnabled: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare function resolveFieldDependencies(perms: FieldPermissions): {
|
|
7
|
+
resolved: FieldPermissions;
|
|
8
|
+
autoEnabled: string[];
|
|
9
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Each key implies all keys listed in its array (transitive dependencies)
|
|
2
|
+
const OBJECT_DEPENDENCY_CHAIN = [
|
|
3
|
+
'modifyAllRecords',
|
|
4
|
+
'viewAllRecords',
|
|
5
|
+
'allowDelete',
|
|
6
|
+
'allowEdit',
|
|
7
|
+
'allowRead',
|
|
8
|
+
];
|
|
9
|
+
export function resolveObjectDependencies(perms) {
|
|
10
|
+
const resolved = { ...perms };
|
|
11
|
+
const autoEnabled = [];
|
|
12
|
+
// Find the highest permission that's enabled, then enable everything below it
|
|
13
|
+
let highestIndex = -1;
|
|
14
|
+
for (let i = 0; i < OBJECT_DEPENDENCY_CHAIN.length; i++) {
|
|
15
|
+
if (resolved[OBJECT_DEPENDENCY_CHAIN[i]]) {
|
|
16
|
+
highestIndex = i;
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (highestIndex >= 0) {
|
|
21
|
+
for (let i = highestIndex + 1; i < OBJECT_DEPENDENCY_CHAIN.length; i++) {
|
|
22
|
+
const key = OBJECT_DEPENDENCY_CHAIN[i];
|
|
23
|
+
if (!resolved[key]) {
|
|
24
|
+
resolved[key] = true;
|
|
25
|
+
autoEnabled.push(key);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Also handle Edit → Read independently (Edit without Delete should still imply Read)
|
|
30
|
+
if (resolved.allowEdit && !resolved.allowRead) {
|
|
31
|
+
resolved.allowRead = true;
|
|
32
|
+
if (!autoEnabled.includes('allowRead'))
|
|
33
|
+
autoEnabled.push('allowRead');
|
|
34
|
+
}
|
|
35
|
+
if (resolved.allowCreate && !resolved.allowRead) {
|
|
36
|
+
resolved.allowRead = true;
|
|
37
|
+
if (!autoEnabled.includes('allowRead'))
|
|
38
|
+
autoEnabled.push('allowRead');
|
|
39
|
+
}
|
|
40
|
+
return { resolved, autoEnabled };
|
|
41
|
+
}
|
|
42
|
+
export function resolveFieldDependencies(perms) {
|
|
43
|
+
const resolved = { ...perms };
|
|
44
|
+
const autoEnabled = [];
|
|
45
|
+
if (resolved.editable && !resolved.readable) {
|
|
46
|
+
resolved.readable = true;
|
|
47
|
+
autoEnabled.push('readable');
|
|
48
|
+
}
|
|
49
|
+
return { resolved, autoEnabled };
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../src/dependencies.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,MAAM,uBAAuB,GAA0B;IACrD,kBAAkB;IAClB,gBAAgB;IAChB,aAAa;IACb,WAAW;IACX,WAAW;CACZ,CAAC;AAEF,MAAM,UAAU,yBAAyB,CAAC,KAAwB;IAIhE,MAAM,QAAQ,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAC9B,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,8EAA8E;IAC9E,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,uBAAuB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,IAAI,QAAQ,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,YAAY,GAAG,CAAC,CAAC;YACjB,MAAM;QACR,CAAC;IACH,CAAC;IAED,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;QACtB,KAAK,IAAI,CAAC,GAAG,YAAY,GAAG,CAAC,EAAE,CAAC,GAAG,uBAAuB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvE,MAAM,GAAG,GAAG,uBAAuB,CAAC,CAAC,CAAC,CAAC;YACvC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnB,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;gBACrB,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAED,sFAAsF;IACtF,IAAI,QAAQ,CAAC,SAAS,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;QAC9C,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,QAAQ,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;QAChD,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAAuB;IAI9D,MAAM,QAAQ,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAC9B,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,IAAI,QAAQ,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAC5C,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;QACzB,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC"}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { OrgInfo, SfdxProject } from './types.js';
|
|
2
|
+
export declare function findProjectRoot(startDir?: string): string;
|
|
3
|
+
export declare function readSfdxProject(projectRoot: string): SfdxProject;
|
|
4
|
+
export declare function getPackageDirectories(project: SfdxProject, projectRoot: string): string[];
|
|
5
|
+
export declare function getAuthenticatedOrg(): OrgInfo;
|
|
6
|
+
export declare function validateEnvironment(): {
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
project: SfdxProject;
|
|
9
|
+
org: OrgInfo;
|
|
10
|
+
};
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
export function findProjectRoot(startDir = process.cwd()) {
|
|
5
|
+
let dir = startDir;
|
|
6
|
+
while (true) {
|
|
7
|
+
if (existsSync(resolve(dir, 'sfdx-project.json'))) {
|
|
8
|
+
return dir;
|
|
9
|
+
}
|
|
10
|
+
const parent = resolve(dir, '..');
|
|
11
|
+
if (parent === dir) {
|
|
12
|
+
throw new Error('Not inside a Salesforce DX project. No sfdx-project.json found.\n' +
|
|
13
|
+
'Run this command from within an SFDX project directory.');
|
|
14
|
+
}
|
|
15
|
+
dir = parent;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function readSfdxProject(projectRoot) {
|
|
19
|
+
const filePath = resolve(projectRoot, 'sfdx-project.json');
|
|
20
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
21
|
+
return JSON.parse(content);
|
|
22
|
+
}
|
|
23
|
+
export function getPackageDirectories(project, projectRoot) {
|
|
24
|
+
return project.packageDirectories.map((d) => resolve(projectRoot, d.path));
|
|
25
|
+
}
|
|
26
|
+
export function getAuthenticatedOrg() {
|
|
27
|
+
try {
|
|
28
|
+
const result = execSync('sf org display --json', {
|
|
29
|
+
encoding: 'utf-8',
|
|
30
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
31
|
+
});
|
|
32
|
+
const parsed = JSON.parse(result);
|
|
33
|
+
if (parsed.status !== 0) {
|
|
34
|
+
throw new Error(parsed.message || 'Failed to get org info');
|
|
35
|
+
}
|
|
36
|
+
const { username, id: orgId, instanceUrl } = parsed.result;
|
|
37
|
+
return { username, orgId, instanceUrl };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
if (err instanceof Error && err.message.includes('No default org found')) {
|
|
41
|
+
throw new Error('No authenticated Salesforce org found.\n' +
|
|
42
|
+
'Run `sf org login web` or `sf config set target-org <alias>` first.');
|
|
43
|
+
}
|
|
44
|
+
throw new Error('Failed to connect to Salesforce org. Ensure `sf` CLI is installed and you have an authenticated org.\n' +
|
|
45
|
+
`Details: ${err instanceof Error ? err.message : String(err)}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function validateEnvironment() {
|
|
49
|
+
const projectRoot = findProjectRoot();
|
|
50
|
+
const project = readSfdxProject(projectRoot);
|
|
51
|
+
const org = getAuthenticatedOrg();
|
|
52
|
+
return { projectRoot, project, org };
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,MAAM,UAAU,eAAe,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IAC9D,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC;YAClD,OAAO,GAAG,CAAC;QACb,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CACb,mEAAmE;gBACjE,yDAAyD,CAC5D,CAAC;QACJ,CAAC;QACD,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,WAAmB;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAoB,EAAE,WAAmB;IAC7E,OAAO,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,uBAAuB,EAAE;YAC/C,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,wBAAwB,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC;QAC3D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;YACzE,MAAM,IAAI,KAAK,CACb,0CAA0C;gBACxC,qEAAqE,CACxE,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,KAAK,CACb,wGAAwG;YACtG,YAAY,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACjE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,mBAAmB,EAAE,CAAC;IAClC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AACvC,CAAC"}
|
package/dist/index.d.ts
ADDED