@salesforce/core 3.31.7 → 3.31.9

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 (153) hide show
  1. package/LICENSE.txt +11 -11
  2. package/README.md +222 -222
  3. package/lib/config/aliasesConfig.d.ts +12 -12
  4. package/lib/config/aliasesConfig.js +27 -27
  5. package/lib/config/authInfoConfig.d.ts +19 -19
  6. package/lib/config/authInfoConfig.js +34 -34
  7. package/lib/config/config.d.ts +311 -311
  8. package/lib/config/config.js +574 -574
  9. package/lib/config/configAggregator.d.ts +232 -232
  10. package/lib/config/configAggregator.js +379 -379
  11. package/lib/config/configFile.d.ts +199 -199
  12. package/lib/config/configFile.js +340 -340
  13. package/lib/config/configGroup.d.ts +141 -141
  14. package/lib/config/configGroup.js +224 -224
  15. package/lib/config/configStore.d.ts +241 -241
  16. package/lib/config/configStore.js +352 -352
  17. package/lib/config/envVars.d.ts +101 -101
  18. package/lib/config/envVars.js +456 -456
  19. package/lib/config/orgUsersConfig.d.ts +31 -31
  20. package/lib/config/orgUsersConfig.js +41 -41
  21. package/lib/config/sandboxOrgConfig.d.ts +37 -37
  22. package/lib/config/sandboxOrgConfig.js +50 -50
  23. package/lib/config/sandboxProcessCache.d.ts +16 -16
  24. package/lib/config/sandboxProcessCache.js +37 -37
  25. package/lib/config/tokensConfig.d.ts +10 -10
  26. package/lib/config/tokensConfig.js +28 -28
  27. package/lib/config/ttlConfig.d.ts +34 -34
  28. package/lib/config/ttlConfig.js +54 -54
  29. package/lib/crypto/crypto.d.ts +54 -54
  30. package/lib/crypto/crypto.js +220 -220
  31. package/lib/crypto/keyChain.d.ts +8 -8
  32. package/lib/crypto/keyChain.js +61 -61
  33. package/lib/crypto/keyChainImpl.d.ts +116 -116
  34. package/lib/crypto/keyChainImpl.js +486 -486
  35. package/lib/crypto/secureBuffer.d.ts +46 -46
  36. package/lib/crypto/secureBuffer.js +82 -82
  37. package/lib/deviceOauthService.d.ts +71 -71
  38. package/lib/deviceOauthService.js +191 -191
  39. package/lib/exported.d.ts +38 -38
  40. package/lib/exported.js +118 -118
  41. package/lib/global.d.ts +70 -70
  42. package/lib/global.js +109 -109
  43. package/lib/lifecycleEvents.d.ts +93 -93
  44. package/lib/lifecycleEvents.js +188 -188
  45. package/lib/logger.d.ts +381 -381
  46. package/lib/logger.js +734 -734
  47. package/lib/messages.d.ts +291 -291
  48. package/lib/messages.js +543 -543
  49. package/lib/org/authInfo.d.ts +344 -344
  50. package/lib/org/authInfo.js +892 -892
  51. package/lib/org/authRemover.d.ts +88 -88
  52. package/lib/org/authRemover.js +182 -182
  53. package/lib/org/connection.d.ts +197 -197
  54. package/lib/org/connection.js +395 -395
  55. package/lib/org/index.d.ts +6 -6
  56. package/lib/org/index.js +28 -28
  57. package/lib/org/org.d.ts +558 -558
  58. package/lib/org/org.js +1267 -1267
  59. package/lib/org/orgConfigProperties.d.ts +69 -69
  60. package/lib/org/orgConfigProperties.js +136 -136
  61. package/lib/org/permissionSetAssignment.d.ts +35 -35
  62. package/lib/org/permissionSetAssignment.js +125 -125
  63. package/lib/org/scratchOrgCache.d.ts +20 -20
  64. package/lib/org/scratchOrgCache.js +32 -32
  65. package/lib/org/scratchOrgCreate.d.ts +54 -54
  66. package/lib/org/scratchOrgCreate.js +216 -216
  67. package/lib/org/scratchOrgErrorCodes.d.ts +10 -10
  68. package/lib/org/scratchOrgErrorCodes.js +88 -88
  69. package/lib/org/scratchOrgFeatureDeprecation.d.ts +26 -26
  70. package/lib/org/scratchOrgFeatureDeprecation.js +109 -109
  71. package/lib/org/scratchOrgInfoApi.d.ts +68 -68
  72. package/lib/org/scratchOrgInfoApi.js +416 -413
  73. package/lib/org/scratchOrgInfoGenerator.d.ts +64 -64
  74. package/lib/org/scratchOrgInfoGenerator.js +241 -241
  75. package/lib/org/scratchOrgLifecycleEvents.d.ts +10 -10
  76. package/lib/org/scratchOrgLifecycleEvents.js +40 -40
  77. package/lib/org/scratchOrgSettingsGenerator.d.ts +78 -78
  78. package/lib/org/scratchOrgSettingsGenerator.js +276 -276
  79. package/lib/org/scratchOrgTypes.d.ts +43 -43
  80. package/lib/org/scratchOrgTypes.js +8 -8
  81. package/lib/org/user.d.ts +187 -187
  82. package/lib/org/user.js +448 -448
  83. package/lib/schema/printer.d.ts +79 -79
  84. package/lib/schema/printer.js +260 -260
  85. package/lib/schema/validator.d.ts +70 -70
  86. package/lib/schema/validator.js +169 -169
  87. package/lib/sfError.d.ts +73 -73
  88. package/lib/sfError.js +136 -136
  89. package/lib/sfProject.d.ts +357 -357
  90. package/lib/sfProject.js +671 -671
  91. package/lib/stateAggregator/accessors/aliasAccessor.d.ts +98 -98
  92. package/lib/stateAggregator/accessors/aliasAccessor.js +145 -145
  93. package/lib/stateAggregator/accessors/orgAccessor.d.ts +101 -101
  94. package/lib/stateAggregator/accessors/orgAccessor.js +240 -240
  95. package/lib/stateAggregator/accessors/sandboxAccessor.d.ts +8 -8
  96. package/lib/stateAggregator/accessors/sandboxAccessor.js +27 -27
  97. package/lib/stateAggregator/accessors/tokenAccessor.d.ts +63 -63
  98. package/lib/stateAggregator/accessors/tokenAccessor.js +79 -79
  99. package/lib/stateAggregator/index.d.ts +4 -4
  100. package/lib/stateAggregator/index.js +26 -26
  101. package/lib/stateAggregator/stateAggregator.d.ts +25 -25
  102. package/lib/stateAggregator/stateAggregator.js +45 -45
  103. package/lib/status/myDomainResolver.d.ts +66 -66
  104. package/lib/status/myDomainResolver.js +124 -124
  105. package/lib/status/pollingClient.d.ts +85 -85
  106. package/lib/status/pollingClient.js +115 -115
  107. package/lib/status/streamingClient.d.ts +244 -244
  108. package/lib/status/streamingClient.js +436 -436
  109. package/lib/status/types.d.ts +89 -89
  110. package/lib/status/types.js +17 -17
  111. package/lib/testSetup.d.ts +553 -553
  112. package/lib/testSetup.js +871 -871
  113. package/lib/util/cache.d.ts +11 -11
  114. package/lib/util/cache.js +69 -69
  115. package/lib/util/checkLightningDomain.d.ts +1 -1
  116. package/lib/util/checkLightningDomain.js +28 -28
  117. package/lib/util/directoryWriter.d.ts +12 -12
  118. package/lib/util/directoryWriter.js +53 -53
  119. package/lib/util/getJwtAudienceUrl.d.ts +4 -4
  120. package/lib/util/getJwtAudienceUrl.js +18 -18
  121. package/lib/util/internal.d.ts +58 -58
  122. package/lib/util/internal.js +118 -118
  123. package/lib/util/jsonXmlTools.d.ts +14 -14
  124. package/lib/util/jsonXmlTools.js +38 -38
  125. package/lib/util/mapKeys.d.ts +14 -14
  126. package/lib/util/mapKeys.js +51 -51
  127. package/lib/util/sfdc.d.ts +52 -52
  128. package/lib/util/sfdc.js +85 -85
  129. package/lib/util/sfdcUrl.d.ts +72 -72
  130. package/lib/util/sfdcUrl.js +215 -215
  131. package/lib/util/structuredWriter.d.ts +9 -9
  132. package/lib/util/structuredWriter.js +2 -2
  133. package/lib/util/zipWriter.d.ts +16 -16
  134. package/lib/util/zipWriter.js +67 -67
  135. package/lib/webOAuthServer.d.ts +156 -156
  136. package/lib/webOAuthServer.js +388 -388
  137. package/messages/auth.md +37 -37
  138. package/messages/config.md +156 -156
  139. package/messages/connection.md +30 -30
  140. package/messages/core.json +20 -20
  141. package/messages/core.md +67 -67
  142. package/messages/encryption.md +85 -85
  143. package/messages/envVars.md +303 -303
  144. package/messages/org.md +63 -63
  145. package/messages/permissionSetAssignment.md +31 -31
  146. package/messages/scratchOrgCreate.md +23 -23
  147. package/messages/scratchOrgErrorCodes.md +115 -115
  148. package/messages/scratchOrgFeatureDeprecation.md +11 -11
  149. package/messages/scratchOrgInfoApi.md +19 -15
  150. package/messages/scratchOrgInfoGenerator.md +23 -23
  151. package/messages/streaming.md +23 -23
  152. package/messages/user.md +35 -35
  153. package/package.json +97 -97
