@salesforce/core 3.18.3 → 3.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/lib/config/configAggregator.d.ts +2 -2
- package/lib/config/configAggregator.js +12 -8
- package/lib/config/envVars.d.ts +2 -3
- package/lib/config/envVars.js +8 -13
- package/lib/config/sandboxProcessCache.d.ts +1 -0
- package/lib/org/authInfo.d.ts +4 -1
- package/lib/org/authInfo.js +43 -17
- package/lib/org/connection.js +2 -1
- package/lib/org/org.d.ts +17 -1
- package/lib/org/org.js +41 -2
- package/lib/org/scratchOrgCache.d.ts +1 -0
- package/lib/org/scratchOrgCreate.d.ts +2 -0
- package/lib/org/scratchOrgCreate.js +10 -6
- package/lib/testSetup.d.ts +1 -0
- package/lib/testSetup.js +1 -0
- package/lib/util/sfdcUrl.d.ts +3 -9
- package/lib/util/sfdcUrl.js +29 -28
- package/messages/core.md +10 -0
- package/messages/scratchOrgCreate.md +0 -4
- package/messages/scratchOrgInfoApi.md +4 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [3.19.2](https://github.com/forcedotcom/sfdx-core/compare/v3.19.1...v3.19.2) (2022-06-02)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- loosen audience url determination ([#588](https://github.com/forcedotcom/sfdx-core/issues/588)) ([a58ab89](https://github.com/forcedotcom/sfdx-core/commit/a58ab89e2ada34fbdb6d8c72d88966a5281db60b))
|
|
10
|
+
|
|
11
|
+
### [3.19.1](https://github.com/forcedotcom/sfdx-core/compare/v3.19.0...v3.19.1) (2022-05-27)
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
- env var resolution in ConfigAggregator ([#590](https://github.com/forcedotcom/sfdx-core/issues/590)) ([a65cfbd](https://github.com/forcedotcom/sfdx-core/commit/a65cfbdd0e2a6c3806aa4da3270b237f68b37133))
|
|
16
|
+
|
|
17
|
+
## [3.19.0](https://github.com/forcedotcom/sfdx-core/compare/v3.18.3...v3.19.0) (2022-05-20)
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
- missing prop and logic correction ([debe97e](https://github.com/forcedotcom/sfdx-core/commit/debe97e08f54bbd55edd2cb5b18e9d14abd3652f))
|
|
22
|
+
- property on org with inteligent defaults and handling of undefined ([e7295d3](https://github.com/forcedotcom/sfdx-core/commit/e7295d38f2b8defdb54a77e61b4ef8862e5398f9))
|
|
23
|
+
- tracking property on AuthFields ([2243d34](https://github.com/forcedotcom/sfdx-core/commit/2243d345c5cc81bd637c889adbe1db6eae6c93fc))
|
|
24
|
+
- tracksSource in TestSetup mock ([7544c60](https://github.com/forcedotcom/sfdx-core/commit/7544c604bd4a32d21d105e8472f41b2d37fbf601))
|
|
25
|
+
|
|
5
26
|
### [3.18.3](https://github.com/forcedotcom/sfdx-core/compare/v3.18.2...v3.18.3) (2022-05-20)
|
|
6
27
|
|
|
7
28
|
### [3.18.2](https://github.com/forcedotcom/sfdx-core/compare/v3.18.1...v3.18.2) (2022-05-17)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AsyncOptionalCreatable } from '@salesforce/kit';
|
|
2
|
-
import { AnyJson, JsonMap, Optional } from '@salesforce/ts-types';
|
|
2
|
+
import { AnyJson, Dictionary, JsonMap, Optional } from '@salesforce/ts-types';
|
|
3
3
|
import { Config, ConfigPropertyMeta } from './config';
|
|
4
4
|
/**
|
|
5
5
|
* Information about a config property.
|
|
@@ -161,7 +161,7 @@ export declare class ConfigAggregator extends AsyncOptionalCreatable<ConfigAggre
|
|
|
161
161
|
/**
|
|
162
162
|
* Get the config properties that are environment variables.
|
|
163
163
|
*/
|
|
164
|
-
getEnvVars():
|
|
164
|
+
getEnvVars(): Dictionary<string>;
|
|
165
165
|
/**
|
|
166
166
|
* Re-read all property configurations from disk.
|
|
167
167
|
*/
|
|
@@ -37,6 +37,7 @@ class ConfigAggregator extends kit_1.AsyncOptionalCreatable {
|
|
|
37
37
|
*/
|
|
38
38
|
constructor(options) {
|
|
39
39
|
super(options || {});
|
|
40
|
+
this.envVars = {};
|
|
40
41
|
// Don't throw an project error with the aggregator, since it should resolve to global if
|
|
41
42
|
// there is no project.
|
|
42
43
|
try {
|
|
@@ -107,7 +108,7 @@ class ConfigAggregator extends kit_1.AsyncOptionalCreatable {
|
|
|
107
108
|
*/
|
|
108
109
|
getPropertyValue(key) {
|
|
109
110
|
if (this.getAllowedProperties().some((element) => key === element.key)) {
|
|
110
|
-
return this.getConfig()[key]
|
|
111
|
+
return this.getConfig()[key];
|
|
111
112
|
}
|
|
112
113
|
else {
|
|
113
114
|
throw messages.createError('unknownConfigKey', [key]);
|
|
@@ -164,7 +165,7 @@ class ConfigAggregator extends kit_1.AsyncOptionalCreatable {
|
|
|
164
165
|
* @param key The key of the property.
|
|
165
166
|
*/
|
|
166
167
|
getLocation(key) {
|
|
167
|
-
if (this.
|
|
168
|
+
if (this.envVars[key] != null) {
|
|
168
169
|
return "Environment" /* ENVIRONMENT */;
|
|
169
170
|
}
|
|
170
171
|
if (this.localConfig && this.localConfig.get(key)) {
|
|
@@ -189,8 +190,8 @@ class ConfigAggregator extends kit_1.AsyncOptionalCreatable {
|
|
|
189
190
|
* @param key The key of the property.
|
|
190
191
|
*/
|
|
191
192
|
getPath(key) {
|
|
192
|
-
if (this.envVars
|
|
193
|
-
return `$${
|
|
193
|
+
if (this.envVars[key] != null) {
|
|
194
|
+
return `$${envVars_1.EnvVars.propertyToEnvName(key)}`;
|
|
194
195
|
}
|
|
195
196
|
if (this.localConfig && this.localConfig.getContents()[key] != null) {
|
|
196
197
|
return this.localConfig.getPath();
|
|
@@ -239,7 +240,7 @@ class ConfigAggregator extends kit_1.AsyncOptionalCreatable {
|
|
|
239
240
|
* Get the config properties that are environment variables.
|
|
240
241
|
*/
|
|
241
242
|
getEnvVars() {
|
|
242
|
-
return this.envVars
|
|
243
|
+
return this.envVars;
|
|
243
244
|
}
|
|
244
245
|
/**
|
|
245
246
|
* Re-read all property configurations from disk.
|
|
@@ -287,9 +288,12 @@ class ConfigAggregator extends kit_1.AsyncOptionalCreatable {
|
|
|
287
288
|
this.resolveProperties(this.globalConfig.readSync(), this.localConfig && this.localConfig.readSync());
|
|
288
289
|
}
|
|
289
290
|
resolveProperties(globalConfig, localConfig) {
|
|
290
|
-
|
|
291
|
+
const envVars = new envVars_1.EnvVars();
|
|
291
292
|
for (const property of this.getAllowedProperties()) {
|
|
292
|
-
|
|
293
|
+
const key = property.newKey ? property.newKey : property.key;
|
|
294
|
+
const value = envVars.getPropertyFromEnv(property.key);
|
|
295
|
+
if (value)
|
|
296
|
+
this.envVars[key] = value;
|
|
293
297
|
}
|
|
294
298
|
// Global config must be read first so it is on the left hand of the
|
|
295
299
|
// object assign and is overwritten by the local config.
|
|
@@ -298,7 +302,7 @@ class ConfigAggregator extends kit_1.AsyncOptionalCreatable {
|
|
|
298
302
|
if (localConfig) {
|
|
299
303
|
configs.push(localConfig);
|
|
300
304
|
}
|
|
301
|
-
configs.push(this.envVars
|
|
305
|
+
configs.push(this.envVars);
|
|
302
306
|
const json = {};
|
|
303
307
|
const reduced = configs.filter(ts_types_1.isJsonMap).reduce((acc, el) => (0, kit_1.merge)(acc, el), json);
|
|
304
308
|
return reduced;
|
package/lib/config/envVars.d.ts
CHANGED
|
@@ -87,10 +87,9 @@ declare type EnvType = {
|
|
|
87
87
|
export declare const SUPPORTED_ENV_VARS: EnvType;
|
|
88
88
|
export declare class EnvVars extends Env {
|
|
89
89
|
constructor(env?: NodeJS.ProcessEnv);
|
|
90
|
+
static propertyToEnvName(property: string, prefix?: string): string;
|
|
90
91
|
private static defaultPrefix;
|
|
91
|
-
|
|
92
|
-
setPropertyFromEnv(property: string, prefix?: string | undefined): void;
|
|
93
|
-
getPropertyFromEnv<T>(property: string, prefix?: string | undefined): T | undefined;
|
|
92
|
+
getPropertyFromEnv<T>(property: string, prefix?: string): Nullable<T>;
|
|
94
93
|
asDictionary(): Dictionary<unknown>;
|
|
95
94
|
asMap(): Map<string, string>;
|
|
96
95
|
private resolve;
|
package/lib/config/envVars.js
CHANGED
|
@@ -337,7 +337,7 @@ exports.SUPPORTED_ENV_VARS = {
|
|
|
337
337
|
},
|
|
338
338
|
[EnvironmentVariable.SF_ORG_MAX_QUERY_LIMIT]: {
|
|
339
339
|
description: getMessage(EnvironmentVariable.SF_ORG_MAX_QUERY_LIMIT),
|
|
340
|
-
synonymOf:
|
|
340
|
+
synonymOf: EnvironmentVariable.SFDX_MAX_QUERY_LIMIT,
|
|
341
341
|
},
|
|
342
342
|
[EnvironmentVariable.SF_MDAPI_TEMP_DIR]: {
|
|
343
343
|
description: getMessage(EnvironmentVariable.SF_MDAPI_TEMP_DIR),
|
|
@@ -397,6 +397,9 @@ class EnvVars extends kit_1.Env {
|
|
|
397
397
|
super(env);
|
|
398
398
|
this.resolve();
|
|
399
399
|
}
|
|
400
|
+
static propertyToEnvName(property, prefix = EnvVars.defaultPrefix()) {
|
|
401
|
+
return `${prefix || ''}${(0, change_case_1.snakeCase)(property).toUpperCase()}`;
|
|
402
|
+
}
|
|
400
403
|
static defaultPrefix() {
|
|
401
404
|
if (process.argv[0].startsWith('sfdx'))
|
|
402
405
|
return 'SFDX_';
|
|
@@ -404,19 +407,11 @@ class EnvVars extends kit_1.Env {
|
|
|
404
407
|
return 'SF_';
|
|
405
408
|
return 'SFDX_';
|
|
406
409
|
}
|
|
407
|
-
propertyToEnvName(property, prefix = EnvVars.defaultPrefix()) {
|
|
408
|
-
return `${prefix || ''}${(0, change_case_1.snakeCase)(property).toUpperCase()}`;
|
|
409
|
-
}
|
|
410
|
-
setPropertyFromEnv(property, prefix = EnvVars.defaultPrefix()) {
|
|
411
|
-
const envName = this.propertyToEnvName(property, prefix);
|
|
412
|
-
const value = this.getString(envName);
|
|
413
|
-
if (value) {
|
|
414
|
-
this.setString(property, value);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
410
|
getPropertyFromEnv(property, prefix = EnvVars.defaultPrefix()) {
|
|
418
|
-
|
|
419
|
-
|
|
411
|
+
var _a;
|
|
412
|
+
const envName = EnvVars.propertyToEnvName(property, prefix);
|
|
413
|
+
const synonym = (_a = exports.SUPPORTED_ENV_VARS[envName]) === null || _a === void 0 ? void 0 : _a.synonymOf;
|
|
414
|
+
return this.get(envName) || this.get(synonym);
|
|
420
415
|
}
|
|
421
416
|
asDictionary() {
|
|
422
417
|
return this.entries().reduce((accumulator, [key, value]) => {
|
|
@@ -6,6 +6,7 @@ export declare type SandboxRequestCacheEntry = {
|
|
|
6
6
|
prodOrgUsername: string;
|
|
7
7
|
sandboxProcessObject: Partial<SandboxProcessObject>;
|
|
8
8
|
sandboxRequest: Partial<SandboxRequest>;
|
|
9
|
+
tracksSource?: boolean;
|
|
9
10
|
};
|
|
10
11
|
export declare class SandboxRequestCache extends TTLConfig<TTLConfig.Options, SandboxRequestCacheEntry> {
|
|
11
12
|
static getDefaultOptions(): TTLConfig.Options;
|
package/lib/org/authInfo.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export declare type AuthFields = {
|
|
|
37
37
|
usernames?: string[];
|
|
38
38
|
userProfileName?: string;
|
|
39
39
|
expirationDate?: string;
|
|
40
|
+
tracksSource?: boolean;
|
|
40
41
|
};
|
|
41
42
|
export declare type OrgAuthorization = {
|
|
42
43
|
orgId: string;
|
|
@@ -64,6 +65,7 @@ export declare type AuthSideEffects = {
|
|
|
64
65
|
alias?: string;
|
|
65
66
|
setDefault: boolean;
|
|
66
67
|
setDefaultDevHub: boolean;
|
|
68
|
+
setTracksSource?: boolean;
|
|
67
69
|
};
|
|
68
70
|
/**
|
|
69
71
|
* A function to update a refresh token when the access token is expired.
|
|
@@ -287,7 +289,8 @@ export declare class AuthInfo extends AsyncOptionalCreatable<AuthInfo.Options> {
|
|
|
287
289
|
private loadDecryptedAuthFromConfig;
|
|
288
290
|
private isTokenOptions;
|
|
289
291
|
private refreshFn;
|
|
290
|
-
private
|
|
292
|
+
private authJwt;
|
|
293
|
+
private tryJwtAuth;
|
|
291
294
|
private buildRefreshTokenConfig;
|
|
292
295
|
/**
|
|
293
296
|
* Performs an authCode exchange but the Oauth2 feature of jsforce is extended to include a code_challenge
|
package/lib/org/authInfo.js
CHANGED
|
@@ -38,6 +38,7 @@ const messages = messages_1.Messages.load('@salesforce/core', 'core', [
|
|
|
38
38
|
'jwtAuthError',
|
|
39
39
|
'authCodeUsernameRetrievalError',
|
|
40
40
|
'authCodeExchangeError',
|
|
41
|
+
'missingClientId',
|
|
41
42
|
]);
|
|
42
43
|
// Extend OAuth2 to add JWT Bearer Token Flow support.
|
|
43
44
|
class JwtOAuth2 extends jsforce_1.OAuth2 {
|
|
@@ -463,14 +464,22 @@ class AuthInfo extends kit_1.AsyncOptionalCreatable {
|
|
|
463
464
|
* @param sideEffects - instance of AuthSideEffects
|
|
464
465
|
*/
|
|
465
466
|
async handleAliasAndDefaultSettings(sideEffects) {
|
|
466
|
-
if (sideEffects.alias ||
|
|
467
|
+
if (sideEffects.alias ||
|
|
468
|
+
sideEffects.setDefault ||
|
|
469
|
+
sideEffects.setDefaultDevHub ||
|
|
470
|
+
typeof sideEffects.setTracksSource === 'boolean') {
|
|
467
471
|
if (sideEffects.alias)
|
|
468
472
|
await this.setAlias(sideEffects.alias);
|
|
469
473
|
if (sideEffects.setDefault)
|
|
470
474
|
await this.setAsDefault({ org: true });
|
|
471
475
|
if (sideEffects.setDefaultDevHub)
|
|
472
476
|
await this.setAsDefault({ devHub: true });
|
|
473
|
-
|
|
477
|
+
if (typeof sideEffects.setTracksSource === 'boolean') {
|
|
478
|
+
await this.save({ tracksSource: sideEffects.setTracksSource });
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
await this.save();
|
|
482
|
+
}
|
|
474
483
|
}
|
|
475
484
|
}
|
|
476
485
|
/**
|
|
@@ -599,7 +608,7 @@ class AuthInfo extends kit_1.AsyncOptionalCreatable {
|
|
|
599
608
|
options.privateKey = (0, path_1.resolve)(options.privateKeyFile);
|
|
600
609
|
}
|
|
601
610
|
if (options.privateKey) {
|
|
602
|
-
authConfig = await this.
|
|
611
|
+
authConfig = await this.authJwt(options);
|
|
603
612
|
}
|
|
604
613
|
else if (!options.authCode && options.refreshToken) {
|
|
605
614
|
// refresh token flow (from sfdxUrl or OAuth refreshFn)
|
|
@@ -659,27 +668,32 @@ class AuthInfo extends kit_1.AsyncOptionalCreatable {
|
|
|
659
668
|
}
|
|
660
669
|
}
|
|
661
670
|
// Build OAuth config for a JWT auth flow
|
|
662
|
-
async
|
|
671
|
+
async authJwt(options) {
|
|
672
|
+
if (!options.clientId) {
|
|
673
|
+
throw messages.createError('missingClientId');
|
|
674
|
+
}
|
|
663
675
|
const privateKeyContents = await fs.promises.readFile((0, ts_types_1.ensure)(options.privateKey), 'utf8');
|
|
664
676
|
const { loginUrl = sfdcUrl_1.SfdcUrl.PRODUCTION } = options;
|
|
665
677
|
const url = new sfdcUrl_1.SfdcUrl(loginUrl);
|
|
666
678
|
const createdOrgInstance = (0, ts_types_1.getString)(options, 'createdOrgInstance', '').trim().toLowerCase();
|
|
667
679
|
const audienceUrl = await url.getJwtAudienceUrl(createdOrgInstance);
|
|
668
|
-
const jwtToken = jwt.sign({
|
|
669
|
-
iss: options.clientId,
|
|
670
|
-
sub: this.getUsername(),
|
|
671
|
-
aud: audienceUrl,
|
|
672
|
-
exp: Date.now() + 300,
|
|
673
|
-
}, privateKeyContents, {
|
|
674
|
-
algorithm: 'RS256',
|
|
675
|
-
});
|
|
676
|
-
const oauth2 = new JwtOAuth2({ loginUrl: options.loginUrl });
|
|
677
680
|
let authFieldsBuilder;
|
|
678
|
-
|
|
679
|
-
|
|
681
|
+
const authErrors = [];
|
|
682
|
+
// given that we can no longer depend on instance names or URls to determine audience, let's try them all
|
|
683
|
+
const loginAndAudienceUrls = (0, sfdcUrl_1.getLoginAudienceCombos)(audienceUrl, loginUrl);
|
|
684
|
+
for (const [login, audience] of loginAndAudienceUrls) {
|
|
685
|
+
try {
|
|
686
|
+
authFieldsBuilder = await this.tryJwtAuth(options.clientId, login, audience, privateKeyContents);
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
catch (err) {
|
|
690
|
+
const error = err;
|
|
691
|
+
const message = error.message.includes('audience') ? `${error.message}-${login}:${audience}` : error.message;
|
|
692
|
+
authErrors.push(message);
|
|
693
|
+
}
|
|
680
694
|
}
|
|
681
|
-
|
|
682
|
-
throw messages.createError('jwtAuthError', [
|
|
695
|
+
if (!authFieldsBuilder) {
|
|
696
|
+
throw messages.createError('jwtAuthError', [authErrors.join('\n')]);
|
|
683
697
|
}
|
|
684
698
|
const authFields = {
|
|
685
699
|
accessToken: (0, ts_types_1.asString)(authFieldsBuilder.access_token),
|
|
@@ -701,6 +715,18 @@ class AuthInfo extends kit_1.AsyncOptionalCreatable {
|
|
|
701
715
|
}
|
|
702
716
|
return authFields;
|
|
703
717
|
}
|
|
718
|
+
async tryJwtAuth(clientId, loginUrl, audienceUrl, privateKeyContents) {
|
|
719
|
+
const jwtToken = jwt.sign({
|
|
720
|
+
iss: clientId,
|
|
721
|
+
sub: this.getUsername(),
|
|
722
|
+
aud: audienceUrl,
|
|
723
|
+
exp: Date.now() + 300,
|
|
724
|
+
}, privateKeyContents, {
|
|
725
|
+
algorithm: 'RS256',
|
|
726
|
+
});
|
|
727
|
+
const oauth2 = new JwtOAuth2({ loginUrl });
|
|
728
|
+
return (0, ts_types_1.ensureJsonMap)(await oauth2.jwtAuthorize(jwtToken));
|
|
729
|
+
}
|
|
704
730
|
// Build OAuth config for a refresh token auth flow
|
|
705
731
|
async buildRefreshTokenConfig(options) {
|
|
706
732
|
// Ideally, this would be removed at some point in the distant future when all auth files
|
package/lib/org/connection.js
CHANGED
|
@@ -21,6 +21,7 @@ const sfError_1 = require("../sfError");
|
|
|
21
21
|
const sfdc_1 = require("../util/sfdc");
|
|
22
22
|
const messages_1 = require("../messages");
|
|
23
23
|
const lifecycleEvents_1 = require("../lifecycleEvents");
|
|
24
|
+
const orgConfigProperties_1 = require("./orgConfigProperties");
|
|
24
25
|
messages_1.Messages.importMessagesDirectory(__dirname);
|
|
25
26
|
const messages = messages_1.Messages.load('@salesforce/core', 'connection', [
|
|
26
27
|
'incorrectAPIVersionError',
|
|
@@ -332,7 +333,7 @@ class Connection extends jsforce_1.Connection {
|
|
|
332
333
|
async autoFetchQuery(soql, queryOptions = {}) {
|
|
333
334
|
const config = await configAggregator_1.ConfigAggregator.create();
|
|
334
335
|
// take the limit from the calling function, then the config, then default 10,000
|
|
335
|
-
const maxFetch = config.getInfo(
|
|
336
|
+
const maxFetch = config.getInfo(orgConfigProperties_1.OrgConfigProperties.ORG_MAX_QUERY_LIMIT).value || queryOptions.maxFetch || 10000;
|
|
336
337
|
const options = Object.assign(queryOptions, {
|
|
337
338
|
autoFetch: true,
|
|
338
339
|
maxFetch,
|
package/lib/org/org.d.ts
CHANGED
|
@@ -235,6 +235,17 @@ export declare class Org extends AsyncOptionalCreatable<Org.Options> {
|
|
|
235
235
|
* scratch org**. If you need accuracy, use the {@link Org.determineIfScratch} method.
|
|
236
236
|
*/
|
|
237
237
|
isScratch(): boolean;
|
|
238
|
+
/**
|
|
239
|
+
* Returns `true` if the org uses source tracking.
|
|
240
|
+
* Side effect: updates files where the property doesn't currently exist
|
|
241
|
+
*/
|
|
242
|
+
tracksSource(): Promise<boolean>;
|
|
243
|
+
/**
|
|
244
|
+
* Set the tracking property on the org's auth file
|
|
245
|
+
*
|
|
246
|
+
* @param value true or false (whether the org should use source tracking or not)
|
|
247
|
+
*/
|
|
248
|
+
setTracksSource(value: boolean): Promise<void>;
|
|
238
249
|
/**
|
|
239
250
|
* Returns `true` if the org is a scratch org.
|
|
240
251
|
*
|
|
@@ -528,6 +539,11 @@ export declare namespace Org {
|
|
|
528
539
|
/**
|
|
529
540
|
* The snapshot used to create the scratch org.
|
|
530
541
|
*/
|
|
531
|
-
SNAPSHOT = "snapshot"
|
|
542
|
+
SNAPSHOT = "snapshot",
|
|
543
|
+
/**
|
|
544
|
+
* true: the org supports and wants source tracking
|
|
545
|
+
* false: the org opted out of tracking or can't support it
|
|
546
|
+
*/
|
|
547
|
+
TRACKS_SOURCE = "tracksSource"
|
|
532
548
|
}
|
|
533
549
|
}
|
package/lib/org/org.js
CHANGED
|
@@ -418,6 +418,41 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
418
418
|
return false;
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
|
+
/**
|
|
422
|
+
* Returns `true` if the org uses source tracking.
|
|
423
|
+
* Side effect: updates files where the property doesn't currently exist
|
|
424
|
+
*/
|
|
425
|
+
async tracksSource() {
|
|
426
|
+
// use the property if it exists
|
|
427
|
+
const tracksSource = this.getField(Org.Fields.TRACKS_SOURCE);
|
|
428
|
+
if ((0, ts_types_1.isBoolean)(tracksSource)) {
|
|
429
|
+
return tracksSource;
|
|
430
|
+
}
|
|
431
|
+
// scratch orgs with no property use tracking by default
|
|
432
|
+
if (await this.determineIfScratch()) {
|
|
433
|
+
// save true for next time to avoid checking again
|
|
434
|
+
await this.setTracksSource(true);
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
if (await this.determineIfSandbox()) {
|
|
438
|
+
// does the sandbox know about the SourceMember object?
|
|
439
|
+
const supportsSourceMembers = await this.supportsSourceTracking();
|
|
440
|
+
await this.setTracksSource(supportsSourceMembers);
|
|
441
|
+
return supportsSourceMembers;
|
|
442
|
+
}
|
|
443
|
+
// any other non-sandbox, non-scratch orgs won't use tracking
|
|
444
|
+
await this.setTracksSource(false);
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Set the tracking property on the org's auth file
|
|
449
|
+
*
|
|
450
|
+
* @param value true or false (whether the org should use source tracking or not)
|
|
451
|
+
*/
|
|
452
|
+
async setTracksSource(value) {
|
|
453
|
+
const originalAuth = await authInfo_1.AuthInfo.create({ username: this.getUsername() });
|
|
454
|
+
originalAuth.handleAliasAndDefaultSettings({ setDefault: false, setDefaultDevHub: false, setTracksSource: value });
|
|
455
|
+
}
|
|
421
456
|
/**
|
|
422
457
|
* Returns `true` if the org is a scratch org.
|
|
423
458
|
*
|
|
@@ -656,9 +691,8 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
656
691
|
if (this.isScratch()) {
|
|
657
692
|
return true;
|
|
658
693
|
}
|
|
659
|
-
const conn = this.getConnection();
|
|
660
694
|
try {
|
|
661
|
-
await
|
|
695
|
+
await this.getConnection().tooling.sobject('SourceMember').describe();
|
|
662
696
|
return true;
|
|
663
697
|
}
|
|
664
698
|
catch (err) {
|
|
@@ -1207,6 +1241,11 @@ exports.Org = Org;
|
|
|
1207
1241
|
* The snapshot used to create the scratch org.
|
|
1208
1242
|
*/
|
|
1209
1243
|
Fields["SNAPSHOT"] = "snapshot";
|
|
1244
|
+
/**
|
|
1245
|
+
* true: the org supports and wants source tracking
|
|
1246
|
+
* false: the org opted out of tracking or can't support it
|
|
1247
|
+
*/
|
|
1248
|
+
Fields["TRACKS_SOURCE"] = "tracksSource";
|
|
1210
1249
|
// Should it be on org? Leave it off for now, as it might
|
|
1211
1250
|
// be confusing to the consumer what this actually is.
|
|
1212
1251
|
// USERNAMES = 'usernames',
|
|
@@ -11,6 +11,7 @@ export declare type CachedOptions = {
|
|
|
11
11
|
apiVersion?: string;
|
|
12
12
|
alias?: string;
|
|
13
13
|
setDefault?: boolean;
|
|
14
|
+
tracksSource?: boolean;
|
|
14
15
|
};
|
|
15
16
|
export declare class ScratchOrgCache extends TTLConfig<TTLConfig.Options, CachedOptions> {
|
|
16
17
|
static getFileName(): string;
|
|
@@ -47,6 +47,8 @@ export interface ScratchOrgCreateOptions {
|
|
|
47
47
|
alias?: string;
|
|
48
48
|
/** after complete, set the org as the default */
|
|
49
49
|
setDefault?: boolean;
|
|
50
|
+
/** do not use source tracking for this org */
|
|
51
|
+
tracksSource?: boolean;
|
|
50
52
|
}
|
|
51
53
|
export declare const scratchOrgResume: (jobId: string) => Promise<ScratchOrgCreateResult>;
|
|
52
54
|
export declare const scratchOrgCreate: (options: ScratchOrgCreateOptions) => Promise<ScratchOrgCreateResult>;
|
|
@@ -24,7 +24,6 @@ const scratchOrgCache_1 = require("./scratchOrgCache");
|
|
|
24
24
|
const scratchOrgErrorCodes_1 = require("./scratchOrgErrorCodes");
|
|
25
25
|
messages_1.Messages.importMessagesDirectory(__dirname);
|
|
26
26
|
const messages = messages_1.Messages.load('@salesforce/core', 'scratchOrgCreate', [
|
|
27
|
-
'SourceStatusResetFailureError',
|
|
28
27
|
'DurationDaysValidationMaxError',
|
|
29
28
|
'DurationDaysValidationMinError',
|
|
30
29
|
'RetryNotIntError',
|
|
@@ -67,7 +66,7 @@ const scratchOrgResume = async (jobId) => {
|
|
|
67
66
|
if (!cache.has(jobId)) {
|
|
68
67
|
throw messages.createError('CacheMissError', [jobId]);
|
|
69
68
|
}
|
|
70
|
-
const { hubUsername, apiVersion, clientSecret, signupTargetLoginUrlConfig, definitionjson, alias, setDefault } = cache.get(jobId);
|
|
69
|
+
const { hubUsername, apiVersion, clientSecret, signupTargetLoginUrlConfig, definitionjson, alias, setDefault, tracksSource, } = cache.get(jobId);
|
|
71
70
|
const hubOrg = await org_1.Org.create({ aliasOrUsername: hubUsername });
|
|
72
71
|
const soi = await (0, scratchOrgInfoApi_1.queryScratchOrgInfo)(hubOrg, jobId);
|
|
73
72
|
await (0, scratchOrgErrorCodes_1.validateScratchOrgInfoForResume)({ jobId, scratchOrgInfo: soi, cache, hubUsername });
|
|
@@ -99,6 +98,7 @@ const scratchOrgResume = async (jobId) => {
|
|
|
99
98
|
alias,
|
|
100
99
|
setDefault: setDefault !== null && setDefault !== void 0 ? setDefault : false,
|
|
101
100
|
setDefaultDevHub: false,
|
|
101
|
+
setTracksSource: tracksSource !== null && tracksSource !== void 0 ? tracksSource : true,
|
|
102
102
|
});
|
|
103
103
|
cache.unset((_c = soi.Id) !== null && _c !== void 0 ? _c : jobId);
|
|
104
104
|
const authFields = authInfo.getFields();
|
|
@@ -117,7 +117,7 @@ const scratchOrgCreate = async (options) => {
|
|
|
117
117
|
const logger = await logger_1.Logger.child('scratchOrgCreate');
|
|
118
118
|
logger.debug('scratchOrgCreate');
|
|
119
119
|
await (0, scratchOrgLifecycleEvents_1.emit)({ stage: 'prepare request' });
|
|
120
|
-
const { hubOrg, connectedAppConsumerKey, durationDays = 1, nonamespace, noancestors, wait = kit_1.Duration.minutes(exports.DEFAULT_STREAM_TIMEOUT_MINUTES), retry = 0, apiversion, definitionjson, definitionfile, orgConfig, clientSecret = undefined, alias, setDefault = false, } = options;
|
|
120
|
+
const { hubOrg, connectedAppConsumerKey, durationDays = 1, nonamespace, noancestors, wait = kit_1.Duration.minutes(exports.DEFAULT_STREAM_TIMEOUT_MINUTES), retry = 0, apiversion, definitionjson, definitionfile, orgConfig, clientSecret = undefined, alias, setDefault = false, tracksSource = true, } = options;
|
|
121
121
|
validateDuration(durationDays);
|
|
122
122
|
validateRetry(retry);
|
|
123
123
|
const { scratchOrgInfoPayload, ignoreAncestorIds, warnings } = await (0, scratchOrgInfoGenerator_1.getScratchOrgInfoPayload)({
|
|
@@ -153,6 +153,7 @@ const scratchOrgCreate = async (options) => {
|
|
|
153
153
|
clientSecret,
|
|
154
154
|
alias,
|
|
155
155
|
setDefault,
|
|
156
|
+
tracksSource,
|
|
156
157
|
});
|
|
157
158
|
await cache.write();
|
|
158
159
|
logger.debug(`scratch org has recordId ${scratchOrgInfoId}`);
|
|
@@ -185,9 +186,12 @@ const scratchOrgCreate = async (options) => {
|
|
|
185
186
|
(0, scratchOrgInfoApi_1.deploySettings)(scratchOrg, settingsGenerator, (_c = apiversion !== null && apiversion !== void 0 ? apiversion : new configAggregator_1.ConfigAggregator().getPropertyValue('org-api-version')) !== null && _c !== void 0 ? _c : (await scratchOrg.retrieveMaxApiVersion())),
|
|
186
187
|
]);
|
|
187
188
|
await scratchOrgAuthInfo.handleAliasAndDefaultSettings({
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
...{
|
|
190
|
+
alias,
|
|
191
|
+
setDefault,
|
|
192
|
+
setDefaultDevHub: false,
|
|
193
|
+
setTracksSource: tracksSource === false ? false : true,
|
|
194
|
+
},
|
|
191
195
|
});
|
|
192
196
|
cache.unset(scratchOrgInfoId);
|
|
193
197
|
const authFields = authInfo.getFields();
|
package/lib/testSetup.d.ts
CHANGED
package/lib/testSetup.js
CHANGED
|
@@ -543,6 +543,7 @@ class MockTestOrgData {
|
|
|
543
543
|
config.createdOrgInstance = 'CS1';
|
|
544
544
|
config.created = '1519163543003';
|
|
545
545
|
config.userId = this.userId;
|
|
546
|
+
config.tracksSource = this.tracksSource;
|
|
546
547
|
if (this.devHubUsername) {
|
|
547
548
|
config.devHubUsername = this.devHubUsername;
|
|
548
549
|
}
|
package/lib/util/sfdcUrl.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { URL } from 'url';
|
|
3
|
+
export declare function getLoginAudienceCombos(audienceUrl: string, loginUrl: string): [string, string][];
|
|
3
4
|
export declare class SfdcUrl extends URL {
|
|
4
5
|
/**
|
|
5
6
|
* Salesforce URLs
|
|
@@ -27,7 +28,7 @@ export declare class SfdcUrl extends URL {
|
|
|
27
28
|
/**
|
|
28
29
|
* Tests whether this url is an internal Salesforce domain
|
|
29
30
|
*
|
|
30
|
-
* @returns {boolean} true if this is
|
|
31
|
+
* @returns {boolean} true if this is an internal domain
|
|
31
32
|
*/
|
|
32
33
|
isInternalUrl(): boolean;
|
|
33
34
|
/**
|
|
@@ -57,6 +58,7 @@ export declare class SfdcUrl extends URL {
|
|
|
57
58
|
/**
|
|
58
59
|
* Tests whether this url is a sandbox url
|
|
59
60
|
*
|
|
61
|
+
* @Deprecated - identification of a sandbox instance by URL alone is not deterministic
|
|
60
62
|
* @param createdOrgInstance The Salesforce instance the org was created on. e.g. `cs42`
|
|
61
63
|
* @returns {boolean}
|
|
62
64
|
*/
|
|
@@ -67,12 +69,4 @@ export declare class SfdcUrl extends URL {
|
|
|
67
69
|
* @returns {boolean} true if this domain is a lightning domain
|
|
68
70
|
*/
|
|
69
71
|
isLightningDomain(): boolean;
|
|
70
|
-
/**
|
|
71
|
-
* Tests whether this url is a sandbox url
|
|
72
|
-
* otherwise tries to resolve dns cnames and then look if any is sandbox url
|
|
73
|
-
*
|
|
74
|
-
* @param createdOrgInstance The Salesforce instance the org was created on. e.g. `cs42`
|
|
75
|
-
* @returns {Promise<boolean>} true if this domain resolves to sanbox url
|
|
76
|
-
*/
|
|
77
|
-
private resolvesToSandbox;
|
|
78
72
|
}
|
package/lib/util/sfdcUrl.js
CHANGED
|
@@ -6,13 +6,37 @@
|
|
|
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
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.SfdcUrl = void 0;
|
|
9
|
+
exports.SfdcUrl = exports.getLoginAudienceCombos = void 0;
|
|
10
10
|
const url_1 = require("url");
|
|
11
11
|
const kit_1 = require("@salesforce/kit");
|
|
12
12
|
const ts_types_1 = require("@salesforce/ts-types");
|
|
13
13
|
const myDomainResolver_1 = require("../status/myDomainResolver");
|
|
14
14
|
const logger_1 = require("../logger");
|
|
15
15
|
const lifecycleEvents_1 = require("../lifecycleEvents");
|
|
16
|
+
function getLoginAudienceCombos(audienceUrl, loginUrl) {
|
|
17
|
+
const filtered = [
|
|
18
|
+
[loginUrl, loginUrl],
|
|
19
|
+
[SfdcUrl.SANDBOX, SfdcUrl.SANDBOX],
|
|
20
|
+
[SfdcUrl.PRODUCTION, SfdcUrl.PRODUCTION],
|
|
21
|
+
[audienceUrl, audienceUrl],
|
|
22
|
+
[audienceUrl, SfdcUrl.PRODUCTION],
|
|
23
|
+
[audienceUrl, SfdcUrl.SANDBOX],
|
|
24
|
+
[loginUrl, audienceUrl],
|
|
25
|
+
[loginUrl, SfdcUrl.PRODUCTION],
|
|
26
|
+
[loginUrl, SfdcUrl.SANDBOX],
|
|
27
|
+
[SfdcUrl.PRODUCTION, audienceUrl],
|
|
28
|
+
[SfdcUrl.SANDBOX, audienceUrl],
|
|
29
|
+
].filter(([login, audience]) => !((login === SfdcUrl.PRODUCTION && audience === SfdcUrl.SANDBOX) ||
|
|
30
|
+
(login === SfdcUrl.SANDBOX && audience === SfdcUrl.PRODUCTION)));
|
|
31
|
+
const reduced = filtered.reduce((acc, [login, audience]) => {
|
|
32
|
+
const l = new url_1.URL(login);
|
|
33
|
+
const a = new url_1.URL(audience);
|
|
34
|
+
acc.set(`${l.origin}:${a.origin}`, [login, audience]);
|
|
35
|
+
return acc;
|
|
36
|
+
}, new Map());
|
|
37
|
+
return [...reduced.values()];
|
|
38
|
+
}
|
|
39
|
+
exports.getLoginAudienceCombos = getLoginAudienceCombos;
|
|
16
40
|
class SfdcUrl extends url_1.URL {
|
|
17
41
|
constructor(input, base) {
|
|
18
42
|
super(input.toString(), base);
|
|
@@ -45,13 +69,6 @@ class SfdcUrl extends url_1.URL {
|
|
|
45
69
|
this.logger.debug(`Audience URL overridden by env var SFDX_AUDIENCE_URL=${envVarVal}`);
|
|
46
70
|
return envVarVal;
|
|
47
71
|
}
|
|
48
|
-
if (this.isInternalUrl()) {
|
|
49
|
-
// This is for internal developers when just doing authorize
|
|
50
|
-
return this.origin;
|
|
51
|
-
}
|
|
52
|
-
if (await this.resolvesToSandbox(createdOrgInstance)) {
|
|
53
|
-
return SfdcUrl.SANDBOX;
|
|
54
|
-
}
|
|
55
72
|
if ((createdOrgInstance && /^gs1/gi.test(createdOrgInstance)) || /(gs1.my.salesforce.com)/gi.test(this.origin)) {
|
|
56
73
|
return 'https://gs1.salesforce.com';
|
|
57
74
|
}
|
|
@@ -81,7 +98,7 @@ class SfdcUrl extends url_1.URL {
|
|
|
81
98
|
/**
|
|
82
99
|
* Tests whether this url is an internal Salesforce domain
|
|
83
100
|
*
|
|
84
|
-
* @returns {boolean} true if this is
|
|
101
|
+
* @returns {boolean} true if this is an internal domain
|
|
85
102
|
*/
|
|
86
103
|
isInternalUrl() {
|
|
87
104
|
const INTERNAL_URL_PARTS = [
|
|
@@ -157,9 +174,11 @@ class SfdcUrl extends url_1.URL {
|
|
|
157
174
|
/**
|
|
158
175
|
* Tests whether this url is a sandbox url
|
|
159
176
|
*
|
|
177
|
+
* @Deprecated - identification of a sandbox instance by URL alone is not deterministic
|
|
160
178
|
* @param createdOrgInstance The Salesforce instance the org was created on. e.g. `cs42`
|
|
161
179
|
* @returns {boolean}
|
|
162
180
|
*/
|
|
181
|
+
// TODO: how to get rid of this?
|
|
163
182
|
isSandboxUrl(createdOrgInstance) {
|
|
164
183
|
return ((createdOrgInstance && /^cs|s$/gi.test(createdOrgInstance)) ||
|
|
165
184
|
this.origin.endsWith('sandbox.my.salesforce.mil') ||
|
|
@@ -177,25 +196,7 @@ class SfdcUrl extends url_1.URL {
|
|
|
177
196
|
* @returns {boolean} true if this domain is a lightning domain
|
|
178
197
|
*/
|
|
179
198
|
isLightningDomain() {
|
|
180
|
-
return /\.lightning\.force\.com/.test(this.origin);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Tests whether this url is a sandbox url
|
|
184
|
-
* otherwise tries to resolve dns cnames and then look if any is sandbox url
|
|
185
|
-
*
|
|
186
|
-
* @param createdOrgInstance The Salesforce instance the org was created on. e.g. `cs42`
|
|
187
|
-
* @returns {Promise<boolean>} true if this domain resolves to sanbox url
|
|
188
|
-
*/
|
|
189
|
-
async resolvesToSandbox(createdOrgInstance) {
|
|
190
|
-
if (this.isSandboxUrl(createdOrgInstance)) {
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
193
|
-
const myDomainResolver = await myDomainResolver_1.MyDomainResolver.create({ url: this });
|
|
194
|
-
const cnames = await myDomainResolver.getCnames();
|
|
195
|
-
return cnames.some((cname) => {
|
|
196
|
-
const url = new SfdcUrl(`https://${cname}`);
|
|
197
|
-
return url.isSandboxUrl();
|
|
198
|
-
});
|
|
199
|
+
return /\.lightning\.force\.com/.test(this.origin) || /\.lightning\.crmforce\.mil/.test(this.origin);
|
|
199
200
|
}
|
|
200
201
|
}
|
|
201
202
|
exports.SfdcUrl = SfdcUrl;
|
package/messages/core.md
CHANGED
|
@@ -24,6 +24,12 @@ Due to: %s
|
|
|
24
24
|
|
|
25
25
|
Error authenticating with JWT config due to: %s
|
|
26
26
|
|
|
27
|
+
# jwtAuthErrors
|
|
28
|
+
|
|
29
|
+
Error authenticating with JWT.
|
|
30
|
+
Errors encountered:
|
|
31
|
+
%s
|
|
32
|
+
|
|
27
33
|
# refreshTokenAuthError
|
|
28
34
|
|
|
29
35
|
Error authenticating with the refresh token due to: %s
|
|
@@ -55,3 +61,7 @@ Setting aliases must be in the format <key>=<value> but found: [%s].
|
|
|
55
61
|
|
|
56
62
|
All JSON input must have heads down camelcase keys. E.g., `{ sfdcLoginUrl: "https://login.salesforce.com" }`
|
|
57
63
|
Found "%s" at %s
|
|
64
|
+
|
|
65
|
+
# missingClientId
|
|
66
|
+
|
|
67
|
+
Client ID is required for JWT authentication.
|
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Org snapshots don’t support one or more options you specified: %s.
|
|
4
4
|
|
|
5
|
-
# SourceStatusResetFailureError
|
|
6
|
-
|
|
7
|
-
Successfully created org with ID: %s and name: %s. Unfortunately, source tracking isn’t working as expected. If you run force:source:status, the results may be incorrect. Try again by creating another scratch org.
|
|
8
|
-
|
|
9
5
|
# DurationDaysValidationMinError
|
|
10
6
|
|
|
11
7
|
Expected 'durationDays' greater than or equal to %s but received %s.
|
|
@@ -9,3 +9,7 @@ You cannot use 'settings' and `'orgPreferences' in your scratch definition file,
|
|
|
9
9
|
# DeprecatedPrefFormat
|
|
10
10
|
|
|
11
11
|
We've deprecated OrgPreferences. Update the scratch org definition file to replace OrgPreferences with their corresponding settings.
|
|
12
|
+
|
|
13
|
+
# SourceStatusResetFailureError
|
|
14
|
+
|
|
15
|
+
Successfully created org with ID: %s and name: %s. Unfortunately, source tracking isn’t working as expected. If you run force:source:status, the results may be incorrect. Try again by creating another scratch org.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.2",
|
|
4
4
|
"description": "Core libraries to interact with SFDX projects, orgs, and APIs.",
|
|
5
5
|
"main": "lib/exported",
|
|
6
6
|
"types": "lib/exported.d.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@salesforce/bunyan": "^2.0.0",
|
|
38
|
-
"@salesforce/kit": "^1.5.
|
|
38
|
+
"@salesforce/kit": "^1.5.41",
|
|
39
39
|
"@salesforce/schemas": "^1.1.0",
|
|
40
40
|
"@salesforce/ts-types": "^1.5.20",
|
|
41
41
|
"@types/graceful-fs": "^4.1.5",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"form-data": "^4.0.0",
|
|
50
50
|
"graceful-fs": "^4.2.9",
|
|
51
51
|
"js2xmlparser": "^4.0.1",
|
|
52
|
-
"jsforce": "2.0.0-beta.
|
|
52
|
+
"jsforce": "2.0.0-beta.10",
|
|
53
53
|
"jsonwebtoken": "8.5.1",
|
|
54
54
|
"mkdirp": "1.0.4",
|
|
55
55
|
"ts-retry-promise": "^0.6.0"
|
|
@@ -68,14 +68,14 @@
|
|
|
68
68
|
"@typescript-eslint/parser": "4.33.0",
|
|
69
69
|
"chai": "^4.3.4",
|
|
70
70
|
"commitizen": "^3.1.2",
|
|
71
|
-
"eslint": "^
|
|
71
|
+
"eslint": "^7.27.0",
|
|
72
72
|
"eslint-config-prettier": "^6.15.0",
|
|
73
73
|
"eslint-config-salesforce": "^0.1.6",
|
|
74
74
|
"eslint-config-salesforce-license": "^0.1.6",
|
|
75
75
|
"eslint-config-salesforce-typescript": "^0.2.8",
|
|
76
|
-
"eslint-plugin-header": "
|
|
76
|
+
"eslint-plugin-header": "3.0.0",
|
|
77
77
|
"eslint-plugin-import": "^2.25.4",
|
|
78
|
-
"eslint-plugin-jsdoc": "^
|
|
78
|
+
"eslint-plugin-jsdoc": "^35.1.2",
|
|
79
79
|
"eslint-plugin-prettier": "^3.1.3",
|
|
80
80
|
"husky": "^7.0.4",
|
|
81
81
|
"mocha": "^9.1.3",
|