@salesforce/core-bundle 8.15.0 → 8.17.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/index.d.ts CHANGED
@@ -368,8 +368,9 @@ declare module '@salesforce/core-bundle/config/configAggregator' {
368
368
  * ```
369
369
  */
370
370
  export class ConfigAggregator extends AsyncOptionalCreatable<ConfigAggregator.Options> {
371
- protected static instance: AsyncOptionalCreatable;
372
371
  protected static encrypted: boolean;
372
+ protected static instance: AsyncOptionalCreatable | undefined;
373
+ private static readonly mutex;
373
374
  private allowedProperties;
374
375
  private readonly localConfig?;
375
376
  private readonly globalConfig;
@@ -382,6 +383,12 @@ declare module '@salesforce/core-bundle/config/configAggregator' {
382
383
  constructor(options?: ConfigAggregator.Options);
383
384
  private get config();
384
385
  static create<P extends ConfigAggregator.Options, T extends AsyncOptionalCreatable<P>>(this: new (options?: P) => T, options?: P): Promise<T>;
386
+ /**
387
+ * Clear the cache to force reading from disk.
388
+ *
389
+ * *NOTE: Only call this method if you must and you know what you are doing.*
390
+ */
391
+ static clearInstance(): Promise<void>;
385
392
  /**
386
393
  * Get the info for a given key. If the ConfigAggregator was not asynchronously created OR
387
394
  * the {@link ConfigAggregator.reload} was not called, the config value may be encrypted.
@@ -1691,6 +1698,7 @@ declare module '@salesforce/core-bundle/index' {
1691
1698
  export { ScratchOrgCache } from '@salesforce/core-bundle/org/scratchOrgCache';
1692
1699
  export { default as ScratchOrgSettingsGenerator } from '@salesforce/core-bundle/org/scratchOrgSettingsGenerator';
1693
1700
  export * from '@salesforce/core-bundle/util/sfdc';
1701
+ export * from '@salesforce/core-bundle/util/mutex';
1694
1702
  export * from '@salesforce/core-bundle/testSetup';
1695
1703
 
1696
1704
  }
@@ -5151,6 +5159,7 @@ declare module '@salesforce/core-bundle/stateAggregator/stateAggregator' {
5151
5159
  import { SandboxAccessor } from '@salesforce/core-bundle/stateAggregator/accessors/sandboxAccessor';
5152
5160
  export class StateAggregator extends AsyncOptionalCreatable {
5153
5161
  private static instanceMap;
5162
+ private static readonly mutex;
5154
5163
  aliases: AliasAccessor;
5155
5164
  orgs: OrgAccessor;
5156
5165
  sandboxes: SandboxAccessor;
@@ -5164,8 +5173,15 @@ declare module '@salesforce/core-bundle/stateAggregator/stateAggregator' {
5164
5173
  * Clear the cache to force reading from disk.
5165
5174
  *
5166
5175
  * *NOTE: Only call this method if you must and you know what you are doing.*
5176
+ * *NOTE: This call is NOT thread-safe, so it should only be called when no other threads are using the StateAggregator.*
5167
5177
  */
5168
5178
  static clearInstance(path?: string): void;
5179
+ /**
5180
+ * Clear the cache to force reading from disk in a thread-safe manner.
5181
+ *
5182
+ * *NOTE: Only call this method if you must and you know what you are doing.*
5183
+ */
5184
+ static clearInstanceAsync(path?: string): Promise<void>;
5169
5185
  protected init(): Promise<void>;
5170
5186
  }
5171
5187
 
@@ -6369,6 +6385,58 @@ declare module '@salesforce/core-bundle/util/mapKeys' {
6369
6385
  */
6370
6386
  export default function mapKeys<T>(obj: T, converter: (key: string) => string, deep?: boolean): Record<string, unknown>;
6371
6387
 
6388
+ }
6389
+ declare module '@salesforce/core-bundle/util/mutex' {
6390
+ /**
6391
+ * A mutual exclusion (mutex) class that ensures only one asynchronous operation
6392
+ * can execute at a time, providing thread-safe execution of critical sections.
6393
+ *
6394
+ * @example
6395
+ * ```typescript
6396
+ * const mutex = new Mutex();
6397
+ *
6398
+ * // Only one of these will execute at a time
6399
+ * mutex.lock(async () => {
6400
+ * // Critical section code here
6401
+ * return someAsyncOperation();
6402
+ * });
6403
+ * ```
6404
+ */
6405
+ export class Mutex {
6406
+ /**
6407
+ * Internal promise chain that maintains the mutex state.
6408
+ * Each new lock acquisition is chained to this promise.
6409
+ *
6410
+ * @private
6411
+ */
6412
+ private mutex;
6413
+ /**
6414
+ * Acquires the mutex lock and executes the provided function.
6415
+ * The function will not execute until all previously queued operations complete.
6416
+ *
6417
+ * @template T - The return type of the function
6418
+ * @param fn - The function to execute while holding the mutex lock. Can be synchronous or asynchronous.
6419
+ * @returns A promise that resolves with the result of the function execution
6420
+ *
6421
+ * @example
6422
+ * ```typescript
6423
+ * const result = await mutex.lock(async () => {
6424
+ * // This code is guaranteed to run exclusively
6425
+ * return await someAsyncOperation();
6426
+ * });
6427
+ * ```
6428
+ */
6429
+ lock<T>(fn: () => Promise<T> | T): Promise<T>;
6430
+ /**
6431
+ * Acquires the mutex by waiting for the current promise chain to resolve
6432
+ * and returns a release function to unlock the mutex.
6433
+ *
6434
+ * @private
6435
+ * @returns A promise that resolves to a function that releases the mutex lock
6436
+ */
6437
+ private acquire;
6438
+ }
6439
+
6372
6440
  }
6373
6441
  declare module '@salesforce/core-bundle/util/sfdc' {
6374
6442
  /**
package/lib/index.js CHANGED
@@ -12336,7 +12336,7 @@ var require_package2 = __commonJS({
12336
12336
  "package.json"(exports2, module2) {
12337
12337
  module2.exports = {
12338
12338
  name: "@salesforce/core-bundle",
12339
- version: "8.15.0",
12339
+ version: "8.17.0",
12340
12340
  description: "Core libraries to interact with SFDX projects, orgs, and APIs.",
12341
12341
  main: "lib/index",
12342
12342
  types: "lib/index.d.ts",
@@ -15851,6 +15851,66 @@ var require_envVars = __commonJS({
15851
15851
  }
15852
15852
  });
15853
15853
 
15854
+ // lib/util/mutex.js
15855
+ var require_mutex = __commonJS({
15856
+ "lib/util/mutex.js"(exports2) {
15857
+ "use strict";
15858
+ Object.defineProperty(exports2, "__esModule", { value: true });
15859
+ exports2.Mutex = void 0;
15860
+ var Mutex = class {
15861
+ /**
15862
+ * Internal promise chain that maintains the mutex state.
15863
+ * Each new lock acquisition is chained to this promise.
15864
+ *
15865
+ * @private
15866
+ */
15867
+ mutex = Promise.resolve();
15868
+ /**
15869
+ * Acquires the mutex lock and executes the provided function.
15870
+ * The function will not execute until all previously queued operations complete.
15871
+ *
15872
+ * @template T - The return type of the function
15873
+ * @param fn - The function to execute while holding the mutex lock. Can be synchronous or asynchronous.
15874
+ * @returns A promise that resolves with the result of the function execution
15875
+ *
15876
+ * @example
15877
+ * ```typescript
15878
+ * const result = await mutex.lock(async () => {
15879
+ * // This code is guaranteed to run exclusively
15880
+ * return await someAsyncOperation();
15881
+ * });
15882
+ * ```
15883
+ */
15884
+ async lock(fn) {
15885
+ const unlock = await this.acquire();
15886
+ try {
15887
+ return await fn();
15888
+ } finally {
15889
+ unlock();
15890
+ }
15891
+ }
15892
+ /**
15893
+ * Acquires the mutex by waiting for the current promise chain to resolve
15894
+ * and returns a release function to unlock the mutex.
15895
+ *
15896
+ * @private
15897
+ * @returns A promise that resolves to a function that releases the mutex lock
15898
+ */
15899
+ async acquire() {
15900
+ let release;
15901
+ const promise = new Promise((resolve) => {
15902
+ release = resolve;
15903
+ });
15904
+ const currentMutex = this.mutex;
15905
+ this.mutex = this.mutex.then(() => promise);
15906
+ await currentMutex;
15907
+ return release;
15908
+ }
15909
+ };
15910
+ exports2.Mutex = Mutex;
15911
+ }
15912
+ });
15913
+
15854
15914
  // lib/stateAggregator/accessors/aliasAccessor.js
15855
15915
  var require_aliasAccessor = __commonJS({
15856
15916
  "lib/stateAggregator/accessors/aliasAccessor.js"(exports2) {
@@ -16394,11 +16454,13 @@ var require_stateAggregator = __commonJS({
16394
16454
  exports2.StateAggregator = void 0;
16395
16455
  var kit_1 = require_lib2();
16396
16456
  var global_12 = require_global();
16457
+ var mutex_1 = require_mutex();
16397
16458
  var aliasAccessor_1 = require_aliasAccessor();
16398
16459
  var orgAccessor_1 = require_orgAccessor();
16399
16460
  var sandboxAccessor_1 = require_sandboxAccessor();
16400
16461
  var StateAggregator = class _StateAggregator extends kit_1.AsyncOptionalCreatable {
16401
16462
  static instanceMap = /* @__PURE__ */ new Map();
16463
+ static mutex = new mutex_1.Mutex();
16402
16464
  aliases;
16403
16465
  orgs;
16404
16466
  sandboxes;
@@ -16408,19 +16470,32 @@ var require_stateAggregator = __commonJS({
16408
16470
  * HomeDir might be stubbed in tests
16409
16471
  */
16410
16472
  static async getInstance() {
16411
- if (!_StateAggregator.instanceMap.has(global_12.Global.DIR)) {
16412
- _StateAggregator.instanceMap.set(global_12.Global.DIR, await _StateAggregator.create());
16413
- }
16414
- return _StateAggregator.instanceMap.get(global_12.Global.DIR);
16473
+ return _StateAggregator.mutex.lock(async () => {
16474
+ if (!_StateAggregator.instanceMap.has(global_12.Global.DIR)) {
16475
+ _StateAggregator.instanceMap.set(global_12.Global.DIR, await _StateAggregator.create());
16476
+ }
16477
+ return _StateAggregator.instanceMap.get(global_12.Global.DIR);
16478
+ });
16415
16479
  }
16416
16480
  /**
16417
16481
  * Clear the cache to force reading from disk.
16418
16482
  *
16419
16483
  * *NOTE: Only call this method if you must and you know what you are doing.*
16484
+ * *NOTE: This call is NOT thread-safe, so it should only be called when no other threads are using the StateAggregator.*
16420
16485
  */
16421
16486
  static clearInstance(path = global_12.Global.DIR) {
16422
16487
  _StateAggregator.instanceMap.delete(path);
16423
16488
  }
16489
+ /**
16490
+ * Clear the cache to force reading from disk in a thread-safe manner.
16491
+ *
16492
+ * *NOTE: Only call this method if you must and you know what you are doing.*
16493
+ */
16494
+ static async clearInstanceAsync(path = global_12.Global.DIR) {
16495
+ return _StateAggregator.mutex.lock(() => {
16496
+ _StateAggregator.clearInstance(path);
16497
+ });
16498
+ }
16424
16499
  async init() {
16425
16500
  this.orgs = await orgAccessor_1.OrgAccessor.create();
16426
16501
  this.sandboxes = await sandboxAccessor_1.SandboxAccessor.create();
@@ -84686,12 +84761,14 @@ var require_configAggregator = __commonJS({
84686
84761
  var ts_types_1 = require_lib();
84687
84762
  var messages_12 = require_messages();
84688
84763
  var lifecycleEvents_12 = require_lifecycleEvents();
84764
+ var mutex_1 = require_mutex();
84689
84765
  var envVars_12 = require_envVars();
84690
84766
  var config_12 = require_config();
84691
84767
  var messages = new messages_12.Messages("@salesforce/core-bundle", "config", /* @__PURE__ */ new Map([["unknownConfigKey", "Unknown config name: %s."], ["deprecatedConfigKey", "Deprecated config name: %s. Please use %s instead."], ["invalidWrite", "The writeSync method is not allowed on SfdxConfig. Use the async write method instead."], ["invalidConfigValue", "Invalid config value: %s."], ["invalidInstanceUrl", "Specify a valid Salesforce instance URL."], ["invalidApiVersion", "Specify a valid Salesforce API version, for example, 42.0."], ["invalidCustomOrgMetadataTemplates", "Specify a valid repository URL or directory for the custom org metadata templates."], ["invalidIsvDebuggerSid", "Specify a valid Debugger SID."], ["invalidIsvDebuggerUrl", "Specify a valid Debugger URL."], ["invalidNumberConfigValue", "Specify a valid positive integer, for example, 150000."], ["invalidBooleanConfigValue", "The config value can only be set to true or false."], ["invalidProjectWorkspace", "This directory does not contain a valid Salesforce DX project."], ["schemaValidationError", 'The config file "%s" is not schema valid.\nDue to: %s'], ["schemaValidationError.actions", ["Fix the invalid entries at %s."]], ["missingDefaultPath", 'In sfdx-project.json, be sure to specify which package directory (path) is the default. Example: `[{ "path": "packageDirectory1", "default": true }, { "path": "packageDirectory2" }]`'], ["missingPackageDirectory", 'The path "%s", specified in sfdx-project.json, does not exist. Be sure this directory is included in your project root.'], ["invalidPackageDirectory", 'The path "%s", specified in sfdx-project.json, must be indicated as a relative path to the project root.'], ["multipleDefaultPaths", "In sfdx-project.json, indicate only one package directory (path) as the default."], ["singleNonDefaultPackage", 'The sfdx-project.json file must include one, and only one, default package directory (path). Because your sfdx-project.json file contains only one package directory, it must be the default. Remove the `"default": false` key and try again.'], ["target-org", "Username or alias of the org that all commands run against by default. (sf only)"], ["target-dev-hub", "Username or alias of your default Dev Hub org. (sf only)"], ["defaultUsername", "Username or alias of the org that all commands run against by default. (sfdx only)"], ["defaultDevHubUsername", "Username or alias of your default Dev Hub org. (sfdx only)"], ["isvDebuggerSid", "ISV debugger SID (sfdx only)"], ["isvDebuggerUrl", "ISV debugger URL (sfdx only)"], ["org-isv-debugger-sid", "ISV debugger SID."], ["org-isv-debugger-url", "ISV debugger URL."], ["apiVersion", "API version of your project. Default: API version of your Dev Hub org. (sfdx only)"], ["org-api-version", "API version of your project. Default: API version of your Dev Hub org."], ["disableTelemetry", "Disables the collection of usage and user environment information, etc. Default: false. (sfdx only)"], ["disable-telemetry", "Disables the collection of usage and user environment information, etc. Default: false."], ["maxQueryLimit", "Maximum number of Salesforce records returned by a CLI command. Default: 10,000. (sfdx only)"], ["org-max-query-limit", "Maximum number of Salesforce records returned by a CLI command. Default: 10,000."], ["restDeploy", "Whether deployments use the Metadata REST API (true) or SOAP API (false, default value). (sfdx only)"], ["instanceUrl", "URL of the Salesforce instance hosting your org. Default: https://login.salesforce.com. (sfdx only)"], ["org-instance-url", "URL of the Salesforce instance hosting your org. Default: https://login.salesforce.com."], ["customOrgMetadataTemplates", "A valid repository URL or directory for the custom org metadata templates."], ["org-custom-metadata-templates", "A valid repository URL or directory for the custom org metadata templates."], ["org-capitalize-record-types", "Whether record types are capitalized on scratch org creation."], ["invalidId", "The given id %s is not a valid 15 or 18 character Salesforce ID."]]));
84692
84768
  var ConfigAggregator = class _ConfigAggregator extends kit_1.AsyncOptionalCreatable {
84693
- static instance;
84694
84769
  static encrypted = true;
84770
+ static instance;
84771
+ static mutex = new mutex_1.Mutex();
84695
84772
  // Initialized in loadProperties
84696
84773
  allowedProperties;
84697
84774
  localConfig;
@@ -84720,18 +84797,31 @@ var require_configAggregator = __commonJS({
84720
84797
  // Use typing from AsyncOptionalCreatable to support extending ConfigAggregator.
84721
84798
  // We really don't want ConfigAggregator extended but typescript doesn't support a final.
84722
84799
  static async create(options) {
84723
- let config = _ConfigAggregator.instance;
84724
- if (!config) {
84725
- config = _ConfigAggregator.instance = new this(options);
84726
- await config.init();
84727
- }
84728
- if (_ConfigAggregator.encrypted) {
84729
- await config.loadProperties();
84730
- }
84731
- if (options?.customConfigMeta) {
84732
- config_12.Config.addAllowedProperties(options.customConfigMeta);
84733
- }
84734
- return _ConfigAggregator.instance;
84800
+ return _ConfigAggregator.mutex.lock(async () => {
84801
+ let config = _ConfigAggregator.instance;
84802
+ if (!config) {
84803
+ config = _ConfigAggregator.instance = new this(options);
84804
+ await config.init();
84805
+ }
84806
+ if (_ConfigAggregator.encrypted) {
84807
+ await config.loadProperties();
84808
+ }
84809
+ if (options?.customConfigMeta) {
84810
+ config_12.Config.addAllowedProperties(options.customConfigMeta);
84811
+ }
84812
+ return _ConfigAggregator.instance;
84813
+ });
84814
+ }
84815
+ /**
84816
+ * Clear the cache to force reading from disk.
84817
+ *
84818
+ * *NOTE: Only call this method if you must and you know what you are doing.*
84819
+ */
84820
+ static async clearInstance() {
84821
+ return _ConfigAggregator.mutex.lock(() => {
84822
+ _ConfigAggregator.instance = void 0;
84823
+ _ConfigAggregator.encrypted = true;
84824
+ });
84735
84825
  }
84736
84826
  /**
84737
84827
  * Get the info for a given key. If the ConfigAggregator was not asynchronously created OR
@@ -123304,6 +123394,7 @@ Object.defineProperty(exports, "ScratchOrgSettingsGenerator", { enumerable: true
123304
123394
  return __importDefault2(scratchOrgSettingsGenerator_1).default;
123305
123395
  } });
123306
123396
  __exportStar2(require_sfdc(), exports);
123397
+ __exportStar2(require_mutex(), exports);
123307
123398
  __exportStar2(require_testSetup(), exports);
123308
123399
  /*! Bundled license information:
123309
123400
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/core-bundle",
3
- "version": "8.15.0",
3
+ "version": "8.17.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",