@salesforce/core 4.0.0-v3.0 → 4.0.1

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