@salesforce/core 8.11.4 → 8.12.1-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/config/configFile.js +6 -2
- package/lib/crypto/keyChain.js +4 -0
- package/lib/global.d.ts +4 -0
- package/lib/global.js +6 -0
- package/lib/logger/logger.js +2 -2
- package/lib/org/authInfo.d.ts +19 -1
- package/lib/org/authInfo.js +64 -17
- package/lib/org/connection.d.ts +4 -0
- package/lib/org/connection.js +1 -1
- package/lib/stateAggregator/accessors/aliasAccessor.d.ts +0 -1
- package/lib/stateAggregator/accessors/aliasAccessor.js +16 -36
- package/lib/status/myDomainResolver.d.ts +1 -0
- package/lib/status/myDomainResolver.js +6 -0
- package/lib/util/fileLocking.js +3 -4
- package/lib/util/lockRetryOptions.d.ts +2 -0
- package/lib/util/lockRetryOptions.js +5 -0
- package/lib/util/time.d.ts +1 -0
- package/lib/util/time.js +2 -2
- package/lib/webOAuthServer.d.ts +27 -1
- package/lib/webOAuthServer.js +43 -8
- package/package.json +2 -2
package/lib/config/configFile.js
CHANGED
|
@@ -247,7 +247,7 @@ class ConfigFile extends configStore_1.BaseConfigStore {
|
|
|
247
247
|
const lockResponse = await (0, fileLocking_1.lockInit)(this.getPath());
|
|
248
248
|
// lock the file. Returns an unlock function to call when done.
|
|
249
249
|
try {
|
|
250
|
-
const fileTimestamp =
|
|
250
|
+
const fileTimestamp = await getNsTimeStamp(this.getPath());
|
|
251
251
|
const fileContents = (0, kit_1.parseJsonMap)(await fs.promises.readFile(this.getPath(), 'utf8'), this.getPath());
|
|
252
252
|
this.logAndMergeContents(fileTimestamp, fileContents);
|
|
253
253
|
}
|
|
@@ -268,7 +268,7 @@ class ConfigFile extends configStore_1.BaseConfigStore {
|
|
|
268
268
|
const lockResponse = (0, fileLocking_1.lockInitSync)(this.getPath());
|
|
269
269
|
try {
|
|
270
270
|
// get the file modstamp. Do this after the lock acquisition in case the file is being written to.
|
|
271
|
-
const fileTimestamp =
|
|
271
|
+
const fileTimestamp = getNsTimeStampSync(this.getPath());
|
|
272
272
|
const fileContents = (0, kit_1.parseJsonMap)(fs.readFileSync(this.getPath(), 'utf8'), this.getPath());
|
|
273
273
|
this.logAndMergeContents(fileTimestamp, fileContents);
|
|
274
274
|
}
|
|
@@ -394,4 +394,8 @@ class ConfigFile extends configStore_1.BaseConfigStore {
|
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
exports.ConfigFile = ConfigFile;
|
|
397
|
+
const getNsTimeStamp = async (filePath) => getNsTimeStampFromStatus(await fs.promises.stat(filePath, { bigint: true }));
|
|
398
|
+
const getNsTimeStampSync = (filePath) => getNsTimeStampFromStatus(fs.statSync(filePath, { bigint: true }));
|
|
399
|
+
/** in browser environment, memfs is missing the bigInt ns timestamp, so we generate it from the ms */
|
|
400
|
+
const getNsTimeStampFromStatus = (stats) => stats.mtimeNs ?? BigInt(stats.mtimeMs) * BigInt(1_000_000);
|
|
397
401
|
//# sourceMappingURL=configFile.js.map
|
package/lib/crypto/keyChain.js
CHANGED
|
@@ -58,6 +58,10 @@ const retrieveKeychain = async (platform) => {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
else if (platform === 'browser') {
|
|
62
|
+
logger.debug(`platform: ${platform}. Using generic keychain.`);
|
|
63
|
+
return keyChainImpl_1.keyChainImpl.generic_unix;
|
|
64
|
+
}
|
|
61
65
|
else {
|
|
62
66
|
throw messages.createError('unsupportedOperatingSystemError', [platform]);
|
|
63
67
|
}
|
package/lib/global.d.ts
CHANGED
|
@@ -32,6 +32,10 @@ export declare class Global {
|
|
|
32
32
|
* The preferred global folder in which state is stored.
|
|
33
33
|
*/
|
|
34
34
|
static readonly STATE_FOLDER = ".sfdx";
|
|
35
|
+
/**
|
|
36
|
+
* Whether the code is running in a web browser.
|
|
37
|
+
*/
|
|
38
|
+
static get isWeb(): boolean;
|
|
35
39
|
/**
|
|
36
40
|
* The full system path to the global sfdx state folder.
|
|
37
41
|
*
|
package/lib/global.js
CHANGED
|
@@ -70,6 +70,12 @@ class Global {
|
|
|
70
70
|
* The preferred global folder in which state is stored.
|
|
71
71
|
*/
|
|
72
72
|
static STATE_FOLDER = Global.SFDX_STATE_FOLDER;
|
|
73
|
+
/**
|
|
74
|
+
* Whether the code is running in a web browser.
|
|
75
|
+
*/
|
|
76
|
+
static get isWeb() {
|
|
77
|
+
return 'window' in globalThis;
|
|
78
|
+
}
|
|
73
79
|
/**
|
|
74
80
|
* The full system path to the global sfdx state folder.
|
|
75
81
|
*
|
package/lib/logger/logger.js
CHANGED
|
@@ -233,7 +233,7 @@ class Logger {
|
|
|
233
233
|
* Gets the name of this logger.
|
|
234
234
|
*/
|
|
235
235
|
getName() {
|
|
236
|
-
return this.pinoLogger.bindings().name ?? '';
|
|
236
|
+
return (this.pinoLogger?.bindings ? this.pinoLogger.bindings().name : '') ?? '';
|
|
237
237
|
}
|
|
238
238
|
/**
|
|
239
239
|
* Gets the current level of this logger.
|
|
@@ -409,7 +409,7 @@ const getWriteStream = (level = 'warn') => {
|
|
|
409
409
|
// write to a rotating file
|
|
410
410
|
target: 'pino/file',
|
|
411
411
|
options: {
|
|
412
|
-
destination: path.join(global_1.Global.SF_DIR, `sf-${rotator.get(logRotationPeriod) ?? rotator.get('1d')}.log`),
|
|
412
|
+
destination: path.join(global_1.Global.SF_DIR, `sf-${(0, ts_types_1.ensureString)(rotator.get(logRotationPeriod)) ?? rotator.get('1d')}.log`),
|
|
413
413
|
mkdir: true,
|
|
414
414
|
level,
|
|
415
415
|
},
|
package/lib/org/authInfo.d.ts
CHANGED
|
@@ -7,6 +7,15 @@ import { Org } from './org';
|
|
|
7
7
|
* Fields for authorization, org, and local information.
|
|
8
8
|
*/
|
|
9
9
|
export type AuthFields = {
|
|
10
|
+
apps?: {
|
|
11
|
+
[key: string]: {
|
|
12
|
+
clientId: string;
|
|
13
|
+
clientSecret?: string;
|
|
14
|
+
accessToken: string;
|
|
15
|
+
refreshToken: string;
|
|
16
|
+
oauthFlow: 'web';
|
|
17
|
+
};
|
|
18
|
+
};
|
|
10
19
|
accessToken?: string;
|
|
11
20
|
alias?: string;
|
|
12
21
|
authCode?: string;
|
|
@@ -234,8 +243,10 @@ export declare class AuthInfo extends AsyncOptionalCreatable<AuthInfo.Options> {
|
|
|
234
243
|
update(authData?: AuthFields): AuthInfo;
|
|
235
244
|
/**
|
|
236
245
|
* Get the auth fields (decrypted) needed to make a connection.
|
|
246
|
+
*
|
|
247
|
+
* @param app Name of the CA/ECA associated with the user.
|
|
237
248
|
*/
|
|
238
|
-
getConnectionOptions(): ConnectionOptions;
|
|
249
|
+
getConnectionOptions(app?: string): ConnectionOptions;
|
|
239
250
|
getClientId(): string;
|
|
240
251
|
getRedirectUri(): string;
|
|
241
252
|
/**
|
|
@@ -343,6 +354,13 @@ export declare namespace AuthInfo {
|
|
|
343
354
|
* OAuth options.
|
|
344
355
|
*/
|
|
345
356
|
oauth2Options?: JwtOAuth2Config;
|
|
357
|
+
apps?: Array<{
|
|
358
|
+
name: string;
|
|
359
|
+
accessToken: string;
|
|
360
|
+
refreshToken: string;
|
|
361
|
+
clientId: string;
|
|
362
|
+
clientSecret?: string;
|
|
363
|
+
}>;
|
|
346
364
|
/**
|
|
347
365
|
* Options for the access token auth.
|
|
348
366
|
*/
|
package/lib/org/authInfo.js
CHANGED
|
@@ -445,38 +445,85 @@ class AuthInfo extends kit_1.AsyncOptionalCreatable {
|
|
|
445
445
|
}
|
|
446
446
|
/**
|
|
447
447
|
* Get the auth fields (decrypted) needed to make a connection.
|
|
448
|
+
*
|
|
449
|
+
* @param app Name of the CA/ECA associated with the user.
|
|
448
450
|
*/
|
|
449
|
-
getConnectionOptions() {
|
|
451
|
+
getConnectionOptions(app) {
|
|
450
452
|
const decryptedCopy = this.getFields(true);
|
|
451
453
|
const { accessToken, instanceUrl, loginUrl } = decryptedCopy;
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
454
|
+
// return main app auth fields
|
|
455
|
+
if (!app) {
|
|
456
|
+
if (this.isAccessTokenFlow()) {
|
|
457
|
+
this.logger.info('Returning fields for a connection using access token.');
|
|
458
|
+
// Just auth with the accessToken
|
|
459
|
+
return { accessToken, instanceUrl, loginUrl };
|
|
460
|
+
}
|
|
461
|
+
if (this.isJwt()) {
|
|
462
|
+
this.logger.info('Returning fields for a connection using JWT config.');
|
|
463
|
+
return {
|
|
464
|
+
accessToken,
|
|
465
|
+
instanceUrl,
|
|
466
|
+
refreshFn: this.refreshFn.bind(this),
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
// @TODO: figure out loginUrl and redirectUri (probably get from config class)
|
|
470
|
+
//
|
|
471
|
+
// redirectUri: org.config.getOauthCallbackUrl()
|
|
472
|
+
// loginUrl: this.fields.instanceUrl || this.config.getAppConfig().sfdcLoginUrl
|
|
473
|
+
this.logger.info('Returning fields for a connection using OAuth config.');
|
|
474
|
+
// Decrypt a user provided client secret or use the default.
|
|
459
475
|
return {
|
|
476
|
+
oauth2: {
|
|
477
|
+
loginUrl: instanceUrl ?? sfdcUrl_1.SfdcUrl.PRODUCTION,
|
|
478
|
+
clientId: this.getClientId(),
|
|
479
|
+
redirectUri: this.getRedirectUri(),
|
|
480
|
+
},
|
|
460
481
|
accessToken,
|
|
461
482
|
instanceUrl,
|
|
462
483
|
refreshFn: this.refreshFn.bind(this),
|
|
463
484
|
};
|
|
464
485
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
486
|
+
if (!decryptedCopy.apps) {
|
|
487
|
+
throw new sfError_1.SfError(`${this.username} does not have any apps linked yet.`);
|
|
488
|
+
}
|
|
489
|
+
if (!(app in decryptedCopy.apps)) {
|
|
490
|
+
throw new sfError_1.SfError(`${this.username} does not have a "${app}" app linked yet.`);
|
|
491
|
+
}
|
|
492
|
+
const decryptedApp = decryptedCopy.apps[app];
|
|
471
493
|
return {
|
|
472
494
|
oauth2: {
|
|
473
495
|
loginUrl: instanceUrl ?? sfdcUrl_1.SfdcUrl.PRODUCTION,
|
|
474
|
-
clientId:
|
|
496
|
+
clientId: decryptedApp.clientId,
|
|
475
497
|
redirectUri: this.getRedirectUri(),
|
|
476
498
|
},
|
|
477
|
-
accessToken,
|
|
499
|
+
accessToken: decryptedApp.accessToken,
|
|
478
500
|
instanceUrl,
|
|
479
|
-
refreshFn
|
|
501
|
+
// Specific refreshFn for AuthInfo's apps.
|
|
502
|
+
//
|
|
503
|
+
// Each app stores the oauth flow used for its initial auth, here we ensure each refresh returns
|
|
504
|
+
// a token, update the auth file with it and send it back to jsforce's through the callback.
|
|
505
|
+
refreshFn: async (_conn, callback) => {
|
|
506
|
+
// This only handles refresh for web flow.
|
|
507
|
+
// When more flows are supported for apps, check the `app.oauthFlow` field to set the appropiate refresh helper.
|
|
508
|
+
const authFields = await this.buildRefreshTokenConfig({
|
|
509
|
+
clientId: decryptedApp.clientId,
|
|
510
|
+
clientSecret: decryptedApp.clientSecret,
|
|
511
|
+
refreshToken: decryptedApp.refreshToken,
|
|
512
|
+
loginUrl: instanceUrl,
|
|
513
|
+
});
|
|
514
|
+
await this.save({
|
|
515
|
+
apps: {
|
|
516
|
+
[app]: {
|
|
517
|
+
accessToken: (0, ts_types_1.ensureString)(authFields.accessToken),
|
|
518
|
+
clientId: decryptedApp.clientId,
|
|
519
|
+
clientSecret: decryptedApp.clientSecret,
|
|
520
|
+
refreshToken: decryptedApp.refreshToken,
|
|
521
|
+
oauthFlow: 'web',
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
await callback(null, authFields.accessToken);
|
|
526
|
+
},
|
|
480
527
|
};
|
|
481
528
|
}
|
|
482
529
|
getClientId() {
|
package/lib/org/connection.d.ts
CHANGED
package/lib/org/connection.js
CHANGED
|
@@ -86,7 +86,7 @@ class Connection extends jsforce_node_1.Connection {
|
|
|
86
86
|
callOptions: {
|
|
87
87
|
client: clientId,
|
|
88
88
|
},
|
|
89
|
-
...options.authInfo.getConnectionOptions(),
|
|
89
|
+
...options.authInfo.getConnectionOptions(options.app),
|
|
90
90
|
// this assertion is questionable, but has existed before core7
|
|
91
91
|
};
|
|
92
92
|
const conn = new this({ ...options, connectionOptions });
|
|
@@ -10,11 +10,10 @@ exports.getFileLocation = exports.AliasAccessor = exports.FILENAME = exports.DEF
|
|
|
10
10
|
const node_path_1 = require("node:path");
|
|
11
11
|
const node_os_1 = require("node:os");
|
|
12
12
|
const promises_1 = require("node:fs/promises");
|
|
13
|
-
const proper_lockfile_1 = require("proper-lockfile");
|
|
14
13
|
const kit_1 = require("@salesforce/kit");
|
|
15
14
|
const global_1 = require("../../global");
|
|
16
15
|
const sfError_1 = require("../../sfError");
|
|
17
|
-
const
|
|
16
|
+
const fileLocking_1 = require("../../util/fileLocking");
|
|
18
17
|
exports.DEFAULT_GROUP = 'orgs';
|
|
19
18
|
exports.FILENAME = 'alias.json';
|
|
20
19
|
class AliasAccessor extends kit_1.AsyncOptionalCreatable {
|
|
@@ -94,18 +93,20 @@ class AliasAccessor extends kit_1.AsyncOptionalCreatable {
|
|
|
94
93
|
*/
|
|
95
94
|
async setAndSave(alias, entity) {
|
|
96
95
|
// get a very fresh copy to merge with to avoid conflicts, then lock
|
|
97
|
-
await this.
|
|
96
|
+
const lockResponse = await (0, fileLocking_1.lockInit)(this.fileLocation);
|
|
97
|
+
await this.readFileToAliasStore();
|
|
98
98
|
this.aliasStore.set(alias, getNameOf(entity));
|
|
99
|
-
return this.
|
|
99
|
+
return lockResponse.writeAndUnlock(aliasStoreToRawFileContents(this.aliasStore));
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
102
|
* Unset the given alias(es). Writes to the file
|
|
103
103
|
*
|
|
104
104
|
*/
|
|
105
105
|
async unsetAndSave(alias) {
|
|
106
|
-
await this.
|
|
106
|
+
const lockResponse = await (0, fileLocking_1.lockInit)(this.fileLocation);
|
|
107
|
+
await this.readFileToAliasStore();
|
|
107
108
|
this.aliasStore.delete(alias);
|
|
108
|
-
return this.
|
|
109
|
+
return lockResponse.writeAndUnlock(aliasStoreToRawFileContents(this.aliasStore));
|
|
109
110
|
}
|
|
110
111
|
/**
|
|
111
112
|
* Unset all the aliases for the given array of entity.
|
|
@@ -113,11 +114,12 @@ class AliasAccessor extends kit_1.AsyncOptionalCreatable {
|
|
|
113
114
|
* @param entity the aliasable entity for which you want to unset all aliases
|
|
114
115
|
*/
|
|
115
116
|
async unsetValuesAndSave(aliasees) {
|
|
116
|
-
await this.
|
|
117
|
+
const lockResponse = await (0, fileLocking_1.lockInit)(this.fileLocation);
|
|
118
|
+
await this.readFileToAliasStore();
|
|
117
119
|
(0, kit_1.ensureArray)(aliasees)
|
|
118
120
|
.flatMap((a) => this.getAll(a))
|
|
119
121
|
.map((a) => this.aliasStore.delete(a));
|
|
120
|
-
return this.
|
|
122
|
+
return lockResponse.writeAndUnlock(aliasStoreToRawFileContents(this.aliasStore));
|
|
121
123
|
}
|
|
122
124
|
/**
|
|
123
125
|
* Returns true if the provided alias exists
|
|
@@ -135,29 +137,19 @@ class AliasAccessor extends kit_1.AsyncOptionalCreatable {
|
|
|
135
137
|
* go to the fileSystem and read the file, storing a copy in the class's store
|
|
136
138
|
* if the file doesn't exist, create it empty
|
|
137
139
|
*/
|
|
138
|
-
async readFileToAliasStore(
|
|
139
|
-
if (useLock) {
|
|
140
|
-
await (0, proper_lockfile_1.lock)(this.fileLocation, lockRetryOptions_1.lockRetryOptions);
|
|
141
|
-
}
|
|
140
|
+
async readFileToAliasStore() {
|
|
142
141
|
try {
|
|
143
142
|
this.aliasStore = fileContentsRawToAliasStore(await (0, promises_1.readFile)(this.fileLocation, 'utf-8'));
|
|
144
143
|
}
|
|
145
144
|
catch (e) {
|
|
146
145
|
if (e instanceof Error && 'code' in e && typeof e.code === 'string' && ['ENOENT', 'ENOTDIR'].includes(e.code)) {
|
|
147
|
-
this.aliasStore = new Map();
|
|
148
146
|
await (0, promises_1.mkdir)((0, node_path_1.dirname)(this.fileLocation), { recursive: true });
|
|
149
|
-
|
|
150
|
-
return;
|
|
147
|
+
this.aliasStore = new Map();
|
|
148
|
+
return (0, promises_1.writeFile)(this.fileLocation, aliasStoreToRawFileContents(this.aliasStore));
|
|
151
149
|
}
|
|
152
|
-
if (useLock)
|
|
153
|
-
return unlockIfLocked(this.fileLocation);
|
|
154
150
|
throw e;
|
|
155
151
|
}
|
|
156
152
|
}
|
|
157
|
-
async saveAliasStoreToFile() {
|
|
158
|
-
await (0, promises_1.writeFile)(this.fileLocation, aliasStoreToRawFileContents(this.aliasStore));
|
|
159
|
-
return unlockIfLocked(this.fileLocation);
|
|
160
|
-
}
|
|
161
153
|
}
|
|
162
154
|
exports.AliasAccessor = AliasAccessor;
|
|
163
155
|
/**
|
|
@@ -166,11 +158,11 @@ exports.AliasAccessor = AliasAccessor;
|
|
|
166
158
|
const getNameOf = (entity) => {
|
|
167
159
|
if (typeof entity === 'string')
|
|
168
160
|
return entity;
|
|
169
|
-
const
|
|
170
|
-
if (!
|
|
161
|
+
const { username } = entity;
|
|
162
|
+
if (!username) {
|
|
171
163
|
throw new sfError_1.SfError(`Invalid aliasee, it must contain a user or username property: ${JSON.stringify(entity)}`);
|
|
172
164
|
}
|
|
173
|
-
return
|
|
165
|
+
return username;
|
|
174
166
|
};
|
|
175
167
|
const fileContentsRawToAliasStore = (contents) => {
|
|
176
168
|
const fileContents = JSON.parse(contents);
|
|
@@ -181,16 +173,4 @@ const aliasStoreToRawFileContents = (aliasStore) => JSON.stringify({ [exports.DE
|
|
|
181
173
|
// exported for testSetup mocking
|
|
182
174
|
const getFileLocation = () => (0, node_path_1.join)((0, node_os_1.homedir)(), global_1.Global.SFDX_STATE_FOLDER, exports.FILENAME);
|
|
183
175
|
exports.getFileLocation = getFileLocation;
|
|
184
|
-
const unlockIfLocked = async (fileLocation) => {
|
|
185
|
-
try {
|
|
186
|
-
await (0, proper_lockfile_1.unlock)(fileLocation);
|
|
187
|
-
}
|
|
188
|
-
catch (e) {
|
|
189
|
-
// ignore the error. If it wasn't locked, that's what we wanted
|
|
190
|
-
if (errorIsNotAcquired(e))
|
|
191
|
-
return;
|
|
192
|
-
throw e;
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
const errorIsNotAcquired = (e) => e instanceof Error && 'code' in e && e.code === 'ENOTACQUIRED';
|
|
196
176
|
//# sourceMappingURL=aliasAccessor.js.map
|
|
@@ -38,6 +38,7 @@ export declare class MyDomainResolver extends AsyncOptionalCreatable<MyDomainRes
|
|
|
38
38
|
* executing the dns loookup.
|
|
39
39
|
*/
|
|
40
40
|
resolve(): Promise<string>;
|
|
41
|
+
/** @deprecated there is nothing using this in forcedotcom, salesforcecli, or public github search */
|
|
41
42
|
getCnames(): Promise<string[]>;
|
|
42
43
|
/**
|
|
43
44
|
* Used to initialize asynchronous components.
|
|
@@ -14,6 +14,7 @@ const ts_types_1 = require("@salesforce/ts-types");
|
|
|
14
14
|
const kit_1 = require("@salesforce/kit");
|
|
15
15
|
const logger_1 = require("../logger/logger");
|
|
16
16
|
const sfdcUrl_1 = require("../util/sfdcUrl");
|
|
17
|
+
const global_1 = require("../global");
|
|
17
18
|
const pollingClient_1 = require("./pollingClient");
|
|
18
19
|
// Timeout for DNS lookup polling defaults to 3 seconds and should always be at least 3 seconds
|
|
19
20
|
const DNS_TIMEOUT = Math.max(3, new kit_1.Env().getNumber('SFDX_DNS_TIMEOUT', 3));
|
|
@@ -69,6 +70,10 @@ class MyDomainResolver extends kit_1.AsyncOptionalCreatable {
|
|
|
69
70
|
this.logger.debug('SF_DISABLE_DNS_CHECK set to true. Skipping DNS check...');
|
|
70
71
|
return this.options.url.host;
|
|
71
72
|
}
|
|
73
|
+
if (global_1.Global.isWeb) {
|
|
74
|
+
this.logger.debug('Web browser detected. Skipping DNS check...');
|
|
75
|
+
return this.options.url.host;
|
|
76
|
+
}
|
|
72
77
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
73
78
|
const self = this;
|
|
74
79
|
const pollingOptions = {
|
|
@@ -106,6 +111,7 @@ class MyDomainResolver extends kit_1.AsyncOptionalCreatable {
|
|
|
106
111
|
const client = await pollingClient_1.PollingClient.create(pollingOptions);
|
|
107
112
|
return (0, ts_types_1.ensureString)(await client.subscribe());
|
|
108
113
|
}
|
|
114
|
+
/** @deprecated there is nothing using this in forcedotcom, salesforcecli, or public github search */
|
|
109
115
|
async getCnames() {
|
|
110
116
|
try {
|
|
111
117
|
await this.resolve();
|
package/lib/util/fileLocking.js
CHANGED
|
@@ -55,11 +55,10 @@ const lockInit = async (filePath) => {
|
|
|
55
55
|
catch (err) {
|
|
56
56
|
throw sfError_1.SfError.wrap(err);
|
|
57
57
|
}
|
|
58
|
-
const unlock = await (0, proper_lockfile_1.lock)(filePath, { ...lockRetryOptions_1.lockRetryOptions, realpath: false });
|
|
58
|
+
const unlock = await (0, proper_lockfile_1.lock)(filePath, { ...lockRetryOptions_1.lockRetryOptions, realpath: false, fs });
|
|
59
59
|
return {
|
|
60
60
|
writeAndUnlock: async (data) => {
|
|
61
|
-
|
|
62
|
-
logger.debug(`Writing to file: ${filePath}`);
|
|
61
|
+
(await logger_1.Logger.child('fileLocking.writeAndUnlock')).debug(`Writing to file: ${filePath}`);
|
|
63
62
|
try {
|
|
64
63
|
await fs.promises.writeFile(filePath, data);
|
|
65
64
|
}
|
|
@@ -83,7 +82,7 @@ const lockInitSync = (filePath) => {
|
|
|
83
82
|
catch (err) {
|
|
84
83
|
throw sfError_1.SfError.wrap(err);
|
|
85
84
|
}
|
|
86
|
-
const unlock = (0, proper_lockfile_1.lockSync)(filePath, { ...lockRetryOptions_1.lockOptions, realpath: false });
|
|
85
|
+
const unlock = (0, proper_lockfile_1.lockSync)(filePath, { ...lockRetryOptions_1.lockOptions, realpath: false, fs });
|
|
87
86
|
return {
|
|
88
87
|
writeAndUnlock: (data) => {
|
|
89
88
|
const logger = logger_1.Logger.childFromRoot('fileLocking.writeAndUnlock');
|
|
@@ -5,12 +5,17 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
8
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
12
|
exports.lockRetryOptions = exports.lockOptions = void 0;
|
|
10
13
|
// docs: https://github.com/moxystudio/node-proper-lockfile
|
|
14
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
15
|
exports.lockOptions = { stale: 10_000 };
|
|
12
16
|
exports.lockRetryOptions = {
|
|
13
17
|
...exports.lockOptions,
|
|
14
18
|
retries: { retries: 10, maxTimeout: 1000, factor: 2 },
|
|
19
|
+
fs: node_fs_1.default, // lockfile supports injectable fs, which is needed for browser use
|
|
15
20
|
};
|
|
16
21
|
//# sourceMappingURL=lockRetryOptions.js.map
|
package/lib/util/time.d.ts
CHANGED
package/lib/util/time.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.nowBigInt = void 0;
|
|
|
7
7
|
* Licensed under the BSD 3-Clause license.
|
|
8
8
|
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
9
9
|
*/
|
|
10
|
-
|
|
11
|
-
const nowBigInt = () => BigInt((
|
|
10
|
+
/** using globalThis.performance instead importing from node:perf_hooks so it works in browser */
|
|
11
|
+
const nowBigInt = () => BigInt((globalThis.performance.now() + globalThis.performance.timeOrigin) * 1_000_000);
|
|
12
12
|
exports.nowBigInt = nowBigInt;
|
|
13
13
|
//# sourceMappingURL=time.js.map
|
package/lib/webOAuthServer.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export declare class WebOAuthServer extends AsyncCreatable<WebOAuthServer.Option
|
|
|
26
26
|
private oauth2;
|
|
27
27
|
private oauthConfig;
|
|
28
28
|
private oauthError;
|
|
29
|
+
private app?;
|
|
30
|
+
private username?;
|
|
29
31
|
constructor(options: WebOAuthServer.Options);
|
|
30
32
|
/**
|
|
31
33
|
* Returns the configured oauthLocalPort or the WebOAuthServer.DEFAULT_PORT
|
|
@@ -80,7 +82,31 @@ export declare class WebOAuthServer extends AsyncCreatable<WebOAuthServer.Option
|
|
|
80
82
|
}
|
|
81
83
|
export declare namespace WebOAuthServer {
|
|
82
84
|
type Options = {
|
|
83
|
-
oauthConfig: JwtOAuth2Config
|
|
85
|
+
oauthConfig: JwtOAuth2Config & {
|
|
86
|
+
/**
|
|
87
|
+
* OAuth scopes to be requested for the access token.
|
|
88
|
+
*
|
|
89
|
+
* This should be a string with each scope separated by spaces:
|
|
90
|
+
* "refresh_token sfap_api chatbot_api web api"
|
|
91
|
+
*
|
|
92
|
+
* If not specified, all scopes assigned to the connected app are requested.
|
|
93
|
+
*/
|
|
94
|
+
scope?: string;
|
|
95
|
+
};
|
|
96
|
+
} | {
|
|
97
|
+
oauthConfig: JwtOAuth2Config & {
|
|
98
|
+
/**
|
|
99
|
+
* OAuth scopes to be requested for the access token.
|
|
100
|
+
*
|
|
101
|
+
* This should be a string with each scope separated by spaces:
|
|
102
|
+
* "refresh_token sfap_api chatbot_api web api"
|
|
103
|
+
*
|
|
104
|
+
* If not specified, all scopes assigned to the connected app are requested.
|
|
105
|
+
*/
|
|
106
|
+
scope?: string;
|
|
107
|
+
};
|
|
108
|
+
app: string;
|
|
109
|
+
username: string;
|
|
84
110
|
};
|
|
85
111
|
type Request = http.IncomingMessage & {
|
|
86
112
|
query: {
|
package/lib/webOAuthServer.js
CHANGED
|
@@ -73,9 +73,15 @@ class WebOAuthServer extends kit_1.AsyncCreatable {
|
|
|
73
73
|
oauth2;
|
|
74
74
|
oauthConfig;
|
|
75
75
|
oauthError = new Error('Oauth Error');
|
|
76
|
+
app;
|
|
77
|
+
username;
|
|
76
78
|
constructor(options) {
|
|
77
79
|
super(options);
|
|
78
80
|
this.oauthConfig = options.oauthConfig;
|
|
81
|
+
if ('app' in options) {
|
|
82
|
+
this.app = options.app;
|
|
83
|
+
this.username = options.username;
|
|
84
|
+
}
|
|
79
85
|
}
|
|
80
86
|
/**
|
|
81
87
|
* Returns the configured oauthLocalPort or the WebOAuthServer.DEFAULT_PORT
|
|
@@ -113,14 +119,43 @@ class WebOAuthServer extends kit_1.AsyncCreatable {
|
|
|
113
119
|
this.executeOauthRequest()
|
|
114
120
|
.then(async (response) => {
|
|
115
121
|
try {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
// Link app to an existing auth file.
|
|
123
|
+
if (this.app) {
|
|
124
|
+
const authInfo = await authInfo_1.AuthInfo.create({
|
|
125
|
+
oauth2Options: this.oauthConfig,
|
|
126
|
+
oauth2: this.oauth2,
|
|
127
|
+
});
|
|
128
|
+
const authFields = authInfo.getFields(true);
|
|
129
|
+
// get user authInfo and save app creds in `apps`
|
|
130
|
+
const userAuthInfo = await authInfo_1.AuthInfo.create({
|
|
131
|
+
username: this.username,
|
|
132
|
+
});
|
|
133
|
+
await userAuthInfo.save({
|
|
134
|
+
apps: {
|
|
135
|
+
[this.app]: {
|
|
136
|
+
clientId: (0, ts_types_1.ensureString)(authFields.clientId),
|
|
137
|
+
clientSecret: authFields.clientSecret,
|
|
138
|
+
accessToken: (0, ts_types_1.ensureString)(authFields.accessToken),
|
|
139
|
+
refreshToken: (0, ts_types_1.ensureString)(authFields.refreshToken),
|
|
140
|
+
oauthFlow: 'web',
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
await this.webServer.handleSuccess(response);
|
|
145
|
+
response.end();
|
|
146
|
+
resolve(authInfo);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// new auth, create new file.
|
|
150
|
+
const authInfo = await authInfo_1.AuthInfo.create({
|
|
151
|
+
oauth2Options: this.oauthConfig,
|
|
152
|
+
oauth2: this.oauth2,
|
|
153
|
+
});
|
|
154
|
+
await authInfo.save();
|
|
155
|
+
await this.webServer.handleSuccess(response);
|
|
156
|
+
response.end();
|
|
157
|
+
resolve(authInfo);
|
|
158
|
+
}
|
|
124
159
|
}
|
|
125
160
|
catch (err) {
|
|
126
161
|
this.oauthError = err;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/core",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.12.1-dev.0",
|
|
4
4
|
"description": "Core libraries to interact with SFDX projects, orgs, and APIs.",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"@salesforce/ts-sinon": "^1.4.30",
|
|
78
78
|
"@types/benchmark": "^2.1.5",
|
|
79
79
|
"@types/fast-levenshtein": "^0.0.4",
|
|
80
|
-
"@types/jsonwebtoken": "9.0.
|
|
80
|
+
"@types/jsonwebtoken": "9.0.9",
|
|
81
81
|
"@types/proper-lockfile": "^4.1.4",
|
|
82
82
|
"@types/semver": "^7.5.8",
|
|
83
83
|
"benchmark": "^2.1.4",
|