package/lib/org/org.js CHANGED
@@ -1,1268 +1,1268 @@
1
- "use strict";
2
- /*
3
- * Copyright (c) 2020, salesforce.com, inc.
4
- * All rights reserved.
5
- * Licensed under the BSD 3-Clause license.
6
- * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
7
- */
8
- /* eslint-disable class-methods-use-this */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.Org = exports.SandboxEvents = exports.OrgTypes = void 0;
11
- const path_1 = require("path");
12
- const fs = require("fs");
13
- const kit_1 = require("@salesforce/kit");
14
- const ts_types_1 = require("@salesforce/ts-types");
15
- const config_1 = require("../config/config");
16
- const configAggregator_1 = require("../config/configAggregator");
17
- const orgUsersConfig_1 = require("../config/orgUsersConfig");
18
- const global_1 = require("../global");
19
- const lifecycleEvents_1 = require("../lifecycleEvents");
20
- const logger_1 = require("../logger");
21
- const sfError_1 = require("../sfError");
22
- const sfdc_1 = require("../util/sfdc");
23
- const webOAuthServer_1 = require("../webOAuthServer");
24
- const messages_1 = require("../messages");
25
- const stateAggregator_1 = require("../stateAggregator");
26
- const pollingClient_1 = require("../status/pollingClient");
27
- const connection_1 = require("./connection");
28
- const authInfo_1 = require("./authInfo");
29
- const scratchOrgCreate_1 = require("./scratchOrgCreate");
30
- const orgConfigProperties_1 = require("./orgConfigProperties");
31
- messages_1.Messages.importMessagesDirectory(__dirname);
32
- const messages = messages_1.Messages.load('@salesforce/core', 'org', [
33
- 'deleteOrgHubError',
34
- 'insufficientAccessToDelete',
35
- 'missingAuthUsername',
36
- 'noDevHubFound',
37
- 'notADevHub',
38
- 'noUsernameFound',
39
- 'sandboxDeleteFailed',
40
- 'sandboxInfoCreateFailed',
41
- 'sandboxNotFound',
42
- 'scratchOrgNotFound',
43
- 'AuthInfoOrgIdUndefined',
44
- 'sandboxCreateNotComplete',
45
- 'SandboxProcessNotFoundBySandboxName',
46
- 'MultiSandboxProcessNotFoundBySandboxName',
47
- ]);
48
- var OrgTypes;
49
- (function (OrgTypes) {
50
- OrgTypes["Scratch"] = "scratch";
51
- OrgTypes["Sandbox"] = "sandbox";
52
- })(OrgTypes = exports.OrgTypes || (exports.OrgTypes = {}));
53
- var SandboxEvents;
54
- (function (SandboxEvents) {
55
- SandboxEvents["EVENT_STATUS"] = "status";
56
- SandboxEvents["EVENT_ASYNC_RESULT"] = "asyncResult";
57
- SandboxEvents["EVENT_RESULT"] = "result";
58
- SandboxEvents["EVENT_AUTH"] = "auth";
59
- SandboxEvents["EVENT_RESUME"] = "resume";
60
- })(SandboxEvents = exports.SandboxEvents || (exports.SandboxEvents = {}));
61
- /**
62
- * Provides a way to manage a locally authenticated Org.
63
- *
64
- * **See** {@link AuthInfo}
65
- *
66
- * **See** {@link Connection}
67
- *
68
- * **See** {@link Aliases}
69
- *
70
- * **See** {@link Config}
71
- *
72
- * ```
73
- * // Email username
74
- * const org1: Org = await Org.create({ aliasOrUsername: 'foo@example.com' });
75
- * // The target-org config property
76
- * const org2: Org = await Org.create();
77
- * // Full Connection
78
- * const org3: Org = await Org.create({
79
- * connection: await Connection.create({
80
- * authInfo: await AuthInfo.create({ username: 'username' })
81
- * })
82
- * });
83
- * ```
84
- *
85
- * **See** https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_cli_usernames_orgs.htm
86
- */
87
- class Org extends kit_1.AsyncOptionalCreatable {
88
- /**
89
- * @ignore
90
- */
91
- constructor(options) {
92
- super(options);
93
- this.status = Org.Status.UNKNOWN;
94
- this.options = options ?? {};
95
- }
96
- /**
97
- * create a sandbox from a production org
98
- * 'this' needs to be a production org with sandbox licenses available
99
- *
100
- * @param sandboxReq SandboxRequest options to create the sandbox with
101
- * @param options Wait: The amount of time to wait before timing out, Interval: The time interval between polling
102
- */
103
- async createSandbox(sandboxReq, options = {
104
- wait: kit_1.Duration.minutes(6),
105
- async: false,
106
- interval: kit_1.Duration.seconds(30),
107
- }) {
108
- this.logger.debug(`CreateSandbox called with SandboxRequest: ${JSON.stringify(sandboxReq, undefined, 2)}`);
109
- const createResult = await this.connection.tooling.create('SandboxInfo', sandboxReq);
110
- this.logger.debug(`Return from calling tooling.create: ${JSON.stringify(createResult, undefined, 2)}`);
111
- if (Array.isArray(createResult) || !createResult.success) {
112
- throw messages.createError('sandboxInfoCreateFailed', [JSON.stringify(createResult)]);
113
- }
114
- const sandboxCreationProgress = await this.querySandboxProcessBySandboxInfoId(createResult.id);
115
- this.logger.debug(`Return from calling singleRecordQuery with tooling: ${JSON.stringify(sandboxCreationProgress, undefined, 2)}`);
116
- const isAsync = !!options.async;
117
- if (isAsync) {
118
- // The user didn't want us to poll, so simply return the status
119
- await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_ASYNC_RESULT, sandboxCreationProgress);
120
- return sandboxCreationProgress;
121
- }
122
- const [wait, pollInterval] = this.validateWaitOptions(options);
123
- this.logger.debug(`create - pollStatusAndAuth sandboxProcessObj ${JSON.stringify(sandboxCreationProgress, undefined, 2)}, max wait time of ${wait.minutes} minutes`);
124
- return this.pollStatusAndAuth({
125
- sandboxProcessObj: sandboxCreationProgress,
126
- wait,
127
- pollInterval,
128
- });
129
- }
130
- /**
131
- *
132
- * @param sandboxReq SandboxRequest options to create the sandbox with
133
- * @param sourceSandboxName the name of the sandbox that your new sandbox will be based on
134
- * @param options Wait: The amount of time to wait before timing out, defaults to 0, Interval: The time interval between polling defaults to 30 seconds
135
- * @returns {SandboxProcessObject} the newly created sandbox process object
136
- */
137
- async cloneSandbox(sandboxReq, sourceSandboxName, options) {
138
- sandboxReq.SourceId = (await this.querySandboxProcessBySandboxName(sourceSandboxName)).SandboxInfoId;
139
- this.logger.debug('Clone sandbox sourceId %s', sandboxReq.SourceId);
140
- return this.createSandbox(sandboxReq, options);
141
- }
142
- /**
143
- * resume a sandbox creation from a production org
144
- * 'this' needs to be a production org with sandbox licenses available
145
- *
146
- * @param resumeSandboxRequest SandboxRequest options to create the sandbox with
147
- * @param options Wait: The amount of time to wait (default: 30 minutes) before timing out,
148
- * Interval: The time interval (default: 30 seconds) between polling
149
- */
150
- async resumeSandbox(resumeSandboxRequest, options = {
151
- wait: kit_1.Duration.minutes(0),
152
- async: false,
153
- interval: kit_1.Duration.seconds(30),
154
- }) {
155
- this.logger.debug(`ResumeSandbox called with ResumeSandboxRequest: ${JSON.stringify(resumeSandboxRequest, undefined, 2)}`);
156
- let sandboxCreationProgress;
157
- // seed the sandboxCreationProgress via the resumeSandboxRequest options
158
- if (resumeSandboxRequest.SandboxName) {
159
- sandboxCreationProgress = await this.querySandboxProcessBySandboxName(resumeSandboxRequest.SandboxName);
160
- }
161
- else if (resumeSandboxRequest.SandboxProcessObjId) {
162
- sandboxCreationProgress = await this.querySandboxProcessById(resumeSandboxRequest.SandboxProcessObjId);
163
- }
164
- else {
165
- throw messages.createError('sandboxNotFound', [
166
- resumeSandboxRequest.SandboxName ?? resumeSandboxRequest.SandboxProcessObjId,
167
- ]);
168
- }
169
- this.logger.debug(`Return from calling singleRecordQuery with tooling: ${JSON.stringify(sandboxCreationProgress, undefined, 2)}`);
170
- await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_RESUME, sandboxCreationProgress);
171
- const [wait, pollInterval] = this.validateWaitOptions(options);
172
- // if wait is 0, return the sandboxCreationProgress immediately
173
- if (wait.seconds === 0) {
174
- if (sandboxCreationProgress.Status === 'Completed') {
175
- // check to see if sandbox can authenticate via sandboxAuth endpoint
176
- const sandboxInfo = await this.sandboxSignupComplete(sandboxCreationProgress);
177
- if (sandboxInfo) {
178
- await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_AUTH, sandboxInfo);
179
- try {
180
- this.logger.debug(`sandbox signup complete with ${JSON.stringify(sandboxInfo, undefined, 2)}`);
181
- await this.writeSandboxAuthFile(sandboxCreationProgress, sandboxInfo);
182
- return sandboxCreationProgress;
183
- }
184
- catch (err) {
185
- // eat the error, we don't want to throw an error if we can't write the file
186
- }
187
- }
188
- }
189
- await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_ASYNC_RESULT, sandboxCreationProgress);
190
- throw messages.createError('sandboxCreateNotComplete');
191
- }
192
- this.logger.debug(`resume - pollStatusAndAuth sandboxProcessObj ${JSON.stringify(sandboxCreationProgress, undefined, 2)}, max wait time of ${wait.minutes} minutes`);
193
- return this.pollStatusAndAuth({
194
- sandboxProcessObj: sandboxCreationProgress,
195
- wait,
196
- pollInterval,
197
- });
198
- }
199
- /**
200
- * Creates a scratchOrg
201
- * 'this' needs to be a valid dev-hub
202
- *
203
- * @param {options} ScratchOrgCreateOptions
204
- * @returns {ScratchOrgCreateResult}
205
- */
206
- async scratchOrgCreate(options) {
207
- return (0, scratchOrgCreate_1.scratchOrgCreate)({ ...options, hubOrg: this });
208
- }
209
- /**
210
- * Reports sandbox org creation status. If the org is ready, authenticates to the org.
211
- *
212
- * @param {sandboxname} string the sandbox name
213
- * @param options Wait: The amount of time to wait before timing out, Interval: The time interval between polling
214
- * @returns {SandboxProcessObject} the sandbox process object
215
- */
216
- async sandboxStatus(sandboxname, options) {
217
- return this.authWithRetriesByName(sandboxname, options);
218
- }
219
- /**
220
- * Clean all data files in the org's data path. Usually <workspace>/.sfdx/orgs/<username>.
221
- *
222
- * @param orgDataPath A relative path other than "orgs/".
223
- * @param throwWhenRemoveFails Should the remove org operations throw an error on failure?
224
- */
225
- async cleanLocalOrgData(orgDataPath, throwWhenRemoveFails = false) {
226
- let dataPath;
227
- try {
228
- dataPath = await this.getLocalDataDir(orgDataPath);
229
- this.logger.debug(`cleaning data for path: ${dataPath}`);
230
- }
231
- catch (err) {
232
- if (err instanceof Error && err.name === 'InvalidProjectWorkspaceError') {
233
- // If we aren't in a project dir, we can't clean up data files.
234
- // If the user unlink this org outside of the workspace they used it in,
235
- // data files will be left over.
236
- return;
237
- }
238
- throw err;
239
- }
240
- return this.manageDelete(async () => fs.promises.rmdir(dataPath), dataPath, throwWhenRemoveFails);
241
- }
242
- /**
243
- * @ignore
244
- */
245
- async retrieveOrgUsersConfig() {
246
- return orgUsersConfig_1.OrgUsersConfig.create(orgUsersConfig_1.OrgUsersConfig.getOptions(this.getOrgId()));
247
- }
248
- /**
249
- * Cleans up all org related artifacts including users, sandbox config(if a sandbox and auth file.
250
- *
251
- * @param throwWhenRemoveFails Determines if the call should throw an error or fail silently.
252
- */
253
- async remove(throwWhenRemoveFails = false) {
254
- // If deleting via the access token there shouldn't be any auth config files
255
- // so just return;
256
- if (this.getConnection().isUsingAccessToken()) {
257
- return Promise.resolve();
258
- }
259
- await this.removeSandboxConfig();
260
- await this.removeUsers(throwWhenRemoveFails);
261
- await this.removeUsersConfig();
262
- // An attempt to remove this org's auth file occurs in this.removeUsersConfig. That's because this org's usersname is also
263
- // included in the OrgUser config file.
264
- //
265
- // So, just in case no users are added to this org we will try the remove again.
266
- await this.removeAuth();
267
- }
268
- /**
269
- * Check if org is a sandbox org by checking its SandboxOrgConfig.
270
- *
271
- */
272
- async isSandbox() {
273
- return (await stateAggregator_1.StateAggregator.getInstance()).sandboxes.hasFile(this.getOrgId());
274
- }
275
- /**
276
- * Check that this org is a scratch org by asking the dev hub if it knows about it.
277
- *
278
- * **Throws** *{@link SfError}{ name: 'NotADevHubError' }* Not a Dev Hub.
279
- *
280
- * **Throws** *{@link SfError}{ name: 'NoResultsError' }* No results.
281
- *
282
- * @param devHubUsernameOrAlias The username or alias of the dev hub org.
283
- */
284
- async checkScratchOrg(devHubUsernameOrAlias) {
285
- let aliasOrUsername = devHubUsernameOrAlias;
286
- if (!aliasOrUsername) {
287
- aliasOrUsername = this.configAggregator.getPropertyValue(orgConfigProperties_1.OrgConfigProperties.TARGET_DEV_HUB);
288
- }
289
- const devHubConnection = (await Org.create({ aliasOrUsername })).getConnection();
290
- const thisOrgAuthConfig = this.getConnection().getAuthInfoFields();
291
- const trimmedId = sfdc_1.sfdc.trimTo15(thisOrgAuthConfig.orgId);
292
- const DEV_HUB_SOQL = `SELECT CreatedDate,Edition,ExpirationDate FROM ActiveScratchOrg WHERE ScratchOrg='${trimmedId}'`;
293
- try {
294
- const results = await devHubConnection.query(DEV_HUB_SOQL);
295
- if (results.records.length !== 1) {
296
- throw new sfError_1.SfError('No results', 'NoResultsError');
297
- }
298
- }
299
- catch (err) {
300
- if (err instanceof Error && err.name === 'INVALID_TYPE') {
301
- throw messages.createError('notADevHub', [devHubConnection.getUsername()]);
302
- }
303
- throw err;
304
- }
305
- return thisOrgAuthConfig;
306
- }
307
- /**
308
- * Returns the Org object or null if this org is not affiliated with a Dev Hub (according to the local config).
309
- */
310
- async getDevHubOrg() {
311
- if (this.isDevHubOrg()) {
312
- return this;
313
- }
314
- else if (this.getField(Org.Fields.DEV_HUB_USERNAME)) {
315
- const devHubUsername = (0, ts_types_1.ensureString)(this.getField(Org.Fields.DEV_HUB_USERNAME));
316
- return Org.create({
317
- connection: await connection_1.Connection.create({
318
- authInfo: await authInfo_1.AuthInfo.create({ username: devHubUsername }),
319
- }),
320
- });
321
- }
322
- }
323
- /**
324
- * Returns `true` if the org is a Dev Hub.
325
- *
326
- * **Note** This relies on a cached value in the auth file. If that property
327
- * is not cached, this method will **always return false even if the org is a
328
- * dev hub**. If you need accuracy, use the {@link Org.determineIfDevHubOrg} method.
329
- */
330
- isDevHubOrg() {
331
- const isDevHub = this.getField(Org.Fields.IS_DEV_HUB);
332
- if ((0, ts_types_1.isBoolean)(isDevHub)) {
333
- return isDevHub;
334
- }
335
- else {
336
- return false;
337
- }
338
- }
339
- /**
340
- * Will delete 'this' instance remotely and any files locally
341
- *
342
- * @param controllingOrg username or Org that 'this.devhub' or 'this.production' refers to. AKA a DevHub for a scratch org, or a Production Org for a sandbox
343
- */
344
- async deleteFrom(controllingOrg) {
345
- if (typeof controllingOrg === 'string') {
346
- controllingOrg = await Org.create({
347
- aggregator: this.configAggregator,
348
- aliasOrUsername: controllingOrg,
349
- });
350
- }
351
- if (await this.isSandbox()) {
352
- await this.deleteSandbox(controllingOrg);
353
- }
354
- else {
355
- await this.deleteScratchOrg(controllingOrg);
356
- }
357
- }
358
- /**
359
- * Will delete 'this' instance remotely and any files locally
360
- */
361
- async delete() {
362
- if (await this.isSandbox()) {
363
- await this.deleteSandbox();
364
- }
365
- else {
366
- await this.deleteScratchOrg();
367
- }
368
- }
369
- /**
370
- * Returns `true` if the org is a Dev Hub.
371
- *
372
- * Use a cached value. If the cached value is not set, then check access to the
373
- * ScratchOrgInfo object to determine if the org is a dev hub.
374
- *
375
- * @param forceServerCheck Ignore the cached value and go straight to the server
376
- * which will be required if the org flips on the dev hub after the value is already
377
- * cached locally.
378
- */
379
- async determineIfDevHubOrg(forceServerCheck = false) {
380
- const cachedIsDevHub = this.getField(Org.Fields.IS_DEV_HUB);
381
- if (!forceServerCheck && (0, ts_types_1.isBoolean)(cachedIsDevHub)) {
382
- return cachedIsDevHub;
383
- }
384
- if (this.isDevHubOrg()) {
385
- return true;
386
- }
387
- this.logger.debug('isDevHub is not cached - querying server...');
388
- const conn = this.getConnection();
389
- let isDevHub = false;
390
- try {
391
- await conn.query('SELECT Id FROM ScratchOrgInfo limit 1');
392
- isDevHub = true;
393
- }
394
- catch (err) {
395
- /* Not a dev hub */
396
- }
397
- const username = (0, ts_types_1.ensure)(this.getUsername());
398
- const authInfo = await authInfo_1.AuthInfo.create({ username });
399
- await authInfo.save({ isDevHub });
400
- // Reset the connection with the updated auth file
401
- this.connection = await connection_1.Connection.create({ authInfo });
402
- return isDevHub;
403
- }
404
- /**
405
- * Returns `true` if the org is a scratch org.
406
- *
407
- * **Note** This relies on a cached value in the auth file. If that property
408
- * is not cached, this method will **always return false even if the org is a
409
- * scratch org**. If you need accuracy, use the {@link Org.determineIfScratch} method.
410
- */
411
- isScratch() {
412
- const isScratch = this.getField(Org.Fields.IS_SCRATCH);
413
- if ((0, ts_types_1.isBoolean)(isScratch)) {
414
- return isScratch;
415
- }
416
- else {
417
- return false;
418
- }
419
- }
420
- /**
421
- * Returns `true` if the org uses source tracking.
422
- * Side effect: updates files where the property doesn't currently exist
423
- */
424
- async tracksSource() {
425
- // use the property if it exists
426
- const tracksSource = this.getField(Org.Fields.TRACKS_SOURCE);
427
- if ((0, ts_types_1.isBoolean)(tracksSource)) {
428
- return tracksSource;
429
- }
430
- // scratch orgs with no property use tracking by default
431
- if (await this.determineIfScratch()) {
432
- // save true for next time to avoid checking again
433
- await this.setTracksSource(true);
434
- return true;
435
- }
436
- if (await this.determineIfSandbox()) {
437
- // does the sandbox know about the SourceMember object?
438
- const supportsSourceMembers = await this.supportsSourceTracking();
439
- await this.setTracksSource(supportsSourceMembers);
440
- return supportsSourceMembers;
441
- }
442
- // any other non-sandbox, non-scratch orgs won't use tracking
443
- await this.setTracksSource(false);
444
- return false;
445
- }
446
- /**
447
- * Set the tracking property on the org's auth file
448
- *
449
- * @param value true or false (whether the org should use source tracking or not)
450
- */
451
- async setTracksSource(value) {
452
- const originalAuth = await authInfo_1.AuthInfo.create({ username: this.getUsername() });
453
- return originalAuth.handleAliasAndDefaultSettings({
454
- setDefault: false,
455
- setDefaultDevHub: false,
456
- setTracksSource: value,
457
- });
458
- }
459
- /**
460
- * Returns `true` if the org is a scratch org.
461
- *
462
- * Use a cached value. If the cached value is not set, then check
463
- * `Organization.IsSandbox == true && Organization.TrialExpirationDate != null`
464
- * using {@link Org.retrieveOrganizationInformation}.
465
- */
466
- async determineIfScratch() {
467
- let cache = this.getField(Org.Fields.IS_SCRATCH);
468
- if (!cache) {
469
- await this.updateLocalInformation();
470
- cache = this.getField(Org.Fields.IS_SCRATCH);
471
- }
472
- return cache;
473
- }
474
- /**
475
- * Returns `true` if the org is a sandbox.
476
- *
477
- * Use a cached value. If the cached value is not set, then check
478
- * `Organization.IsSandbox == true && Organization.TrialExpirationDate == null`
479
- * using {@link Org.retrieveOrganizationInformation}.
480
- */
481
- async determineIfSandbox() {
482
- let cache = this.getField(Org.Fields.IS_SANDBOX);
483
- if (!cache) {
484
- await this.updateLocalInformation();
485
- cache = this.getField(Org.Fields.IS_SANDBOX);
486
- }
487
- return cache;
488
- }
489
- /**
490
- * Retrieve a handful of fields from the Organization table in Salesforce. If this does not have the
491
- * data you need, just use {@link Connection.singleRecordQuery} with `SELECT <needed fields> FROM Organization`.
492
- *
493
- * @returns org information
494
- */
495
- async retrieveOrganizationInformation() {
496
- return this.getConnection().singleRecordQuery('SELECT Name, InstanceName, IsSandbox, TrialExpirationDate, NamespacePrefix FROM Organization');
497
- }
498
- /**
499
- * Some organization information is locally cached, such as if the org name or if it is a scratch org.
500
- * This method populates/updates the filesystem from information retrieved from the org.
501
- */
502
- async updateLocalInformation() {
503
- const username = this.getUsername();
504
- if (username) {
505
- const organization = await this.retrieveOrganizationInformation();
506
- const isScratch = organization.IsSandbox && Boolean(organization.TrialExpirationDate);
507
- const isSandbox = organization.IsSandbox && !organization.TrialExpirationDate;
508
- const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
509
- stateAggregator.orgs.update(username, {
510
- [Org.Fields.NAME]: organization.Name,
511
- [Org.Fields.INSTANCE_NAME]: organization.InstanceName,
512
- [Org.Fields.NAMESPACE_PREFIX]: organization.NamespacePrefix,
513
- [Org.Fields.IS_SANDBOX]: isSandbox,
514
- [Org.Fields.IS_SCRATCH]: isScratch,
515
- [Org.Fields.TRIAL_EXPIRATION_DATE]: organization.TrialExpirationDate,
516
- });
517
- await stateAggregator.orgs.write(username);
518
- }
519
- }
520
- /**
521
- * Refreshes the auth for this org's instance by calling HTTP GET on the baseUrl of the connection object.
522
- */
523
- async refreshAuth() {
524
- this.logger.debug('Refreshing auth for org.');
525
- const requestInfo = {
526
- url: this.getConnection().baseUrl(),
527
- method: 'GET',
528
- };
529
- const conn = this.getConnection();
530
- await conn.request(requestInfo);
531
- }
532
- /**
533
- * Reads and returns the content of all user auth files for this org as an array.
534
- */
535
- async readUserAuthFiles() {
536
- const config = await this.retrieveOrgUsersConfig();
537
- const contents = await config.read();
538
- const thisUsername = (0, ts_types_1.ensure)(this.getUsername());
539
- const usernames = (0, ts_types_1.ensureJsonArray)(contents.usernames ?? [thisUsername]);
540
- return Promise.all(usernames.map((username) => {
541
- if (username === thisUsername) {
542
- return authInfo_1.AuthInfo.create({
543
- username: this.getConnection().getUsername(),
544
- });
545
- }
546
- else {
547
- return authInfo_1.AuthInfo.create({ username: (0, ts_types_1.ensureString)(username) });
548
- }
549
- }));
550
- }
551
- /**
552
- * Adds a username to the user config for this org. For convenience `this` object is returned.
553
- *
554
- * ```
555
- * const org: Org = await Org.create({
556
- * connection: await Connection.create({
557
- * authInfo: await AuthInfo.create('foo@example.com')
558
- * })
559
- * });
560
- * const userAuth: AuthInfo = await AuthInfo.create({
561
- * username: 'bar@example.com'
562
- * });
563
- * await org.addUsername(userAuth);
564
- * ```
565
- *
566
- * @param {AuthInfo | string} auth The AuthInfo for the username to add.
567
- */
568
- async addUsername(auth) {
569
- if (!auth) {
570
- throw new sfError_1.SfError('Missing auth info', 'MissingAuthInfo');
571
- }
572
- const authInfo = (0, ts_types_1.isString)(auth) ? await authInfo_1.AuthInfo.create({ username: auth }) : auth;
573
- this.logger.debug(`adding username ${authInfo.getFields().username}`);
574
- const orgConfig = await this.retrieveOrgUsersConfig();
575
- const contents = await orgConfig.read();
576
- // TODO: This is kind of screwy because contents values can be `AnyJson | object`...
577
- // needs config refactoring to improve
578
- const usernames = contents.usernames ?? [];
579
- if (!(0, ts_types_1.isArray)(usernames)) {
580
- throw new sfError_1.SfError('Usernames is not an array', 'UnexpectedDataFormat');
581
- }
582
- let shouldUpdate = false;
583
- const thisUsername = (0, ts_types_1.ensure)(this.getUsername());
584
- if (!usernames.includes(thisUsername)) {
585
- usernames.push(thisUsername);
586
- shouldUpdate = true;
587
- }
588
- const username = authInfo.getFields().username;
589
- if (username) {
590
- usernames.push(username);
591
- shouldUpdate = true;
592
- }
593
- if (shouldUpdate) {
594
- orgConfig.set('usernames', usernames);
595
- await orgConfig.write();
596
- }
597
- return this;
598
- }
599
- /**
600
- * Removes a username from the user config for this object. For convenience `this` object is returned.
601
- *
602
- * **Throws** *{@link SfError}{ name: 'MissingAuthInfoError' }* Auth info is missing.
603
- *
604
- * @param {AuthInfo | string} auth The AuthInfo containing the username to remove.
605
- */
606
- async removeUsername(auth) {
607
- if (!auth) {
608
- throw new sfError_1.SfError('Missing auth info', 'MissingAuthInfoError');
609
- }
610
- const authInfo = (0, ts_types_1.isString)(auth) ? await authInfo_1.AuthInfo.create({ username: auth }) : auth;
611
- this.logger.debug(`removing username ${authInfo.getFields().username}`);
612
- const orgConfig = await this.retrieveOrgUsersConfig();
613
- const contents = await orgConfig.read();
614
- const targetUser = authInfo.getFields().username;
615
- const usernames = (contents.usernames ?? []);
616
- contents.usernames = usernames.filter((username) => username !== targetUser);
617
- await orgConfig.write();
618
- return this;
619
- }
620
- /**
621
- * set the sandbox config related to this given org
622
- *
623
- * @param orgId {string} orgId of the sandbox
624
- * @param config {SandboxFields} config of the sandbox
625
- */
626
- async setSandboxConfig(orgId, config) {
627
- (await stateAggregator_1.StateAggregator.getInstance()).sandboxes.set(orgId, config);
628
- return this;
629
- }
630
- /**
631
- * get the sandbox config for the given orgId
632
- *
633
- * @param orgId {string} orgId of the sandbox
634
- */
635
- async getSandboxConfig(orgId) {
636
- return (await stateAggregator_1.StateAggregator.getInstance()).sandboxes.read(orgId);
637
- }
638
- /**
639
- * Retrieves the highest api version that is supported by the target server instance. If the apiVersion configured for
640
- * Sfdx is greater than the one returned in this call an api version mismatch occurs. In the case of the CLI that
641
- * results in a warning.
642
- */
643
- async retrieveMaxApiVersion() {
644
- return this.getConnection().retrieveMaxApiVersion();
645
- }
646
- /**
647
- * Returns the admin username used to create the org.
648
- */
649
- getUsername() {
650
- return this.getConnection().getUsername();
651
- }
652
- /**
653
- * Returns the orgId for this org.
654
- */
655
- getOrgId() {
656
- return this.orgId ?? this.getField(Org.Fields.ORG_ID);
657
- }
658
- /**
659
- * Returns for the config aggregator.
660
- */
661
- getConfigAggregator() {
662
- return this.configAggregator;
663
- }
664
- /**
665
- * Returns an org field. Returns undefined if the field is not set or invalid.
666
- */
667
- getField(key) {
668
- /* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */
669
- // @ts-ignore Legacy. We really shouldn't be doing this.
670
- const ownProp = this[key];
671
- if (ownProp && typeof ownProp !== 'function')
672
- return ownProp;
673
- // @ts-ignore
674
- return this.getConnection().getAuthInfoFields()[key];
675
- /* eslint-enable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */
676
- }
677
- /**
678
- * Returns a map of requested fields.
679
- */
680
- getFields(keys) {
681
- const json = {};
682
- return keys.reduce((map, key) => {
683
- map[key] = this.getField(key);
684
- return map;
685
- }, json);
686
- }
687
- /**
688
- * Returns the JSForce connection for the org.
689
- */
690
- getConnection() {
691
- return this.connection;
692
- }
693
- async supportsSourceTracking() {
694
- if (this.isScratch()) {
695
- return true;
696
- }
697
- try {
698
- await this.getConnection().tooling.sobject('SourceMember').describe();
699
- return true;
700
- }
701
- catch (err) {
702
- if (err.message.includes('The requested resource does not exist')) {
703
- return false;
704
- }
705
- throw err;
706
- }
707
- }
708
- /**
709
- * query SandboxProcess via sandbox name
710
- *
711
- * @param name SandboxName to query for
712
- * @private
713
- */
714
- async querySandboxProcessBySandboxName(name) {
715
- return this.querySandboxProcess(`SandboxName='${name}'`);
716
- }
717
- /**
718
- * query SandboxProcess via SandboxInfoId
719
- *
720
- * @param id SandboxInfoId to query for
721
- * @private
722
- */
723
- async querySandboxProcessBySandboxInfoId(id) {
724
- return this.querySandboxProcess(`SandboxInfoId='${id}'`);
725
- }
726
- /**
727
- * query SandboxProcess via Id
728
- *
729
- * @param id SandboxProcessId to query for
730
- * @private
731
- */
732
- async querySandboxProcessById(id) {
733
- return this.querySandboxProcess(`Id='${id}'`);
734
- }
735
- /**
736
- * Initialize async components.
737
- */
738
- async init() {
739
- const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
740
- this.logger = await logger_1.Logger.child('Org');
741
- this.configAggregator = this.options.aggregator ? this.options.aggregator : await configAggregator_1.ConfigAggregator.create();
742
- if (!this.options.connection) {
743
- if (this.options.aliasOrUsername == null) {
744
- this.configAggregator = this.getConfigAggregator();
745
- const aliasOrUsername = this.options.isDevHub
746
- ? this.configAggregator.getPropertyValue(orgConfigProperties_1.OrgConfigProperties.TARGET_DEV_HUB)
747
- : this.configAggregator.getPropertyValue(orgConfigProperties_1.OrgConfigProperties.TARGET_ORG);
748
- this.options.aliasOrUsername = aliasOrUsername ?? undefined;
749
- }
750
- const username = stateAggregator.aliases.resolveUsername(this.options.aliasOrUsername);
751
- if (!username) {
752
- throw messages.createError('noUsernameFound');
753
- }
754
- this.connection = await connection_1.Connection.create({
755
- // If no username is provided or resolvable from an alias, AuthInfo will throw an SfError.
756
- authInfo: await authInfo_1.AuthInfo.create({ username, isDevHub: this.options.isDevHub }),
757
- });
758
- }
759
- else {
760
- this.connection = this.options.connection;
761
- }
762
- this.orgId = this.getField(Org.Fields.ORG_ID);
763
- }
764
- /**
765
- * **Throws** *{@link SfError}{ name: 'NotSupportedError' }* Throws an unsupported error.
766
- */
767
- // eslint-disable-next-line class-methods-use-this
768
- getDefaultOptions() {
769
- throw new sfError_1.SfError('Not Supported', 'NotSupportedError');
770
- }
771
- async getLocalDataDir(orgDataPath) {
772
- const rootFolder = await config_1.Config.resolveRootFolder(false);
773
- return (0, path_1.join)(rootFolder, global_1.Global.SFDX_STATE_FOLDER, orgDataPath ? orgDataPath : 'orgs');
774
- }
775
- /**
776
- * Gets the sandboxProcessObject and then polls for it to complete.
777
- *
778
- * @param sandboxProcessName sanbox process name
779
- * @param options { wait?: Duration; interval?: Duration }
780
- * @returns {SandboxProcessObject} The SandboxProcessObject for the sandbox
781
- */
782
- async authWithRetriesByName(sandboxProcessName, options) {
783
- return this.authWithRetries(await this.queryLatestSandboxProcessBySandboxName(sandboxProcessName), options);
784
- }
785
- /**
786
- * Polls the sandbox org for the sandboxProcessObject.
787
- *
788
- * @param sandboxProcessObj: The in-progress sandbox signup request
789
- * @param options { wait?: Duration; interval?: Duration }
790
- * @returns {SandboxProcessObject}
791
- */
792
- async authWithRetries(sandboxProcessObj, options = {
793
- wait: kit_1.Duration.minutes(0),
794
- interval: kit_1.Duration.seconds(30),
795
- }) {
796
- const [wait, pollInterval] = this.validateWaitOptions(options);
797
- this.logger.debug(`AuthWithRetries sandboxProcessObj ${JSON.stringify(sandboxProcessObj, undefined, 2)}, max wait time of ${wait.minutes} minutes`);
798
- return this.pollStatusAndAuth({
799
- sandboxProcessObj,
800
- wait,
801
- pollInterval,
802
- });
803
- }
804
- /**
805
- * Query the sandbox for the SandboxProcessObject by sandbox name
806
- *
807
- * @param sandboxName The name of the sandbox to query
808
- * @returns {SandboxProcessObject} The SandboxProcessObject for the sandbox
809
- */
810
- async queryLatestSandboxProcessBySandboxName(sandboxNameIn) {
811
- const { tooling } = this.getConnection();
812
- this.logger.debug('QueryLatestSandboxProcessBySandboxName called with SandboxName: %s ', sandboxNameIn);
813
- const queryStr = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE SandboxName='${sandboxNameIn}' AND Status != 'D' ORDER BY CreatedDate DESC LIMIT 1`;
814
- const queryResult = await tooling.query(queryStr);
815
- this.logger.debug('Return from calling queryToolingApi: %s ', queryResult);
816
- if (queryResult?.records?.length === 1) {
817
- return queryResult.records[0];
818
- }
819
- else if (queryResult.records && queryResult.records.length > 1) {
820
- throw messages.createError('MultiSandboxProcessNotFoundBySandboxName', [sandboxNameIn]);
821
- }
822
- else {
823
- throw messages.createError('SandboxProcessNotFoundBySandboxName', [sandboxNameIn]);
824
- }
825
- }
826
- // eslint-disable-next-line class-methods-use-this
827
- async queryProduction(org, field, value) {
828
- return org.connection.singleRecordQuery(`SELECT SandboxInfoId FROM SandboxProcess WHERE ${field} ='${value}' AND Status NOT IN ('D', 'E')`, { tooling: true });
829
- }
830
- async destroySandbox(org, id) {
831
- return org.getConnection().tooling.delete('SandboxInfo', id);
832
- }
833
- async destroyScratchOrg(org, id) {
834
- return org.getConnection().delete('ActiveScratchOrg', id);
835
- }
836
- /**
837
- * this method will delete the sandbox org from the production org and clean up any local files
838
- *
839
- * @param prodOrg - Production org associated with this sandbox
840
- * @private
841
- */
842
- async deleteSandbox(prodOrg) {
843
- const sandbox = await this.getSandboxConfig(this.getOrgId());
844
- prodOrg ?? (prodOrg = await Org.create({
845
- aggregator: this.configAggregator,
846
- aliasOrUsername: sandbox?.prodOrgUsername,
847
- }));
848
- let sandboxInfoId = sandbox?.sandboxInfoId;
849
- if (!sandboxInfoId) {
850
- let result;
851
- try {
852
- // grab sandboxName from config or try to calculate from the sandbox username
853
- const sandboxName = sandbox?.sandboxName ?? (this.getUsername() ?? '').split(`${prodOrg.getUsername()}.`)[1];
854
- if (!sandboxName) {
855
- this.logger.debug('Sandbox name is not available');
856
- // jump to query by orgId
857
- throw new Error();
858
- }
859
- this.logger.debug(`attempting to locate sandbox with sandbox ${sandboxName}`);
860
- try {
861
- result = await this.queryProduction(prodOrg, 'SandboxName', sandboxName);
862
- }
863
- catch (err) {
864
- this.logger.debug(`Failed to find sandbox with sandbox name: ${sandboxName}`);
865
- // jump to query by orgId
866
- throw err;
867
- }
868
- }
869
- catch {
870
- // if an error is thrown, don't panic yet. we'll try querying by orgId
871
- const trimmedId = sfdc_1.sfdc.trimTo15(this.getOrgId());
872
- this.logger.debug(`defaulting to trimming id from ${this.getOrgId()} to ${trimmedId}`);
873
- try {
874
- result = await this.queryProduction(prodOrg, 'SandboxOrganization', trimmedId);
875
- sandboxInfoId = result.SandboxInfoId;
876
- }
877
- catch {
878
- // eating exceptions when trying to find sandbox process record by orgId
879
- // allows idempotent cleanup of sandbox orgs
880
- this.logger.debug(`Failed find a SandboxProcess for the sandbox org: ${this.getOrgId()}`);
881
- }
882
- }
883
- }
884
- if (sandboxInfoId) {
885
- const deleteResult = await this.destroySandbox(prodOrg, sandboxInfoId);
886
- this.logger.debug('Return from calling tooling.delete: ', deleteResult);
887
- }
888
- // cleanup remaining artifacts
889
- await this.remove();
890
- }
891
- /**
892
- * If this Org is a scratch org, calling this method will delete the scratch org from the DevHub and clean up any local files
893
- *
894
- * @param devHub - optional DevHub Org of the to-be-deleted scratch org
895
- * @private
896
- */
897
- async deleteScratchOrg(devHub) {
898
- // if we didn't get a devHub, we'll get it from the this org
899
- devHub ?? (devHub = await this.getDevHubOrg());
900
- if (!devHub) {
901
- throw messages.createError('noDevHubFound');
902
- }
903
- if (devHub.getOrgId() === this.getOrgId()) {
904
- // we're attempting to delete a DevHub
905
- throw messages.createError('deleteOrgHubError');
906
- }
907
- try {
908
- const devHubConn = devHub.getConnection();
909
- const username = this.getUsername();
910
- const activeScratchOrgRecordId = (await devHubConn.singleRecordQuery(`SELECT Id FROM ActiveScratchOrg WHERE SignupUsername='${username}'`)).Id;
911
- this.logger.trace(`found matching ActiveScratchOrg with SignupUsername: ${username}. Deleting...`);
912
- await this.destroyScratchOrg(devHub, activeScratchOrgRecordId);
913
- await this.remove();
914
- }
915
- catch (err) {
916
- this.logger.info(err instanceof Error ? err.message : err);
917
- if (err instanceof Error && (err.name === 'INVALID_TYPE' || err.name === 'INSUFFICIENT_ACCESS_OR_READONLY')) {
918
- // most likely from devHubConn.delete
919
- this.logger.info('Insufficient privilege to access ActiveScratchOrgs.');
920
- throw messages.createError('insufficientAccessToDelete');
921
- }
922
- if (err instanceof Error && err.name === connection_1.SingleRecordQueryErrors.NoRecords) {
923
- // most likely from singleRecordQuery
924
- this.logger.info('The above error can be the result of deleting an expired or already deleted org.');
925
- this.logger.info('attempting to cleanup the auth file');
926
- await this.removeAuth();
927
- throw messages.createError('scratchOrgNotFound');
928
- }
929
- throw err;
930
- }
931
- }
932
- /**
933
- * Delete an auth info file from the local file system and any related cache information for
934
- * this Org. You don't want to call this method directly. Instead consider calling Org.remove()
935
- */
936
- async removeAuth() {
937
- const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
938
- const username = this.getUsername();
939
- // If there is no username, it has already been removed from the globalInfo.
940
- // We can skip the unset and just ensure that globalInfo is updated.
941
- if (username) {
942
- this.logger.debug(`Removing auth for user: ${username}`);
943
- this.logger.debug(`Clearing auth cache for user: ${username}`);
944
- await stateAggregator.orgs.remove(username);
945
- }
946
- }
947
- /**
948
- * Deletes the users config file
949
- */
950
- async removeUsersConfig() {
951
- const config = await this.retrieveOrgUsersConfig();
952
- if (await config.exists()) {
953
- this.logger.debug(`Removing org users config at: ${config.getPath()}`);
954
- await config.unlink();
955
- }
956
- }
957
- async manageDelete(cb, dirPath, throwWhenRemoveFails) {
958
- return cb().catch((e) => {
959
- if (throwWhenRemoveFails) {
960
- throw e;
961
- }
962
- else {
963
- this.logger.warn(`failed to read directory ${dirPath}`);
964
- return;
965
- }
966
- });
967
- }
968
- /**
969
- * Remove the org users auth file.
970
- *
971
- * @param throwWhenRemoveFails true if manageDelete should throw or not if the deleted fails.
972
- */
973
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
974
- async removeUsers(throwWhenRemoveFails) {
975
- const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
976
- this.logger.debug(`Removing users associate with org: ${this.getOrgId()}`);
977
- const config = await this.retrieveOrgUsersConfig();
978
- this.logger.debug(`using path for org users: ${config.getPath()}`);
979
- const authInfos = await this.readUserAuthFiles();
980
- await Promise.all(authInfos
981
- .map((auth) => auth.getFields().username)
982
- .map(async (username) => {
983
- const aliasKeys = (username && stateAggregator.aliases.getAll(username)) ?? [];
984
- stateAggregator.aliases.unsetAll(username);
985
- const orgForUser = username === this.getUsername()
986
- ? this
987
- : await Org.create({
988
- connection: await connection_1.Connection.create({ authInfo: await authInfo_1.AuthInfo.create({ username }) }),
989
- });
990
- const orgType = this.isDevHubOrg() ? orgConfigProperties_1.OrgConfigProperties.TARGET_DEV_HUB : orgConfigProperties_1.OrgConfigProperties.TARGET_ORG;
991
- const configInfo = orgForUser.configAggregator.getInfo(orgType);
992
- const needsConfigUpdate = (configInfo.isGlobal() || configInfo.isLocal()) &&
993
- (configInfo.value === username || aliasKeys.includes(configInfo.value));
994
- return [
995
- orgForUser.removeAuth(),
996
- needsConfigUpdate ? config_1.Config.update(configInfo.isGlobal(), orgType, undefined) : undefined,
997
- ].filter(Boolean);
998
- }));
999
- await stateAggregator.aliases.write();
1000
- }
1001
- async removeSandboxConfig() {
1002
- const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
1003
- await stateAggregator.sandboxes.remove(this.getOrgId());
1004
- }
1005
- async writeSandboxAuthFile(sandboxProcessObj, sandboxRes) {
1006
- this.logger.debug(`writeSandboxAuthFile sandboxProcessObj: ${JSON.stringify(sandboxProcessObj)}, sandboxRes: ${JSON.stringify(sandboxRes)}`);
1007
- if (sandboxRes.authUserName) {
1008
- const productionAuthFields = this.connection.getAuthInfoFields();
1009
- this.logger.debug('Result from getAuthInfoFields: AuthFields', productionAuthFields);
1010
- // let's do headless auth via jwt (if we have privateKey) or web auth
1011
- const oauth2Options = {
1012
- loginUrl: sandboxRes.loginUrl,
1013
- instanceUrl: sandboxRes.instanceUrl,
1014
- username: sandboxRes.authUserName,
1015
- };
1016
- // If we don't have a privateKey then we assume it's web auth.
1017
- if (!productionAuthFields.privateKey) {
1018
- oauth2Options.redirectUri = `http://localhost:${await webOAuthServer_1.WebOAuthServer.determineOauthPort()}/OauthRedirect`;
1019
- oauth2Options.authCode = sandboxRes.authCode;
1020
- }
1021
- else {
1022
- oauth2Options.privateKey = productionAuthFields.privateKey;
1023
- oauth2Options.clientId = productionAuthFields.clientId;
1024
- }
1025
- const authInfo = await authInfo_1.AuthInfo.create({
1026
- username: sandboxRes.authUserName,
1027
- oauth2Options,
1028
- parentUsername: productionAuthFields.username,
1029
- });
1030
- this.logger.debug('Creating AuthInfo for sandbox', sandboxRes.authUserName, productionAuthFields.username, oauth2Options);
1031
- // save auth info for new sandbox
1032
- await authInfo.save();
1033
- const sandboxOrgId = authInfo.getFields().orgId;
1034
- if (!sandboxOrgId) {
1035
- throw messages.createError('AuthInfoOrgIdUndefined');
1036
- }
1037
- // set the sandbox config value
1038
- const sfSandbox = {
1039
- sandboxUsername: sandboxRes.authUserName,
1040
- sandboxOrgId,
1041
- prodOrgUsername: this.getUsername(),
1042
- sandboxName: sandboxProcessObj.SandboxName,
1043
- sandboxProcessId: sandboxProcessObj.Id,
1044
- sandboxInfoId: sandboxProcessObj.SandboxInfoId,
1045
- timestamp: new Date().toISOString(),
1046
- };
1047
- await this.setSandboxConfig(sandboxOrgId, sfSandbox);
1048
- await (await stateAggregator_1.StateAggregator.getInstance()).sandboxes.write(sandboxOrgId);
1049
- await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_RESULT, {
1050
- sandboxProcessObj,
1051
- sandboxRes,
1052
- });
1053
- }
1054
- else {
1055
- // no authed sandbox user, error
1056
- throw messages.createError('missingAuthUsername', [sandboxProcessObj.SandboxName]);
1057
- }
1058
- }
1059
- async pollStatusAndAuth(options) {
1060
- this.logger.debug('PollStatusAndAuth called with SandboxProcessObject', options.sandboxProcessObj, options.wait.minutes, options.pollInterval.seconds);
1061
- let remainingWait = options.wait;
1062
- let waitingOnAuth = false;
1063
- const pollingClient = await pollingClient_1.PollingClient.create({
1064
- poll: async () => {
1065
- const sandboxProcessObj = await this.querySandboxProcessBySandboxInfoId(options.sandboxProcessObj.SandboxInfoId);
1066
- // check to see if sandbox can authenticate via sandboxAuth endpoint
1067
- const sandboxInfo = await this.sandboxSignupComplete(sandboxProcessObj);
1068
- if (sandboxInfo) {
1069
- await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_AUTH, sandboxInfo);
1070
- try {
1071
- this.logger.debug('sandbox signup complete with', sandboxInfo);
1072
- await this.writeSandboxAuthFile(sandboxProcessObj, sandboxInfo);
1073
- return { completed: true, payload: sandboxProcessObj };
1074
- }
1075
- catch (err) {
1076
- const error = err;
1077
- this.logger.debug('Exception while calling writeSandboxAuthFile', err);
1078
- if (error?.name === 'JwtAuthError' && error?.stack?.includes("user hasn't approved")) {
1079
- waitingOnAuth = true;
1080
- }
1081
- else {
1082
- throw sfError_1.SfError.wrap(error);
1083
- }
1084
- }
1085
- }
1086
- await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_STATUS, {
1087
- sandboxProcessObj,
1088
- remainingWait: remainingWait.seconds,
1089
- interval: options.pollInterval.seconds,
1090
- waitingOnAuth,
1091
- });
1092
- remainingWait = kit_1.Duration.seconds(remainingWait.seconds - options.pollInterval.seconds);
1093
- return { completed: false, payload: sandboxProcessObj };
1094
- },
1095
- frequency: options.pollInterval,
1096
- timeout: options.wait,
1097
- });
1098
- return pollingClient.subscribe();
1099
- }
1100
- /**
1101
- * query SandboxProcess using supplied where clause
1102
- *
1103
- * @param where clause to query for
1104
- * @private
1105
- */
1106
- async querySandboxProcess(where) {
1107
- const queryStr = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE ${where} AND Status != 'D'`;
1108
- return this.connection.singleRecordQuery(queryStr, {
1109
- tooling: true,
1110
- });
1111
- }
1112
- /**
1113
- * determines if the sandbox has successfully been created
1114
- *
1115
- * @param sandboxProcessObj sandbox signup progress
1116
- * @private
1117
- */
1118
- async sandboxSignupComplete(sandboxProcessObj) {
1119
- this.logger.debug('sandboxSignupComplete called with SandboxProcessObject', sandboxProcessObj);
1120
- if (!sandboxProcessObj.EndDate) {
1121
- return;
1122
- }
1123
- try {
1124
- // call server side /sandboxAuth API to auth the sandbox org user with the connected app
1125
- const authFields = this.connection.getAuthInfoFields();
1126
- const callbackUrl = `http://localhost:${await webOAuthServer_1.WebOAuthServer.determineOauthPort()}/OauthRedirect`;
1127
- const sandboxReq = {
1128
- // the sandbox signup has been completed on production, we have production clientId by this point
1129
- clientId: authFields.clientId,
1130
- sandboxName: sandboxProcessObj.SandboxName,
1131
- callbackUrl,
1132
- };
1133
- this.logger.debug('Calling sandboxAuth with SandboxUserAuthRequest', sandboxReq);
1134
- // eslint-disable-next-line no-underscore-dangle
1135
- const url = `${this.connection.tooling._baseUrl()}/sandboxAuth`;
1136
- const params = {
1137
- method: 'POST',
1138
- url,
1139
- headers: { 'Content-Type': 'application/json' },
1140
- body: JSON.stringify(sandboxReq),
1141
- };
1142
- const result = await this.connection.tooling.request(params);
1143
- this.logger.debug('Result of calling sandboxAuth', result);
1144
- return result;
1145
- }
1146
- catch (err) {
1147
- const error = err;
1148
- // There are cases where the endDate is set before the sandbox has actually completed.
1149
- // In that case, the sandboxAuth call will throw a specific exception.
1150
- if (error?.name === 'INVALID_STATUS') {
1151
- this.logger.debug('Error while authenticating the user', error?.toString());
1152
- }
1153
- else {
1154
- // If it fails for any unexpected reason, just pass that through
1155
- throw sfError_1.SfError.wrap(error);
1156
- }
1157
- }
1158
- }
1159
- validateWaitOptions(options) {
1160
- const wait = options.wait ?? kit_1.Duration.minutes(30);
1161
- const interval = options.interval ?? kit_1.Duration.seconds(30);
1162
- let pollInterval = options.async ? kit_1.Duration.seconds(0) : interval;
1163
- // pollInterval cannot be > wait.
1164
- pollInterval = pollInterval.seconds > wait.seconds ? wait : pollInterval;
1165
- return [wait, pollInterval];
1166
- }
1167
- }
1168
- exports.Org = Org;
1169
- (function (Org) {
1170
- /**
1171
- * Scratch Org status.
1172
- */
1173
- let Status;
1174
- (function (Status) {
1175
- /**
1176
- * The scratch org is active.
1177
- */
1178
- Status["ACTIVE"] = "ACTIVE";
1179
- /**
1180
- * The scratch org has expired.
1181
- */
1182
- Status["EXPIRED"] = "EXPIRED";
1183
- /**
1184
- * The org is a scratch Org but no dev hub is indicated.
1185
- */
1186
- Status["UNKNOWN"] = "UNKNOWN";
1187
- /**
1188
- * The dev hub configuration is reporting an active Scratch org but the AuthInfo cannot be found.
1189
- */
1190
- Status["MISSING"] = "MISSING";
1191
- })(Status = Org.Status || (Org.Status = {}));
1192
- /**
1193
- * Org Fields.
1194
- */
1195
- // A subset of fields from AuthInfoFields and properties that are specific to Org,
1196
- // and properties that are defined on Org itself.
1197
- let Fields;
1198
- (function (Fields) {
1199
- /**
1200
- * The org alias.
1201
- */
1202
- // From AuthInfo
1203
- Fields["ALIAS"] = "alias";
1204
- Fields["CREATED"] = "created";
1205
- // From Organization
1206
- Fields["NAME"] = "name";
1207
- Fields["NAMESPACE_PREFIX"] = "namespacePrefix";
1208
- Fields["INSTANCE_NAME"] = "instanceName";
1209
- Fields["TRIAL_EXPIRATION_DATE"] = "trailExpirationDate";
1210
- /**
1211
- * The Salesforce instance the org was created on. e.g. `cs42`.
1212
- */
1213
- Fields["CREATED_ORG_INSTANCE"] = "createdOrgInstance";
1214
- /**
1215
- * The username of the dev hub org that created this org. Only populated for scratch orgs.
1216
- */
1217
- Fields["DEV_HUB_USERNAME"] = "devHubUsername";
1218
- /**
1219
- * The full url of the instance the org lives on.
1220
- */
1221
- Fields["INSTANCE_URL"] = "instanceUrl";
1222
- /**
1223
- * Is the current org a dev hub org. e.g. They have access to the `ScratchOrgInfo` object.
1224
- */
1225
- Fields["IS_DEV_HUB"] = "isDevHub";
1226
- /**
1227
- * Is the current org a scratch org. e.g. Organization has IsSandbox == true and TrialExpirationDate != null.
1228
- */
1229
- Fields["IS_SCRATCH"] = "isScratch";
1230
- /**
1231
- * Is the current org a dev hub org. e.g. Organization has IsSandbox == true and TrialExpirationDate == null.
1232
- */
1233
- Fields["IS_SANDBOX"] = "isSandbox";
1234
- /**
1235
- * The login url of the org. e.g. `https://login.salesforce.com` or `https://test.salesforce.com`.
1236
- */
1237
- Fields["LOGIN_URL"] = "loginUrl";
1238
- /**
1239
- * The org ID.
1240
- */
1241
- Fields["ORG_ID"] = "orgId";
1242
- /**
1243
- * The `OrgStatus` of the org.
1244
- */
1245
- Fields["STATUS"] = "status";
1246
- /**
1247
- * The snapshot used to create the scratch org.
1248
- */
1249
- Fields["SNAPSHOT"] = "snapshot";
1250
- /**
1251
- * true: the org supports and wants source tracking
1252
- * false: the org opted out of tracking or can't support it
1253
- */
1254
- Fields["TRACKS_SOURCE"] = "tracksSource";
1255
- // Should it be on org? Leave it off for now, as it might
1256
- // be confusing to the consumer what this actually is.
1257
- // USERNAMES = 'usernames',
1258
- // Keep separation of concerns. I think these should be on a "user" that belongs to the org.
1259
- // Org can have a list of user objects that belong to it? Should connection be on user and org.getConnection()
1260
- // gets the orgs current user for the process? Maybe we just want to keep with the Org only model for
1261
- // the end of time?
1262
- // USER_ID = 'userId',
1263
- // USERNAME = 'username',
1264
- // PASSWORD = 'password',
1265
- // USER_PROFILE_NAME = 'userProfileName'
1266
- })(Fields = Org.Fields || (Org.Fields = {}));
1267
- })(Org = exports.Org || (exports.Org = {}));
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2020, salesforce.com, inc.
4
+ * All rights reserved.
5
+ * Licensed under the BSD 3-Clause license.
6
+ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
7
+ */
8
+ /* eslint-disable class-methods-use-this */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.Org = exports.SandboxEvents = exports.OrgTypes = void 0;
11
+ const path_1 = require("path");
12
+ const fs = require("fs");
13
+ const kit_1 = require("@salesforce/kit");
14
+ const ts_types_1 = require("@salesforce/ts-types");
15
+ const config_1 = require("../config/config");
16
+ const configAggregator_1 = require("../config/configAggregator");
17
+ const orgUsersConfig_1 = require("../config/orgUsersConfig");
18
+ const global_1 = require("../global");
19
+ const lifecycleEvents_1 = require("../lifecycleEvents");
20
+ const logger_1 = require("../logger");
21
+ const sfError_1 = require("../sfError");
22
+ const sfdc_1 = require("../util/sfdc");
23
+ const webOAuthServer_1 = require("../webOAuthServer");
24
+ const messages_1 = require("../messages");
25
+ const stateAggregator_1 = require("../stateAggregator");
26
+ const pollingClient_1 = require("../status/pollingClient");
27
+ const connection_1 = require("./connection");
28
+ const authInfo_1 = require("./authInfo");
29
+ const scratchOrgCreate_1 = require("./scratchOrgCreate");
30
+ const orgConfigProperties_1 = require("./orgConfigProperties");
31
+ messages_1.Messages.importMessagesDirectory(__dirname);
32
+ const messages = messages_1.Messages.load('@salesforce/core', 'org', [
33
+ 'deleteOrgHubError',
34
+ 'insufficientAccessToDelete',
35
+ 'missingAuthUsername',
36
+ 'noDevHubFound',
37
+ 'notADevHub',
38
+ 'noUsernameFound',
39
+ 'sandboxDeleteFailed',
40
+ 'sandboxInfoCreateFailed',
41
+ 'sandboxNotFound',
42
+ 'scratchOrgNotFound',
43
+ 'AuthInfoOrgIdUndefined',
44
+ 'sandboxCreateNotComplete',
45
+ 'SandboxProcessNotFoundBySandboxName',
46
+ 'MultiSandboxProcessNotFoundBySandboxName',
47
+ ]);
48
+ var OrgTypes;
49
+ (function (OrgTypes) {
50
+ OrgTypes["Scratch"] = "scratch";
51
+ OrgTypes["Sandbox"] = "sandbox";
52
+ })(OrgTypes = exports.OrgTypes || (exports.OrgTypes = {}));
53
+ var SandboxEvents;
54
+ (function (SandboxEvents) {
55
+ SandboxEvents["EVENT_STATUS"] = "status";
56
+ SandboxEvents["EVENT_ASYNC_RESULT"] = "asyncResult";
57
+ SandboxEvents["EVENT_RESULT"] = "result";
58
+ SandboxEvents["EVENT_AUTH"] = "auth";
59
+ SandboxEvents["EVENT_RESUME"] = "resume";
60
+ })(SandboxEvents = exports.SandboxEvents || (exports.SandboxEvents = {}));
61
+ /**
62
+ * Provides a way to manage a locally authenticated Org.
63
+ *
64
+ * **See** {@link AuthInfo}
65
+ *
66
+ * **See** {@link Connection}
67
+ *
68
+ * **See** {@link Aliases}
69
+ *
70
+ * **See** {@link Config}
71
+ *
72
+ * ```
73
+ * // Email username
74
+ * const org1: Org = await Org.create({ aliasOrUsername: 'foo@example.com' });
75
+ * // The target-org config property
76
+ * const org2: Org = await Org.create();
77
+ * // Full Connection
78
+ * const org3: Org = await Org.create({
79
+ * connection: await Connection.create({
80
+ * authInfo: await AuthInfo.create({ username: 'username' })
81
+ * })
82
+ * });
83
+ * ```
84
+ *
85
+ * **See** https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_cli_usernames_orgs.htm
86
+ */
87
+ class Org extends kit_1.AsyncOptionalCreatable {
88
+ /**
89
+ * @ignore
90
+ */
91
+ constructor(options) {
92
+ super(options);
93
+ this.status = Org.Status.UNKNOWN;
94
+ this.options = options ?? {};
95
+ }
96
+ /**
97
+ * create a sandbox from a production org
98
+ * 'this' needs to be a production org with sandbox licenses available
99
+ *
100
+ * @param sandboxReq SandboxRequest options to create the sandbox with
101
+ * @param options Wait: The amount of time to wait before timing out, Interval: The time interval between polling
102
+ */
103
+ async createSandbox(sandboxReq, options = {
104
+ wait: kit_1.Duration.minutes(6),
105
+ async: false,
106
+ interval: kit_1.Duration.seconds(30),
107
+ }) {
108
+ this.logger.debug(`CreateSandbox called with SandboxRequest: ${JSON.stringify(sandboxReq, undefined, 2)}`);
109
+ const createResult = await this.connection.tooling.create('SandboxInfo', sandboxReq);
110
+ this.logger.debug(`Return from calling tooling.create: ${JSON.stringify(createResult, undefined, 2)}`);
111
+ if (Array.isArray(createResult) || !createResult.success) {
112
+ throw messages.createError('sandboxInfoCreateFailed', [JSON.stringify(createResult)]);
113
+ }
114
+ const sandboxCreationProgress = await this.querySandboxProcessBySandboxInfoId(createResult.id);
115
+ this.logger.debug(`Return from calling singleRecordQuery with tooling: ${JSON.stringify(sandboxCreationProgress, undefined, 2)}`);
116
+ const isAsync = !!options.async;
117
+ if (isAsync) {
118
+ // The user didn't want us to poll, so simply return the status
119
+ await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_ASYNC_RESULT, sandboxCreationProgress);
120
+ return sandboxCreationProgress;
121
+ }
122
+ const [wait, pollInterval] = this.validateWaitOptions(options);
123
+ this.logger.debug(`create - pollStatusAndAuth sandboxProcessObj ${JSON.stringify(sandboxCreationProgress, undefined, 2)}, max wait time of ${wait.minutes} minutes`);
124
+ return this.pollStatusAndAuth({
125
+ sandboxProcessObj: sandboxCreationProgress,
126
+ wait,
127
+ pollInterval,
128
+ });
129
+ }
130
+ /**
131
+ *
132
+ * @param sandboxReq SandboxRequest options to create the sandbox with
133
+ * @param sourceSandboxName the name of the sandbox that your new sandbox will be based on
134
+ * @param options Wait: The amount of time to wait before timing out, defaults to 0, Interval: The time interval between polling defaults to 30 seconds
135
+ * @returns {SandboxProcessObject} the newly created sandbox process object
136
+ */
137
+ async cloneSandbox(sandboxReq, sourceSandboxName, options) {
138
+ sandboxReq.SourceId = (await this.querySandboxProcessBySandboxName(sourceSandboxName)).SandboxInfoId;
139
+ this.logger.debug('Clone sandbox sourceId %s', sandboxReq.SourceId);
140
+ return this.createSandbox(sandboxReq, options);
141
+ }
142
+ /**
143
+ * resume a sandbox creation from a production org
144
+ * 'this' needs to be a production org with sandbox licenses available
145
+ *
146
+ * @param resumeSandboxRequest SandboxRequest options to create the sandbox with
147
+ * @param options Wait: The amount of time to wait (default: 30 minutes) before timing out,
148
+ * Interval: The time interval (default: 30 seconds) between polling
149
+ */
150
+ async resumeSandbox(resumeSandboxRequest, options = {
151
+ wait: kit_1.Duration.minutes(0),
152
+ async: false,
153
+ interval: kit_1.Duration.seconds(30),
154
+ }) {
155
+ this.logger.debug(`ResumeSandbox called with ResumeSandboxRequest: ${JSON.stringify(resumeSandboxRequest, undefined, 2)}`);
156
+ let sandboxCreationProgress;
157
+ // seed the sandboxCreationProgress via the resumeSandboxRequest options
158
+ if (resumeSandboxRequest.SandboxName) {
159
+ sandboxCreationProgress = await this.querySandboxProcessBySandboxName(resumeSandboxRequest.SandboxName);
160
+ }
161
+ else if (resumeSandboxRequest.SandboxProcessObjId) {
162
+ sandboxCreationProgress = await this.querySandboxProcessById(resumeSandboxRequest.SandboxProcessObjId);
163
+ }
164
+ else {
165
+ throw messages.createError('sandboxNotFound', [
166
+ resumeSandboxRequest.SandboxName ?? resumeSandboxRequest.SandboxProcessObjId,
167
+ ]);
168
+ }
169
+ this.logger.debug(`Return from calling singleRecordQuery with tooling: ${JSON.stringify(sandboxCreationProgress, undefined, 2)}`);
170
+ await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_RESUME, sandboxCreationProgress);
171
+ const [wait, pollInterval] = this.validateWaitOptions(options);
172
+ // if wait is 0, return the sandboxCreationProgress immediately
173
+ if (wait.seconds === 0) {
174
+ if (sandboxCreationProgress.Status === 'Completed') {
175
+ // check to see if sandbox can authenticate via sandboxAuth endpoint
176
+ const sandboxInfo = await this.sandboxSignupComplete(sandboxCreationProgress);
177
+ if (sandboxInfo) {
178
+ await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_AUTH, sandboxInfo);
179
+ try {
180
+ this.logger.debug(`sandbox signup complete with ${JSON.stringify(sandboxInfo, undefined, 2)}`);
181
+ await this.writeSandboxAuthFile(sandboxCreationProgress, sandboxInfo);
182
+ return sandboxCreationProgress;
183
+ }
184
+ catch (err) {
185
+ // eat the error, we don't want to throw an error if we can't write the file
186
+ }
187
+ }
188
+ }
189
+ await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_ASYNC_RESULT, sandboxCreationProgress);
190
+ throw messages.createError('sandboxCreateNotComplete');
191
+ }
192
+ this.logger.debug(`resume - pollStatusAndAuth sandboxProcessObj ${JSON.stringify(sandboxCreationProgress, undefined, 2)}, max wait time of ${wait.minutes} minutes`);
193
+ return this.pollStatusAndAuth({
194
+ sandboxProcessObj: sandboxCreationProgress,
195
+ wait,
196
+ pollInterval,
197
+ });
198
+ }
199
+ /**
200
+ * Creates a scratchOrg
201
+ * 'this' needs to be a valid dev-hub
202
+ *
203
+ * @param {options} ScratchOrgCreateOptions
204
+ * @returns {ScratchOrgCreateResult}
205
+ */
206
+ async scratchOrgCreate(options) {
207
+ return (0, scratchOrgCreate_1.scratchOrgCreate)({ ...options, hubOrg: this });
208
+ }
209
+ /**
210
+ * Reports sandbox org creation status. If the org is ready, authenticates to the org.
211
+ *
212
+ * @param {sandboxname} string the sandbox name
213
+ * @param options Wait: The amount of time to wait before timing out, Interval: The time interval between polling
214
+ * @returns {SandboxProcessObject} the sandbox process object
215
+ */
216
+ async sandboxStatus(sandboxname, options) {
217
+ return this.authWithRetriesByName(sandboxname, options);
218
+ }
219
+ /**
220
+ * Clean all data files in the org's data path. Usually <workspace>/.sfdx/orgs/<username>.
221
+ *
222
+ * @param orgDataPath A relative path other than "orgs/".
223
+ * @param throwWhenRemoveFails Should the remove org operations throw an error on failure?
224
+ */
225
+ async cleanLocalOrgData(orgDataPath, throwWhenRemoveFails = false) {
226
+ let dataPath;
227
+ try {
228
+ dataPath = await this.getLocalDataDir(orgDataPath);
229
+ this.logger.debug(`cleaning data for path: ${dataPath}`);
230
+ }
231
+ catch (err) {
232
+ if (err instanceof Error && err.name === 'InvalidProjectWorkspaceError') {
233
+ // If we aren't in a project dir, we can't clean up data files.
234
+ // If the user unlink this org outside of the workspace they used it in,
235
+ // data files will be left over.
236
+ return;
237
+ }
238
+ throw err;
239
+ }
240
+ return this.manageDelete(async () => fs.promises.rmdir(dataPath), dataPath, throwWhenRemoveFails);
241
+ }
242
+ /**
243
+ * @ignore
244
+ */
245
+ async retrieveOrgUsersConfig() {
246
+ return orgUsersConfig_1.OrgUsersConfig.create(orgUsersConfig_1.OrgUsersConfig.getOptions(this.getOrgId()));
247
+ }
248
+ /**
249
+ * Cleans up all org related artifacts including users, sandbox config(if a sandbox and auth file.
250
+ *
251
+ * @param throwWhenRemoveFails Determines if the call should throw an error or fail silently.
252
+ */
253
+ async remove(throwWhenRemoveFails = false) {
254
+ // If deleting via the access token there shouldn't be any auth config files
255
+ // so just return;
256
+ if (this.getConnection().isUsingAccessToken()) {
257
+ return Promise.resolve();
258
+ }
259
+ await this.removeSandboxConfig();
260
+ await this.removeUsers(throwWhenRemoveFails);
261
+ await this.removeUsersConfig();
262
+ // An attempt to remove this org's auth file occurs in this.removeUsersConfig. That's because this org's usersname is also
263
+ // included in the OrgUser config file.
264
+ //
265
+ // So, just in case no users are added to this org we will try the remove again.
266
+ await this.removeAuth();
267
+ }
268
+ /**
269
+ * Check if org is a sandbox org by checking its SandboxOrgConfig.
270
+ *
271
+ */
272
+ async isSandbox() {
273
+ return (await stateAggregator_1.StateAggregator.getInstance()).sandboxes.hasFile(this.getOrgId());
274
+ }
275
+ /**
276
+ * Check that this org is a scratch org by asking the dev hub if it knows about it.
277
+ *
278
+ * **Throws** *{@link SfError}{ name: 'NotADevHubError' }* Not a Dev Hub.
279
+ *
280
+ * **Throws** *{@link SfError}{ name: 'NoResultsError' }* No results.
281
+ *
282
+ * @param devHubUsernameOrAlias The username or alias of the dev hub org.
283
+ */
284
+ async checkScratchOrg(devHubUsernameOrAlias) {
285
+ let aliasOrUsername = devHubUsernameOrAlias;
286
+ if (!aliasOrUsername) {
287
+ aliasOrUsername = this.configAggregator.getPropertyValue(orgConfigProperties_1.OrgConfigProperties.TARGET_DEV_HUB);
288
+ }
289
+ const devHubConnection = (await Org.create({ aliasOrUsername })).getConnection();
290
+ const thisOrgAuthConfig = this.getConnection().getAuthInfoFields();
291
+ const trimmedId = sfdc_1.sfdc.trimTo15(thisOrgAuthConfig.orgId);
292
+ const DEV_HUB_SOQL = `SELECT CreatedDate,Edition,ExpirationDate FROM ActiveScratchOrg WHERE ScratchOrg='${trimmedId}'`;
293
+ try {
294
+ const results = await devHubConnection.query(DEV_HUB_SOQL);
295
+ if (results.records.length !== 1) {
296
+ throw new sfError_1.SfError('No results', 'NoResultsError');
297
+ }
298
+ }
299
+ catch (err) {
300
+ if (err instanceof Error && err.name === 'INVALID_TYPE') {
301
+ throw messages.createError('notADevHub', [devHubConnection.getUsername()]);
302
+ }
303
+ throw err;
304
+ }
305
+ return thisOrgAuthConfig;
306
+ }
307
+ /**
308
+ * Returns the Org object or null if this org is not affiliated with a Dev Hub (according to the local config).
309
+ */
310
+ async getDevHubOrg() {
311
+ if (this.isDevHubOrg()) {
312
+ return this;
313
+ }
314
+ else if (this.getField(Org.Fields.DEV_HUB_USERNAME)) {
315
+ const devHubUsername = (0, ts_types_1.ensureString)(this.getField(Org.Fields.DEV_HUB_USERNAME));
316
+ return Org.create({
317
+ connection: await connection_1.Connection.create({
318
+ authInfo: await authInfo_1.AuthInfo.create({ username: devHubUsername }),
319
+ }),
320
+ });
321
+ }
322
+ }
323
+ /**
324
+ * Returns `true` if the org is a Dev Hub.
325
+ *
326
+ * **Note** This relies on a cached value in the auth file. If that property
327
+ * is not cached, this method will **always return false even if the org is a
328
+ * dev hub**. If you need accuracy, use the {@link Org.determineIfDevHubOrg} method.
329
+ */
330
+ isDevHubOrg() {
331
+ const isDevHub = this.getField(Org.Fields.IS_DEV_HUB);
332
+ if ((0, ts_types_1.isBoolean)(isDevHub)) {
333
+ return isDevHub;
334
+ }
335
+ else {
336
+ return false;
337
+ }
338
+ }
339
+ /**
340
+ * Will delete 'this' instance remotely and any files locally
341
+ *
342
+ * @param controllingOrg username or Org that 'this.devhub' or 'this.production' refers to. AKA a DevHub for a scratch org, or a Production Org for a sandbox
343
+ */
344
+ async deleteFrom(controllingOrg) {
345
+ if (typeof controllingOrg === 'string') {
346
+ controllingOrg = await Org.create({
347
+ aggregator: this.configAggregator,
348
+ aliasOrUsername: controllingOrg,
349
+ });
350
+ }
351
+ if (await this.isSandbox()) {
352
+ await this.deleteSandbox(controllingOrg);
353
+ }
354
+ else {
355
+ await this.deleteScratchOrg(controllingOrg);
356
+ }
357
+ }
358
+ /**
359
+ * Will delete 'this' instance remotely and any files locally
360
+ */
361
+ async delete() {
362
+ if (await this.isSandbox()) {
363
+ await this.deleteSandbox();
364
+ }
365
+ else {
366
+ await this.deleteScratchOrg();
367
+ }
368
+ }
369
+ /**
370
+ * Returns `true` if the org is a Dev Hub.
371
+ *
372
+ * Use a cached value. If the cached value is not set, then check access to the
373
+ * ScratchOrgInfo object to determine if the org is a dev hub.
374
+ *
375
+ * @param forceServerCheck Ignore the cached value and go straight to the server
376
+ * which will be required if the org flips on the dev hub after the value is already
377
+ * cached locally.
378
+ */
379
+ async determineIfDevHubOrg(forceServerCheck = false) {
380
+ const cachedIsDevHub = this.getField(Org.Fields.IS_DEV_HUB);
381
+ if (!forceServerCheck && (0, ts_types_1.isBoolean)(cachedIsDevHub)) {
382
+ return cachedIsDevHub;
383
+ }
384
+ if (this.isDevHubOrg()) {
385
+ return true;
386
+ }
387
+ this.logger.debug('isDevHub is not cached - querying server...');
388
+ const conn = this.getConnection();
389
+ let isDevHub = false;
390
+ try {
391
+ await conn.query('SELECT Id FROM ScratchOrgInfo limit 1');
392
+ isDevHub = true;
393
+ }
394
+ catch (err) {
395
+ /* Not a dev hub */
396
+ }
397
+ const username = (0, ts_types_1.ensure)(this.getUsername());
398
+ const authInfo = await authInfo_1.AuthInfo.create({ username });
399
+ await authInfo.save({ isDevHub });
400
+ // Reset the connection with the updated auth file
401
+ this.connection = await connection_1.Connection.create({ authInfo });
402
+ return isDevHub;
403
+ }
404
+ /**
405
+ * Returns `true` if the org is a scratch org.
406
+ *
407
+ * **Note** This relies on a cached value in the auth file. If that property
408
+ * is not cached, this method will **always return false even if the org is a
409
+ * scratch org**. If you need accuracy, use the {@link Org.determineIfScratch} method.
410
+ */
411
+ isScratch() {
412
+ const isScratch = this.getField(Org.Fields.IS_SCRATCH);
413
+ if ((0, ts_types_1.isBoolean)(isScratch)) {
414
+ return isScratch;
415
+ }
416
+ else {
417
+ return false;
418
+ }
419
+ }
420
+ /**
421
+ * Returns `true` if the org uses source tracking.
422
+ * Side effect: updates files where the property doesn't currently exist
423
+ */
424
+ async tracksSource() {
425
+ // use the property if it exists
426
+ const tracksSource = this.getField(Org.Fields.TRACKS_SOURCE);
427
+ if ((0, ts_types_1.isBoolean)(tracksSource)) {
428
+ return tracksSource;
429
+ }
430
+ // scratch orgs with no property use tracking by default
431
+ if (await this.determineIfScratch()) {
432
+ // save true for next time to avoid checking again
433
+ await this.setTracksSource(true);
434
+ return true;
435
+ }
436
+ if (await this.determineIfSandbox()) {
437
+ // does the sandbox know about the SourceMember object?
438
+ const supportsSourceMembers = await this.supportsSourceTracking();
439
+ await this.setTracksSource(supportsSourceMembers);
440
+ return supportsSourceMembers;
441
+ }
442
+ // any other non-sandbox, non-scratch orgs won't use tracking
443
+ await this.setTracksSource(false);
444
+ return false;
445
+ }
446
+ /**
447
+ * Set the tracking property on the org's auth file
448
+ *
449
+ * @param value true or false (whether the org should use source tracking or not)
450
+ */
451
+ async setTracksSource(value) {
452
+ const originalAuth = await authInfo_1.AuthInfo.create({ username: this.getUsername() });
453
+ return originalAuth.handleAliasAndDefaultSettings({
454
+ setDefault: false,
455
+ setDefaultDevHub: false,
456
+ setTracksSource: value,
457
+ });
458
+ }
459
+ /**
460
+ * Returns `true` if the org is a scratch org.
461
+ *
462
+ * Use a cached value. If the cached value is not set, then check
463
+ * `Organization.IsSandbox == true && Organization.TrialExpirationDate != null`
464
+ * using {@link Org.retrieveOrganizationInformation}.
465
+ */
466
+ async determineIfScratch() {
467
+ let cache = this.getField(Org.Fields.IS_SCRATCH);
468
+ if (!cache) {
469
+ await this.updateLocalInformation();
470
+ cache = this.getField(Org.Fields.IS_SCRATCH);
471
+ }
472
+ return cache;
473
+ }
474
+ /**
475
+ * Returns `true` if the org is a sandbox.
476
+ *
477
+ * Use a cached value. If the cached value is not set, then check
478
+ * `Organization.IsSandbox == true && Organization.TrialExpirationDate == null`
479
+ * using {@link Org.retrieveOrganizationInformation}.
480
+ */
481
+ async determineIfSandbox() {
482
+ let cache = this.getField(Org.Fields.IS_SANDBOX);
483
+ if (!cache) {
484
+ await this.updateLocalInformation();
485
+ cache = this.getField(Org.Fields.IS_SANDBOX);
486
+ }
487
+ return cache;
488
+ }
489
+ /**
490
+ * Retrieve a handful of fields from the Organization table in Salesforce. If this does not have the
491
+ * data you need, just use {@link Connection.singleRecordQuery} with `SELECT <needed fields> FROM Organization`.
492
+ *
493
+ * @returns org information
494
+ */
495
+ async retrieveOrganizationInformation() {
496
+ return this.getConnection().singleRecordQuery('SELECT Name, InstanceName, IsSandbox, TrialExpirationDate, NamespacePrefix FROM Organization');
497
+ }
498
+ /**
499
+ * Some organization information is locally cached, such as if the org name or if it is a scratch org.
500
+ * This method populates/updates the filesystem from information retrieved from the org.
501
+ */
502
+ async updateLocalInformation() {
503
+ const username = this.getUsername();
504
+ if (username) {
505
+ const organization = await this.retrieveOrganizationInformation();
506
+ const isScratch = organization.IsSandbox && Boolean(organization.TrialExpirationDate);
507
+ const isSandbox = organization.IsSandbox && !organization.TrialExpirationDate;
508
+ const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
509
+ stateAggregator.orgs.update(username, {
510
+ [Org.Fields.NAME]: organization.Name,
511
+ [Org.Fields.INSTANCE_NAME]: organization.InstanceName,
512
+ [Org.Fields.NAMESPACE_PREFIX]: organization.NamespacePrefix,
513
+ [Org.Fields.IS_SANDBOX]: isSandbox,
514
+ [Org.Fields.IS_SCRATCH]: isScratch,
515
+ [Org.Fields.TRIAL_EXPIRATION_DATE]: organization.TrialExpirationDate,
516
+ });
517
+ await stateAggregator.orgs.write(username);
518
+ }
519
+ }
520
+ /**
521
+ * Refreshes the auth for this org's instance by calling HTTP GET on the baseUrl of the connection object.
522
+ */
523
+ async refreshAuth() {
524
+ this.logger.debug('Refreshing auth for org.');
525
+ const requestInfo = {
526
+ url: this.getConnection().baseUrl(),
527
+ method: 'GET',
528
+ };
529
+ const conn = this.getConnection();
530
+ await conn.request(requestInfo);
531
+ }
532
+ /**
533
+ * Reads and returns the content of all user auth files for this org as an array.
534
+ */
535
+ async readUserAuthFiles() {
536
+ const config = await this.retrieveOrgUsersConfig();
537
+ const contents = await config.read();
538
+ const thisUsername = (0, ts_types_1.ensure)(this.getUsername());
539
+ const usernames = (0, ts_types_1.ensureJsonArray)(contents.usernames ?? [thisUsername]);
540
+ return Promise.all(usernames.map((username) => {
541
+ if (username === thisUsername) {
542
+ return authInfo_1.AuthInfo.create({
543
+ username: this.getConnection().getUsername(),
544
+ });
545
+ }
546
+ else {
547
+ return authInfo_1.AuthInfo.create({ username: (0, ts_types_1.ensureString)(username) });
548
+ }
549
+ }));
550
+ }
551
+ /**
552
+ * Adds a username to the user config for this org. For convenience `this` object is returned.
553
+ *
554
+ * ```
555
+ * const org: Org = await Org.create({
556
+ * connection: await Connection.create({
557
+ * authInfo: await AuthInfo.create('foo@example.com')
558
+ * })
559
+ * });
560
+ * const userAuth: AuthInfo = await AuthInfo.create({
561
+ * username: 'bar@example.com'
562
+ * });
563
+ * await org.addUsername(userAuth);
564
+ * ```
565
+ *
566
+ * @param {AuthInfo | string} auth The AuthInfo for the username to add.
567
+ */
568
+ async addUsername(auth) {
569
+ if (!auth) {
570
+ throw new sfError_1.SfError('Missing auth info', 'MissingAuthInfo');
571
+ }
572
+ const authInfo = (0, ts_types_1.isString)(auth) ? await authInfo_1.AuthInfo.create({ username: auth }) : auth;
573
+ this.logger.debug(`adding username ${authInfo.getFields().username}`);
574
+ const orgConfig = await this.retrieveOrgUsersConfig();
575
+ const contents = await orgConfig.read();
576
+ // TODO: This is kind of screwy because contents values can be `AnyJson | object`...
577
+ // needs config refactoring to improve
578
+ const usernames = contents.usernames ?? [];
579
+ if (!(0, ts_types_1.isArray)(usernames)) {
580
+ throw new sfError_1.SfError('Usernames is not an array', 'UnexpectedDataFormat');
581
+ }
582
+ let shouldUpdate = false;
583
+ const thisUsername = (0, ts_types_1.ensure)(this.getUsername());
584
+ if (!usernames.includes(thisUsername)) {
585
+ usernames.push(thisUsername);
586
+ shouldUpdate = true;
587
+ }
588
+ const username = authInfo.getFields().username;
589
+ if (username) {
590
+ usernames.push(username);
591
+ shouldUpdate = true;
592
+ }
593
+ if (shouldUpdate) {
594
+ orgConfig.set('usernames', usernames);
595
+ await orgConfig.write();
596
+ }
597
+ return this;
598
+ }
599
+ /**
600
+ * Removes a username from the user config for this object. For convenience `this` object is returned.
601
+ *
602
+ * **Throws** *{@link SfError}{ name: 'MissingAuthInfoError' }* Auth info is missing.
603
+ *
604
+ * @param {AuthInfo | string} auth The AuthInfo containing the username to remove.
605
+ */
606
+ async removeUsername(auth) {
607
+ if (!auth) {
608
+ throw new sfError_1.SfError('Missing auth info', 'MissingAuthInfoError');
609
+ }
610
+ const authInfo = (0, ts_types_1.isString)(auth) ? await authInfo_1.AuthInfo.create({ username: auth }) : auth;
611
+ this.logger.debug(`removing username ${authInfo.getFields().username}`);
612
+ const orgConfig = await this.retrieveOrgUsersConfig();
613
+ const contents = await orgConfig.read();
614
+ const targetUser = authInfo.getFields().username;
615
+ const usernames = (contents.usernames ?? []);
616
+ contents.usernames = usernames.filter((username) => username !== targetUser);
617
+ await orgConfig.write();
618
+ return this;
619
+ }
620
+ /**
621
+ * set the sandbox config related to this given org
622
+ *
623
+ * @param orgId {string} orgId of the sandbox
624
+ * @param config {SandboxFields} config of the sandbox
625
+ */
626
+ async setSandboxConfig(orgId, config) {
627
+ (await stateAggregator_1.StateAggregator.getInstance()).sandboxes.set(orgId, config);
628
+ return this;
629
+ }
630
+ /**
631
+ * get the sandbox config for the given orgId
632
+ *
633
+ * @param orgId {string} orgId of the sandbox
634
+ */
635
+ async getSandboxConfig(orgId) {
636
+ return (await stateAggregator_1.StateAggregator.getInstance()).sandboxes.read(orgId);
637
+ }
638
+ /**
639
+ * Retrieves the highest api version that is supported by the target server instance. If the apiVersion configured for
640
+ * Sfdx is greater than the one returned in this call an api version mismatch occurs. In the case of the CLI that
641
+ * results in a warning.
642
+ */
643
+ async retrieveMaxApiVersion() {
644
+ return this.getConnection().retrieveMaxApiVersion();
645
+ }
646
+ /**
647
+ * Returns the admin username used to create the org.
648
+ */
649
+ getUsername() {
650
+ return this.getConnection().getUsername();
651
+ }
652
+ /**
653
+ * Returns the orgId for this org.
654
+ */
655
+ getOrgId() {
656
+ return this.orgId ?? this.getField(Org.Fields.ORG_ID);
657
+ }
658
+ /**
659
+ * Returns for the config aggregator.
660
+ */
661
+ getConfigAggregator() {
662
+ return this.configAggregator;
663
+ }
664
+ /**
665
+ * Returns an org field. Returns undefined if the field is not set or invalid.
666
+ */
667
+ getField(key) {
668
+ /* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */
669
+ // @ts-ignore Legacy. We really shouldn't be doing this.
670
+ const ownProp = this[key];
671
+ if (ownProp && typeof ownProp !== 'function')
672
+ return ownProp;
673
+ // @ts-ignore
674
+ return this.getConnection().getAuthInfoFields()[key];
675
+ /* eslint-enable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment */
676
+ }
677
+ /**
678
+ * Returns a map of requested fields.
679
+ */
680
+ getFields(keys) {
681
+ const json = {};
682
+ return keys.reduce((map, key) => {
683
+ map[key] = this.getField(key);
684
+ return map;
685
+ }, json);
686
+ }
687
+ /**
688
+ * Returns the JSForce connection for the org.
689
+ */
690
+ getConnection() {
691
+ return this.connection;
692
+ }
693
+ async supportsSourceTracking() {
694
+ if (this.isScratch()) {
695
+ return true;
696
+ }
697
+ try {
698
+ await this.getConnection().tooling.sobject('SourceMember').describe();
699
+ return true;
700
+ }
701
+ catch (err) {
702
+ if (err.message.includes('The requested resource does not exist')) {
703
+ return false;
704
+ }
705
+ throw err;
706
+ }
707
+ }
708
+ /**
709
+ * query SandboxProcess via sandbox name
710
+ *
711
+ * @param name SandboxName to query for
712
+ * @private
713
+ */
714
+ async querySandboxProcessBySandboxName(name) {
715
+ return this.querySandboxProcess(`SandboxName='${name}'`);
716
+ }
717
+ /**
718
+ * query SandboxProcess via SandboxInfoId
719
+ *
720
+ * @param id SandboxInfoId to query for
721
+ * @private
722
+ */
723
+ async querySandboxProcessBySandboxInfoId(id) {
724
+ return this.querySandboxProcess(`SandboxInfoId='${id}'`);
725
+ }
726
+ /**
727
+ * query SandboxProcess via Id
728
+ *
729
+ * @param id SandboxProcessId to query for
730
+ * @private
731
+ */
732
+ async querySandboxProcessById(id) {
733
+ return this.querySandboxProcess(`Id='${id}'`);
734
+ }
735
+ /**
736
+ * Initialize async components.
737
+ */
738
+ async init() {
739
+ const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
740
+ this.logger = await logger_1.Logger.child('Org');
741
+ this.configAggregator = this.options.aggregator ? this.options.aggregator : await configAggregator_1.ConfigAggregator.create();
742
+ if (!this.options.connection) {
743
+ if (this.options.aliasOrUsername == null) {
744
+ this.configAggregator = this.getConfigAggregator();
745
+ const aliasOrUsername = this.options.isDevHub
746
+ ? this.configAggregator.getPropertyValue(orgConfigProperties_1.OrgConfigProperties.TARGET_DEV_HUB)
747
+ : this.configAggregator.getPropertyValue(orgConfigProperties_1.OrgConfigProperties.TARGET_ORG);
748
+ this.options.aliasOrUsername = aliasOrUsername ?? undefined;
749
+ }
750
+ const username = stateAggregator.aliases.resolveUsername(this.options.aliasOrUsername);
751
+ if (!username) {
752
+ throw messages.createError('noUsernameFound');
753
+ }
754
+ this.connection = await connection_1.Connection.create({
755
+ // If no username is provided or resolvable from an alias, AuthInfo will throw an SfError.
756
+ authInfo: await authInfo_1.AuthInfo.create({ username, isDevHub: this.options.isDevHub }),
757
+ });
758
+ }
759
+ else {
760
+ this.connection = this.options.connection;
761
+ }
762
+ this.orgId = this.getField(Org.Fields.ORG_ID);
763
+ }
764
+ /**
765
+ * **Throws** *{@link SfError}{ name: 'NotSupportedError' }* Throws an unsupported error.
766
+ */
767
+ // eslint-disable-next-line class-methods-use-this
768
+ getDefaultOptions() {
769
+ throw new sfError_1.SfError('Not Supported', 'NotSupportedError');
770
+ }
771
+ async getLocalDataDir(orgDataPath) {
772
+ const rootFolder = await config_1.Config.resolveRootFolder(false);
773
+ return (0, path_1.join)(rootFolder, global_1.Global.SFDX_STATE_FOLDER, orgDataPath ? orgDataPath : 'orgs');
774
+ }
775
+ /**
776
+ * Gets the sandboxProcessObject and then polls for it to complete.
777
+ *
778
+ * @param sandboxProcessName sanbox process name
779
+ * @param options { wait?: Duration; interval?: Duration }
780
+ * @returns {SandboxProcessObject} The SandboxProcessObject for the sandbox
781
+ */
782
+ async authWithRetriesByName(sandboxProcessName, options) {
783
+ return this.authWithRetries(await this.queryLatestSandboxProcessBySandboxName(sandboxProcessName), options);
784
+ }
785
+ /**
786
+ * Polls the sandbox org for the sandboxProcessObject.
787
+ *
788
+ * @param sandboxProcessObj: The in-progress sandbox signup request
789
+ * @param options { wait?: Duration; interval?: Duration }
790
+ * @returns {SandboxProcessObject}
791
+ */
792
+ async authWithRetries(sandboxProcessObj, options = {
793
+ wait: kit_1.Duration.minutes(0),
794
+ interval: kit_1.Duration.seconds(30),
795
+ }) {
796
+ const [wait, pollInterval] = this.validateWaitOptions(options);
797
+ this.logger.debug(`AuthWithRetries sandboxProcessObj ${JSON.stringify(sandboxProcessObj, undefined, 2)}, max wait time of ${wait.minutes} minutes`);
798
+ return this.pollStatusAndAuth({
799
+ sandboxProcessObj,
800
+ wait,
801
+ pollInterval,
802
+ });
803
+ }
804
+ /**
805
+ * Query the sandbox for the SandboxProcessObject by sandbox name
806
+ *
807
+ * @param sandboxName The name of the sandbox to query
808
+ * @returns {SandboxProcessObject} The SandboxProcessObject for the sandbox
809
+ */
810
+ async queryLatestSandboxProcessBySandboxName(sandboxNameIn) {
811
+ const { tooling } = this.getConnection();
812
+ this.logger.debug('QueryLatestSandboxProcessBySandboxName called with SandboxName: %s ', sandboxNameIn);
813
+ const queryStr = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE SandboxName='${sandboxNameIn}' AND Status != 'D' ORDER BY CreatedDate DESC LIMIT 1`;
814
+ const queryResult = await tooling.query(queryStr);
815
+ this.logger.debug('Return from calling queryToolingApi: %s ', queryResult);
816
+ if (queryResult?.records?.length === 1) {
817
+ return queryResult.records[0];
818
+ }
819
+ else if (queryResult.records && queryResult.records.length > 1) {
820
+ throw messages.createError('MultiSandboxProcessNotFoundBySandboxName', [sandboxNameIn]);
821
+ }
822
+ else {
823
+ throw messages.createError('SandboxProcessNotFoundBySandboxName', [sandboxNameIn]);
824
+ }
825
+ }
826
+ // eslint-disable-next-line class-methods-use-this
827
+ async queryProduction(org, field, value) {
828
+ return org.connection.singleRecordQuery(`SELECT SandboxInfoId FROM SandboxProcess WHERE ${field} ='${value}' AND Status NOT IN ('D', 'E')`, { tooling: true });
829
+ }
830
+ async destroySandbox(org, id) {
831
+ return org.getConnection().tooling.delete('SandboxInfo', id);
832
+ }
833
+ async destroyScratchOrg(org, id) {
834
+ return org.getConnection().delete('ActiveScratchOrg', id);
835
+ }
836
+ /**
837
+ * this method will delete the sandbox org from the production org and clean up any local files
838
+ *
839
+ * @param prodOrg - Production org associated with this sandbox
840
+ * @private
841
+ */
842
+ async deleteSandbox(prodOrg) {
843
+ const sandbox = await this.getSandboxConfig(this.getOrgId());
844
+ prodOrg ?? (prodOrg = await Org.create({
845
+ aggregator: this.configAggregator,
846
+ aliasOrUsername: sandbox?.prodOrgUsername,
847
+ }));
848
+ let sandboxInfoId = sandbox?.sandboxInfoId;
849
+ if (!sandboxInfoId) {
850
+ let result;
851
+ try {
852
+ // grab sandboxName from config or try to calculate from the sandbox username
853
+ const sandboxName = sandbox?.sandboxName ?? (this.getUsername() ?? '').split(`${prodOrg.getUsername()}.`)[1];
854
+ if (!sandboxName) {
855
+ this.logger.debug('Sandbox name is not available');
856
+ // jump to query by orgId
857
+ throw new Error();
858
+ }
859
+ this.logger.debug(`attempting to locate sandbox with sandbox ${sandboxName}`);
860
+ try {
861
+ result = await this.queryProduction(prodOrg, 'SandboxName', sandboxName);
862
+ }
863
+ catch (err) {
864
+ this.logger.debug(`Failed to find sandbox with sandbox name: ${sandboxName}`);
865
+ // jump to query by orgId
866
+ throw err;
867
+ }
868
+ }
869
+ catch {
870
+ // if an error is thrown, don't panic yet. we'll try querying by orgId
871
+ const trimmedId = sfdc_1.sfdc.trimTo15(this.getOrgId());
872
+ this.logger.debug(`defaulting to trimming id from ${this.getOrgId()} to ${trimmedId}`);
873
+ try {
874
+ result = await this.queryProduction(prodOrg, 'SandboxOrganization', trimmedId);
875
+ sandboxInfoId = result.SandboxInfoId;
876
+ }
877
+ catch {
878
+ // eating exceptions when trying to find sandbox process record by orgId
879
+ // allows idempotent cleanup of sandbox orgs
880
+ this.logger.debug(`Failed find a SandboxProcess for the sandbox org: ${this.getOrgId()}`);
881
+ }
882
+ }
883
+ }
884
+ if (sandboxInfoId) {
885
+ const deleteResult = await this.destroySandbox(prodOrg, sandboxInfoId);
886
+ this.logger.debug('Return from calling tooling.delete: ', deleteResult);
887
+ }
888
+ // cleanup remaining artifacts
889
+ await this.remove();
890
+ }
891
+ /**
892
+ * If this Org is a scratch org, calling this method will delete the scratch org from the DevHub and clean up any local files
893
+ *
894
+ * @param devHub - optional DevHub Org of the to-be-deleted scratch org
895
+ * @private
896
+ */
897
+ async deleteScratchOrg(devHub) {
898
+ // if we didn't get a devHub, we'll get it from the this org
899
+ devHub ?? (devHub = await this.getDevHubOrg());
900
+ if (!devHub) {
901
+ throw messages.createError('noDevHubFound');
902
+ }
903
+ if (devHub.getOrgId() === this.getOrgId()) {
904
+ // we're attempting to delete a DevHub
905
+ throw messages.createError('deleteOrgHubError');
906
+ }
907
+ try {
908
+ const devHubConn = devHub.getConnection();
909
+ const username = this.getUsername();
910
+ const activeScratchOrgRecordId = (await devHubConn.singleRecordQuery(`SELECT Id FROM ActiveScratchOrg WHERE SignupUsername='${username}'`)).Id;
911
+ this.logger.trace(`found matching ActiveScratchOrg with SignupUsername: ${username}. Deleting...`);
912
+ await this.destroyScratchOrg(devHub, activeScratchOrgRecordId);
913
+ await this.remove();
914
+ }
915
+ catch (err) {
916
+ this.logger.info(err instanceof Error ? err.message : err);
917
+ if (err instanceof Error && (err.name === 'INVALID_TYPE' || err.name === 'INSUFFICIENT_ACCESS_OR_READONLY')) {
918
+ // most likely from devHubConn.delete
919
+ this.logger.info('Insufficient privilege to access ActiveScratchOrgs.');
920
+ throw messages.createError('insufficientAccessToDelete');
921
+ }
922
+ if (err instanceof Error && err.name === connection_1.SingleRecordQueryErrors.NoRecords) {
923
+ // most likely from singleRecordQuery
924
+ this.logger.info('The above error can be the result of deleting an expired or already deleted org.');
925
+ this.logger.info('attempting to cleanup the auth file');
926
+ await this.removeAuth();
927
+ throw messages.createError('scratchOrgNotFound');
928
+ }
929
+ throw err;
930
+ }
931
+ }
932
+ /**
933
+ * Delete an auth info file from the local file system and any related cache information for
934
+ * this Org. You don't want to call this method directly. Instead consider calling Org.remove()
935
+ */
936
+ async removeAuth() {
937
+ const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
938
+ const username = this.getUsername();
939
+ // If there is no username, it has already been removed from the globalInfo.
940
+ // We can skip the unset and just ensure that globalInfo is updated.
941
+ if (username) {
942
+ this.logger.debug(`Removing auth for user: ${username}`);
943
+ this.logger.debug(`Clearing auth cache for user: ${username}`);
944
+ await stateAggregator.orgs.remove(username);
945
+ }
946
+ }
947
+ /**
948
+ * Deletes the users config file
949
+ */
950
+ async removeUsersConfig() {
951
+ const config = await this.retrieveOrgUsersConfig();
952
+ if (await config.exists()) {
953
+ this.logger.debug(`Removing org users config at: ${config.getPath()}`);
954
+ await config.unlink();
955
+ }
956
+ }
957
+ async manageDelete(cb, dirPath, throwWhenRemoveFails) {
958
+ return cb().catch((e) => {
959
+ if (throwWhenRemoveFails) {
960
+ throw e;
961
+ }
962
+ else {
963
+ this.logger.warn(`failed to read directory ${dirPath}`);
964
+ return;
965
+ }
966
+ });
967
+ }
968
+ /**
969
+ * Remove the org users auth file.
970
+ *
971
+ * @param throwWhenRemoveFails true if manageDelete should throw or not if the deleted fails.
972
+ */
973
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
974
+ async removeUsers(throwWhenRemoveFails) {
975
+ const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
976
+ this.logger.debug(`Removing users associate with org: ${this.getOrgId()}`);
977
+ const config = await this.retrieveOrgUsersConfig();
978
+ this.logger.debug(`using path for org users: ${config.getPath()}`);
979
+ const authInfos = await this.readUserAuthFiles();
980
+ await Promise.all(authInfos
981
+ .map((auth) => auth.getFields().username)
982
+ .map(async (username) => {
983
+ const aliasKeys = (username && stateAggregator.aliases.getAll(username)) ?? [];
984
+ stateAggregator.aliases.unsetAll(username);
985
+ const orgForUser = username === this.getUsername()
986
+ ? this
987
+ : await Org.create({
988
+ connection: await connection_1.Connection.create({ authInfo: await authInfo_1.AuthInfo.create({ username }) }),
989
+ });
990
+ const orgType = this.isDevHubOrg() ? orgConfigProperties_1.OrgConfigProperties.TARGET_DEV_HUB : orgConfigProperties_1.OrgConfigProperties.TARGET_ORG;
991
+ const configInfo = orgForUser.configAggregator.getInfo(orgType);
992
+ const needsConfigUpdate = (configInfo.isGlobal() || configInfo.isLocal()) &&
993
+ (configInfo.value === username || aliasKeys.includes(configInfo.value));
994
+ return [
995
+ orgForUser.removeAuth(),
996
+ needsConfigUpdate ? config_1.Config.update(configInfo.isGlobal(), orgType, undefined) : undefined,
997
+ ].filter(Boolean);
998
+ }));
999
+ await stateAggregator.aliases.write();
1000
+ }
1001
+ async removeSandboxConfig() {
1002
+ const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
1003
+ await stateAggregator.sandboxes.remove(this.getOrgId());
1004
+ }
1005
+ async writeSandboxAuthFile(sandboxProcessObj, sandboxRes) {
1006
+ this.logger.debug(`writeSandboxAuthFile sandboxProcessObj: ${JSON.stringify(sandboxProcessObj)}, sandboxRes: ${JSON.stringify(sandboxRes)}`);
1007
+ if (sandboxRes.authUserName) {
1008
+ const productionAuthFields = this.connection.getAuthInfoFields();
1009
+ this.logger.debug('Result from getAuthInfoFields: AuthFields', productionAuthFields);
1010
+ // let's do headless auth via jwt (if we have privateKey) or web auth
1011
+ const oauth2Options = {
1012
+ loginUrl: sandboxRes.loginUrl,
1013
+ instanceUrl: sandboxRes.instanceUrl,
1014
+ username: sandboxRes.authUserName,
1015
+ };
1016
+ // If we don't have a privateKey then we assume it's web auth.
1017
+ if (!productionAuthFields.privateKey) {
1018
+ oauth2Options.redirectUri = `http://localhost:${await webOAuthServer_1.WebOAuthServer.determineOauthPort()}/OauthRedirect`;
1019
+ oauth2Options.authCode = sandboxRes.authCode;
1020
+ }
1021
+ else {
1022
+ oauth2Options.privateKey = productionAuthFields.privateKey;
1023
+ oauth2Options.clientId = productionAuthFields.clientId;
1024
+ }
1025
+ const authInfo = await authInfo_1.AuthInfo.create({
1026
+ username: sandboxRes.authUserName,
1027
+ oauth2Options,
1028
+ parentUsername: productionAuthFields.username,
1029
+ });
1030
+ this.logger.debug('Creating AuthInfo for sandbox', sandboxRes.authUserName, productionAuthFields.username, oauth2Options);
1031
+ // save auth info for new sandbox
1032
+ await authInfo.save();
1033
+ const sandboxOrgId = authInfo.getFields().orgId;
1034
+ if (!sandboxOrgId) {
1035
+ throw messages.createError('AuthInfoOrgIdUndefined');
1036
+ }
1037
+ // set the sandbox config value
1038
+ const sfSandbox = {
1039
+ sandboxUsername: sandboxRes.authUserName,
1040
+ sandboxOrgId,
1041
+ prodOrgUsername: this.getUsername(),
1042
+ sandboxName: sandboxProcessObj.SandboxName,
1043
+ sandboxProcessId: sandboxProcessObj.Id,
1044
+ sandboxInfoId: sandboxProcessObj.SandboxInfoId,
1045
+ timestamp: new Date().toISOString(),
1046
+ };
1047
+ await this.setSandboxConfig(sandboxOrgId, sfSandbox);
1048
+ await (await stateAggregator_1.StateAggregator.getInstance()).sandboxes.write(sandboxOrgId);
1049
+ await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_RESULT, {
1050
+ sandboxProcessObj,
1051
+ sandboxRes,
1052
+ });
1053
+ }
1054
+ else {
1055
+ // no authed sandbox user, error
1056
+ throw messages.createError('missingAuthUsername', [sandboxProcessObj.SandboxName]);
1057
+ }
1058
+ }
1059
+ async pollStatusAndAuth(options) {
1060
+ this.logger.debug('PollStatusAndAuth called with SandboxProcessObject', options.sandboxProcessObj, options.wait.minutes, options.pollInterval.seconds);
1061
+ let remainingWait = options.wait;
1062
+ let waitingOnAuth = false;
1063
+ const pollingClient = await pollingClient_1.PollingClient.create({
1064
+ poll: async () => {
1065
+ const sandboxProcessObj = await this.querySandboxProcessBySandboxInfoId(options.sandboxProcessObj.SandboxInfoId);
1066
+ // check to see if sandbox can authenticate via sandboxAuth endpoint
1067
+ const sandboxInfo = await this.sandboxSignupComplete(sandboxProcessObj);
1068
+ if (sandboxInfo) {
1069
+ await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_AUTH, sandboxInfo);
1070
+ try {
1071
+ this.logger.debug('sandbox signup complete with', sandboxInfo);
1072
+ await this.writeSandboxAuthFile(sandboxProcessObj, sandboxInfo);
1073
+ return { completed: true, payload: sandboxProcessObj };
1074
+ }
1075
+ catch (err) {
1076
+ const error = err;
1077
+ this.logger.debug('Exception while calling writeSandboxAuthFile', err);
1078
+ if (error?.name === 'JwtAuthError' && error?.stack?.includes("user hasn't approved")) {
1079
+ waitingOnAuth = true;
1080
+ }
1081
+ else {
1082
+ throw sfError_1.SfError.wrap(error);
1083
+ }
1084
+ }
1085
+ }
1086
+ await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_STATUS, {
1087
+ sandboxProcessObj,
1088
+ remainingWait: remainingWait.seconds,
1089
+ interval: options.pollInterval.seconds,
1090
+ waitingOnAuth,
1091
+ });
1092
+ remainingWait = kit_1.Duration.seconds(remainingWait.seconds - options.pollInterval.seconds);
1093
+ return { completed: false, payload: sandboxProcessObj };
1094
+ },
1095
+ frequency: options.pollInterval,
1096
+ timeout: options.wait,
1097
+ });
1098
+ return pollingClient.subscribe();
1099
+ }
1100
+ /**
1101
+ * query SandboxProcess using supplied where clause
1102
+ *
1103
+ * @param where clause to query for
1104
+ * @private
1105
+ */
1106
+ async querySandboxProcess(where) {
1107
+ const queryStr = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE ${where} AND Status != 'D'`;
1108
+ return this.connection.singleRecordQuery(queryStr, {
1109
+ tooling: true,
1110
+ });
1111
+ }
1112
+ /**
1113
+ * determines if the sandbox has successfully been created
1114
+ *
1115
+ * @param sandboxProcessObj sandbox signup progress
1116
+ * @private
1117
+ */
1118
+ async sandboxSignupComplete(sandboxProcessObj) {
1119
+ this.logger.debug('sandboxSignupComplete called with SandboxProcessObject', sandboxProcessObj);
1120
+ if (!sandboxProcessObj.EndDate) {
1121
+ return;
1122
+ }
1123
+ try {
1124
+ // call server side /sandboxAuth API to auth the sandbox org user with the connected app
1125
+ const authFields = this.connection.getAuthInfoFields();
1126
+ const callbackUrl = `http://localhost:${await webOAuthServer_1.WebOAuthServer.determineOauthPort()}/OauthRedirect`;
1127
+ const sandboxReq = {
1128
+ // the sandbox signup has been completed on production, we have production clientId by this point
1129
+ clientId: authFields.clientId,
1130
+ sandboxName: sandboxProcessObj.SandboxName,
1131
+ callbackUrl,
1132
+ };
1133
+ this.logger.debug('Calling sandboxAuth with SandboxUserAuthRequest', sandboxReq);
1134
+ // eslint-disable-next-line no-underscore-dangle
1135
+ const url = `${this.connection.tooling._baseUrl()}/sandboxAuth`;
1136
+ const params = {
1137
+ method: 'POST',
1138
+ url,
1139
+ headers: { 'Content-Type': 'application/json' },
1140
+ body: JSON.stringify(sandboxReq),
1141
+ };
1142
+ const result = await this.connection.tooling.request(params);
1143
+ this.logger.debug('Result of calling sandboxAuth', result);
1144
+ return result;
1145
+ }
1146
+ catch (err) {
1147
+ const error = err;
1148
+ // There are cases where the endDate is set before the sandbox has actually completed.
1149
+ // In that case, the sandboxAuth call will throw a specific exception.
1150
+ if (error?.name === 'INVALID_STATUS') {
1151
+ this.logger.debug('Error while authenticating the user', error?.toString());
1152
+ }
1153
+ else {
1154
+ // If it fails for any unexpected reason, just pass that through
1155
+ throw sfError_1.SfError.wrap(error);
1156
+ }
1157
+ }
1158
+ }
1159
+ validateWaitOptions(options) {
1160
+ const wait = options.wait ?? kit_1.Duration.minutes(30);
1161
+ const interval = options.interval ?? kit_1.Duration.seconds(30);
1162
+ let pollInterval = options.async ? kit_1.Duration.seconds(0) : interval;
1163
+ // pollInterval cannot be > wait.
1164
+ pollInterval = pollInterval.seconds > wait.seconds ? wait : pollInterval;
1165
+ return [wait, pollInterval];
1166
+ }
1167
+ }
1168
+ exports.Org = Org;
1169
+ (function (Org) {
1170
+ /**
1171
+ * Scratch Org status.
1172
+ */
1173
+ let Status;
1174
+ (function (Status) {
1175
+ /**
1176
+ * The scratch org is active.
1177
+ */
1178
+ Status["ACTIVE"] = "ACTIVE";
1179
+ /**
1180
+ * The scratch org has expired.
1181
+ */
1182
+ Status["EXPIRED"] = "EXPIRED";
1183
+ /**
1184
+ * The org is a scratch Org but no dev hub is indicated.
1185
+ */
1186
+ Status["UNKNOWN"] = "UNKNOWN";
1187
+ /**
1188
+ * The dev hub configuration is reporting an active Scratch org but the AuthInfo cannot be found.
1189
+ */
1190
+ Status["MISSING"] = "MISSING";
1191
+ })(Status = Org.Status || (Org.Status = {}));
1192
+ /**
1193
+ * Org Fields.
1194
+ */
1195
+ // A subset of fields from AuthInfoFields and properties that are specific to Org,
1196
+ // and properties that are defined on Org itself.
1197
+ let Fields;
1198
+ (function (Fields) {
1199
+ /**
1200
+ * The org alias.
1201
+ */
1202
+ // From AuthInfo
1203
+ Fields["ALIAS"] = "alias";
1204
+ Fields["CREATED"] = "created";
1205
+ // From Organization
1206
+ Fields["NAME"] = "name";
1207
+ Fields["NAMESPACE_PREFIX"] = "namespacePrefix";
1208
+ Fields["INSTANCE_NAME"] = "instanceName";
1209
+ Fields["TRIAL_EXPIRATION_DATE"] = "trailExpirationDate";
1210
+ /**
1211
+ * The Salesforce instance the org was created on. e.g. `cs42`.
1212
+ */
1213
+ Fields["CREATED_ORG_INSTANCE"] = "createdOrgInstance";
1214
+ /**
1215
+ * The username of the dev hub org that created this org. Only populated for scratch orgs.
1216
+ */
1217
+ Fields["DEV_HUB_USERNAME"] = "devHubUsername";
1218
+ /**
1219
+ * The full url of the instance the org lives on.
1220
+ */
1221
+ Fields["INSTANCE_URL"] = "instanceUrl";
1222
+ /**
1223
+ * Is the current org a dev hub org. e.g. They have access to the `ScratchOrgInfo` object.
1224
+ */
1225
+ Fields["IS_DEV_HUB"] = "isDevHub";
1226
+ /**
1227
+ * Is the current org a scratch org. e.g. Organization has IsSandbox == true and TrialExpirationDate != null.
1228
+ */
1229
+ Fields["IS_SCRATCH"] = "isScratch";
1230
+ /**
1231
+ * Is the current org a dev hub org. e.g. Organization has IsSandbox == true and TrialExpirationDate == null.
1232
+ */
1233
+ Fields["IS_SANDBOX"] = "isSandbox";
1234
+ /**
1235
+ * The login url of the org. e.g. `https://login.salesforce.com` or `https://test.salesforce.com`.
1236
+ */
1237
+ Fields["LOGIN_URL"] = "loginUrl";
1238
+ /**
1239
+ * The org ID.
1240
+ */
1241
+ Fields["ORG_ID"] = "orgId";
1242
+ /**
1243
+ * The `OrgStatus` of the org.
1244
+ */
1245
+ Fields["STATUS"] = "status";
1246
+ /**
1247
+ * The snapshot used to create the scratch org.
1248
+ */
1249
+ Fields["SNAPSHOT"] = "snapshot";
1250
+ /**
1251
+ * true: the org supports and wants source tracking
1252
+ * false: the org opted out of tracking or can't support it
1253
+ */
1254
+ Fields["TRACKS_SOURCE"] = "tracksSource";
1255
+ // Should it be on org? Leave it off for now, as it might
1256
+ // be confusing to the consumer what this actually is.
1257
+ // USERNAMES = 'usernames',
1258
+ // Keep separation of concerns. I think these should be on a "user" that belongs to the org.
1259
+ // Org can have a list of user objects that belong to it? Should connection be on user and org.getConnection()
1260
+ // gets the orgs current user for the process? Maybe we just want to keep with the Org only model for
1261
+ // the end of time?
1262
+ // USER_ID = 'userId',
1263
+ // USERNAME = 'username',
1264
+ // PASSWORD = 'password',
1265
+ // USER_PROFILE_NAME = 'userProfileName'
1266
+ })(Fields = Org.Fields || (Org.Fields = {}));
1267
+ })(Org = exports.Org || (exports.Org = {}));
1268
1268
  //# sourceMappingURL=org.js.map