@wdio/browserstack-service 9.27.1 → 9.28.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/build/index.js CHANGED
@@ -23,7 +23,7 @@ var init_package = __esm({
23
23
  "package.json"() {
24
24
  package_default = {
25
25
  name: "@wdio/browserstack-service",
26
- version: "9.27.0",
26
+ version: "9.27.2",
27
27
  description: "WebdriverIO service for better Browserstack integration",
28
28
  author: "Adam Bjerstedt <abjerstedt@gmail.com>",
29
29
  homepage: "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-browserstack-service",
@@ -70,7 +70,6 @@ var init_package = __esm({
70
70
  "browserstack-local": "^1.5.1",
71
71
  chalk: "^5.3.0",
72
72
  "csv-writer": "^1.6.0",
73
- "formdata-node": "5.0.1",
74
73
  "git-repo-info": "^2.1.1",
75
74
  gitconfiglocal: "^2.1.0",
76
75
  glob: "^11.0.0",
@@ -98,7 +97,7 @@ var init_package = __esm({
98
97
  });
99
98
 
100
99
  // src/constants.ts
101
- var bstackServiceVersion, BROWSER_DESCRIPTION, VALID_APP_EXTENSION, DEFAULT_OPTIONS, consoleHolder, APP_ALLY_ISSUES_ENDPOINT, APP_ALLY_ISSUES_SUMMARY_ENDPOINT, DATA_EVENT_ENDPOINT, DATA_BATCH_ENDPOINT, DATA_SCREENSHOT_ENDPOINT, DATA_BATCH_SIZE, DATA_BATCH_INTERVAL, DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS, BSTACK_SERVICE_VERSION, NOT_ALLOWED_KEYS_IN_CAPS, LOGS_FILE, CLI_DEBUG_LOGS_FILE, UPLOAD_LOGS_ENDPOINT, PERCY_LOGS_FILE, PERCY_DOM_CHANGING_COMMANDS_ENDPOINTS, CAPTURE_MODES, LOG_KIND_USAGE_MAP, SUPPORTED_BROWSERS_FOR_AI, TCG_URL, TCG_INFO, SMART_SELECTION_MODE_RELEVANT_FIRST, SMART_SELECTION_MODE_RELEVANT_ONLY, BROWSERSTACK_TESTHUB_JWT, BSTACK_TCG_AUTH_RESULT, TESTOPS_SCREENSHOT_ENV, BROWSERSTACK_TESTHUB_UUID, TEST_ANALYTICS_ID, PERF_MEASUREMENT_ENV, RERUN_TESTS_ENV, RERUN_ENV, TESTOPS_BUILD_COMPLETED_ENV, BROWSERSTACK_PERCY, BROWSERSTACK_ACCESSIBILITY, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_TEST_REPORTING, TEST_REPORTING_PROJECT_NAME, MAX_GIT_META_DATA_SIZE_IN_BYTES, GIT_META_DATA_TRUNCATED, CLI_STOP_TIMEOUT, WDIO_NAMING_PREFIX, UPDATED_CLI_ENDPOINT;
100
+ var bstackServiceVersion, BROWSER_DESCRIPTION, VALID_APP_EXTENSION, DEFAULT_OPTIONS, consoleHolder, APP_ALLY_ISSUES_ENDPOINT, APP_ALLY_ISSUES_SUMMARY_ENDPOINT, DATA_EVENT_ENDPOINT, DATA_BATCH_ENDPOINT, DATA_SCREENSHOT_ENDPOINT, DATA_BATCH_SIZE, DATA_BATCH_INTERVAL, DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS, BSTACK_SERVICE_VERSION, NOT_ALLOWED_KEYS_IN_CAPS, BROWSERSTACK_TEST_PLAN_ID, LOGS_FILE, CLI_DEBUG_LOGS_FILE, UPLOAD_LOGS_ENDPOINT, PERCY_LOGS_FILE, PERCY_DOM_CHANGING_COMMANDS_ENDPOINTS, CAPTURE_MODES, LOG_KIND_USAGE_MAP, SUPPORTED_BROWSERS_FOR_AI, SUPPORTED_BROWSERS_FOR_ACCESSIBILITY, MIN_BROWSER_VERSIONS_A11Y, MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK, TCG_URL, TCG_INFO, SMART_SELECTION_MODE_RELEVANT_FIRST, SMART_SELECTION_MODE_RELEVANT_ONLY, BROWSERSTACK_TESTHUB_JWT, BSTACK_TCG_AUTH_RESULT, TESTOPS_SCREENSHOT_ENV, BROWSERSTACK_TESTHUB_UUID, TEST_ANALYTICS_ID, PERF_MEASUREMENT_ENV, RERUN_TESTS_ENV, RERUN_ENV, TESTOPS_BUILD_COMPLETED_ENV, BROWSERSTACK_PERCY, BROWSERSTACK_ACCESSIBILITY, BROWSERSTACK_OBSERVABILITY, BROWSERSTACK_TEST_REPORTING, TEST_REPORTING_PROJECT_NAME, MAX_GIT_META_DATA_SIZE_IN_BYTES, GIT_META_DATA_TRUNCATED, CLI_STOP_TIMEOUT, BINARY_BUSY_ERROR_CODES, MAX_SPAWN_RETRIES, SPAWN_RETRY_DELAY_MS, WDIO_NAMING_PREFIX, UPDATED_CLI_ENDPOINT;
102
101
  var init_constants = __esm({
103
102
  "src/constants.ts"() {
104
103
  "use strict";
@@ -122,8 +121,7 @@ var init_constants = __esm({
122
121
  DEFAULT_OPTIONS = {
123
122
  setSessionName: true,
124
123
  setSessionStatus: true,
125
- testObservability: true,
126
- accessibility: false
124
+ testObservability: true
127
125
  };
128
126
  consoleHolder = Object.assign({}, console);
129
127
  APP_ALLY_ISSUES_ENDPOINT = "api/v1/issues";
@@ -136,7 +134,8 @@ var init_constants = __esm({
136
134
  DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS = 5e3;
137
135
  DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS = 100;
138
136
  BSTACK_SERVICE_VERSION = bstackServiceVersion;
139
- NOT_ALLOWED_KEYS_IN_CAPS = ["includeTagsInTestingScope", "excludeTagsInTestingScope"];
137
+ NOT_ALLOWED_KEYS_IN_CAPS = ["includeTagsInTestingScope", "excludeTagsInTestingScope", "testManagementOptions"];
138
+ BROWSERSTACK_TEST_PLAN_ID = "BROWSERSTACK_TEST_PLAN_ID";
140
139
  LOGS_FILE = "logs/bstack-wdio-service.log";
141
140
  CLI_DEBUG_LOGS_FILE = "log/sdk-cli-debug.log";
142
141
  UPLOAD_LOGS_ENDPOINT = "client-logs/upload";
@@ -158,6 +157,17 @@ var init_constants = __esm({
158
157
  "HTTP": "http"
159
158
  };
160
159
  SUPPORTED_BROWSERS_FOR_AI = ["chrome", "microsoftedge", "firefox"];
160
+ SUPPORTED_BROWSERS_FOR_ACCESSIBILITY = ["chrome", "chromefortesting", "safari"];
161
+ MIN_BROWSER_VERSIONS_A11Y = {
162
+ chrome: 95,
163
+ chromefortesting: 141,
164
+ safari: 18.4
165
+ };
166
+ MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK = {
167
+ chrome: 100,
168
+ chromefortesting: 141,
169
+ safari: 18.4
170
+ };
161
171
  TCG_URL = "https://tcg.browserstack.com";
162
172
  TCG_INFO = {
163
173
  tcgRegion: "use",
@@ -182,6 +192,9 @@ var init_constants = __esm({
182
192
  MAX_GIT_META_DATA_SIZE_IN_BYTES = 64 * 1024;
183
193
  GIT_META_DATA_TRUNCATED = "...[TRUNCATED]";
184
194
  CLI_STOP_TIMEOUT = 5e3;
195
+ BINARY_BUSY_ERROR_CODES = ["ETXTBSY", "EBUSY"];
196
+ MAX_SPAWN_RETRIES = 3;
197
+ SPAWN_RETRY_DELAY_MS = 1e3;
185
198
  WDIO_NAMING_PREFIX = "WebdriverIO-";
186
199
  UPDATED_CLI_ENDPOINT = "sdk/v1/update_cli";
187
200
  }
@@ -266,34 +279,155 @@ var init_apiUtils = __esm({
266
279
  }
267
280
  });
268
281
 
282
+ // src/caCert.ts
283
+ import { setGlobalDispatcher, Agent } from "undici";
284
+ import tls from "node:tls";
285
+ import fs from "node:fs";
286
+ import os from "node:os";
287
+ import path from "node:path";
288
+ function derToPem(der) {
289
+ const b64 = der.toString("base64").replace(/(.{64})/g, "$1\n");
290
+ return `-----BEGIN CERTIFICATE-----
291
+ ${b64}${b64.endsWith("\n") ? "" : "\n"}-----END CERTIFICATE-----
292
+ `;
293
+ }
294
+ function loadCaCertsAsPem(buf) {
295
+ if (buf.includes("-----BEGIN CERTIFICATE-----")) {
296
+ return buf.toString("utf8").match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g) || [];
297
+ }
298
+ return [derToPem(buf)];
299
+ }
300
+ function resolveCaCertPath(options) {
301
+ let p = process.env.BROWSERSTACK_EXTRA_CA_CERTS;
302
+ if ((!p || !p.trim()) && options?.proxyCaCertificate) {
303
+ p = options.proxyCaCertificate;
304
+ }
305
+ if (!p || !String(p).trim()) {
306
+ return void 0;
307
+ }
308
+ p = String(p).trim();
309
+ try {
310
+ if (fs.existsSync(p) && fs.statSync(p).isFile()) {
311
+ return p;
312
+ }
313
+ BStackLogger.warn(`proxyCaCertificate: path does not exist or is not a file, falling back to system trust store: ${p}`);
314
+ } catch (e) {
315
+ BStackLogger.warn(`proxyCaCertificate: failed to stat cert path ${p}: ${e.message}`);
316
+ }
317
+ return void 0;
318
+ }
319
+ function getMergedCa() {
320
+ return mergedCa;
321
+ }
322
+ function configureCaCertificate(options) {
323
+ if (configured) {
324
+ return;
325
+ }
326
+ try {
327
+ const certPath = resolveCaCertPath(options);
328
+ if (!certPath) {
329
+ return;
330
+ }
331
+ const buf = fs.readFileSync(certPath);
332
+ const isPem = buf.includes("-----BEGIN CERTIFICATE-----");
333
+ const pemCerts = loadCaCertsAsPem(buf);
334
+ if (!pemCerts.length) {
335
+ BStackLogger.warn(`proxyCaCertificate: no certificate found in ${certPath}; falling back to system trust store.`);
336
+ return;
337
+ }
338
+ mergedCa = [...tls.rootCertificates, ...pemCerts];
339
+ setGlobalDispatcher(new Agent({ connect: { ca: mergedCa } }));
340
+ configured = true;
341
+ BStackLogger.info(`proxyCaCertificate: trusting custom CA from ${certPath} (merged with system roots).`);
342
+ try {
343
+ if (!process.env.NODE_EXTRA_CA_CERTS) {
344
+ let nodeExtra = certPath;
345
+ if (!isPem) {
346
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "browserstack_sdk_ca_"));
347
+ nodeExtra = path.join(tmpDir, "ca.pem");
348
+ const fd = fs.openSync(nodeExtra, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | (fs.constants.O_NOFOLLOW || 0), 384);
349
+ try {
350
+ fs.writeFileSync(fd, pemCerts.join(""));
351
+ } finally {
352
+ fs.closeSync(fd);
353
+ }
354
+ }
355
+ process.env.NODE_EXTRA_CA_CERTS = nodeExtra;
356
+ }
357
+ } catch (e) {
358
+ BStackLogger.warn(`proxyCaCertificate: CA is trusted for this process, but exporting NODE_EXTRA_CA_CERTS for detached child processes failed (children may not trust the custom CA): ${e.message}`);
359
+ }
360
+ } catch (e) {
361
+ BStackLogger.warn(`proxyCaCertificate: setup failed, falling back to system trust store: ${e.message}`);
362
+ }
363
+ }
364
+ var mergedCa, configured;
365
+ var init_caCert = __esm({
366
+ "src/caCert.ts"() {
367
+ "use strict";
368
+ init_bstackLogger();
369
+ configured = false;
370
+ }
371
+ });
372
+
269
373
  // src/fetchWrapper.ts
270
- import { fetch as undiciFetch, ProxyAgent } from "undici";
271
- async function fetchWrap(input, init) {
272
- const res = await _fetch(input, init);
374
+ import { fetch as undiciFetch, ProxyAgent, Agent as Agent2 } from "undici";
375
+ function getDispatcher(proxyUrl, connectTimeoutMs) {
376
+ const ca = getMergedCa();
377
+ const key = `${proxyUrl ?? "direct"}:${connectTimeoutMs ?? "default"}:${ca ? "ca" : "noca"}`;
378
+ let dispatcher = dispatcherCache.get(key);
379
+ if (!dispatcher) {
380
+ const connect = {};
381
+ if (connectTimeoutMs) {
382
+ connect.timeout = connectTimeoutMs;
383
+ }
384
+ if (proxyUrl) {
385
+ dispatcher = new ProxyAgent({ uri: proxyUrl, connect, ...ca ? { requestTls: { ca } } : {} });
386
+ } else {
387
+ if (ca) {
388
+ connect.ca = ca;
389
+ }
390
+ dispatcher = new Agent2({ connect });
391
+ }
392
+ dispatcherCache.set(key, dispatcher);
393
+ }
394
+ return dispatcher;
395
+ }
396
+ async function fetchWrap(input, init, options) {
397
+ const res = await _fetch(input, init, options);
273
398
  if (!res.ok) {
274
399
  throw new ResponseError(`Error response from server ${res.status}: ${await res.text()}`, res);
275
400
  }
276
401
  return res;
277
402
  }
278
- function _fetch(input, init) {
403
+ function _fetch(input, init, options) {
404
+ const connectTimeoutMs = options?.connectTimeoutMs;
279
405
  const proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY;
280
406
  if (proxyUrl) {
281
407
  const noProxy = process.env.NO_PROXY && process.env.NO_PROXY.trim() ? process.env.NO_PROXY.trim().split(/[\s,;]+/) : [];
282
408
  const request = new Request(input);
283
409
  const url3 = new URL(request.url);
284
410
  if (!noProxy.some((str) => url3.hostname.endsWith(str))) {
411
+ const dispatcher = getDispatcher(proxyUrl, connectTimeoutMs);
285
412
  return undiciFetch(
286
413
  request.url,
287
- { ...init, dispatcher: new ProxyAgent(proxyUrl) }
414
+ { ...init, dispatcher }
288
415
  );
289
416
  }
290
417
  }
418
+ if (connectTimeoutMs) {
419
+ return undiciFetch(
420
+ new Request(input).url,
421
+ { ...init, dispatcher: getDispatcher(void 0, connectTimeoutMs) }
422
+ );
423
+ }
291
424
  return fetch(input, init);
292
425
  }
293
- var ResponseError;
426
+ var ResponseError, dispatcherCache;
294
427
  var init_fetchWrapper = __esm({
295
428
  "src/fetchWrapper.ts"() {
296
429
  "use strict";
430
+ init_caCert();
297
431
  ResponseError = class extends Error {
298
432
  response;
299
433
  constructor(message, res) {
@@ -301,6 +435,7 @@ var init_fetchWrapper = __esm({
301
435
  this.response = res;
302
436
  }
303
437
  };
438
+ dispatcherCache = /* @__PURE__ */ new Map();
304
439
  }
305
440
  });
306
441
 
@@ -458,26 +593,26 @@ var init_constants2 = __esm({
458
593
  });
459
594
 
460
595
  // src/cli/cliLogger.ts
461
- import path from "node:path";
462
- import fs from "node:fs";
596
+ import path2 from "node:path";
597
+ import fs2 from "node:fs";
463
598
  import chalk from "chalk";
464
599
  import logger from "@wdio/logger";
465
- var log, BStackLogger;
600
+ var log, BStackLogger2;
466
601
  var init_cliLogger = __esm({
467
602
  "src/cli/cliLogger.ts"() {
468
603
  "use strict";
469
604
  init_constants();
470
605
  init_util();
471
606
  log = logger("@wdio/browserstack-service/cli");
472
- BStackLogger = class {
473
- static logFilePath = path.join(process.cwd(), LOGS_FILE);
474
- static logFolderPath = path.join(process.cwd(), "logs");
607
+ BStackLogger2 = class {
608
+ static logFilePath = path2.join(process.cwd(), LOGS_FILE);
609
+ static logFolderPath = path2.join(process.cwd(), "logs");
475
610
  static logFileStream;
476
611
  static logToFile(logMessage, logLevel) {
477
612
  try {
478
613
  if (!this.logFileStream) {
479
614
  this.ensureLogsFolder();
480
- this.logFileStream = fs.createWriteStream(this.logFilePath, { flags: "a" });
615
+ this.logFileStream = fs2.createWriteStream(this.logFilePath, { flags: "a" });
481
616
  }
482
617
  if (this.logFileStream && this.logFileStream.writable) {
483
618
  this.logFileStream.write(this.formatLog(logMessage, logLevel));
@@ -521,13 +656,13 @@ var init_cliLogger = __esm({
521
656
  this.logFileStream = null;
522
657
  }
523
658
  static clearLogFile() {
524
- if (fs.existsSync(this.logFilePath)) {
525
- fs.truncateSync(this.logFilePath);
659
+ if (fs2.existsSync(this.logFilePath)) {
660
+ fs2.truncateSync(this.logFilePath);
526
661
  }
527
662
  }
528
663
  static ensureLogsFolder() {
529
- if (!fs.existsSync(this.logFolderPath)) {
530
- fs.mkdirSync(this.logFolderPath);
664
+ if (!fs2.existsSync(this.logFolderPath)) {
665
+ fs2.mkdirSync(this.logFolderPath);
531
666
  }
532
667
  }
533
668
  };
@@ -585,16 +720,16 @@ var init_testFrameworkConstants = __esm({
585
720
  });
586
721
 
587
722
  // src/cli/cliUtils.ts
588
- import fs2 from "node:fs";
723
+ import fs3 from "node:fs";
589
724
  import fsp from "node:fs/promises";
590
725
  import { platform, arch, homedir } from "node:os";
591
- import path2 from "node:path";
726
+ import path3 from "node:path";
592
727
  import util, { promisify } from "node:util";
593
728
  import { exec } from "node:child_process";
594
729
  import { Readable } from "node:stream";
595
730
  import yauzl from "yauzl";
596
731
  import { threadId } from "node:worker_threads";
597
- var CLI_LOCK_TIMEOUT_MS, CLI_LOCK_POLL_MS, CLI_DOWNLOAD_TIMEOUT_MS, CLI_DOWNLOAD_TMP_PREFIX, CLI_DOWNLOAD_TMP_SUFFIX, CLIUtils;
732
+ var CLI_LOCK_TIMEOUT_MS, CLI_LOCK_POLL_MS, CLI_DOWNLOAD_TIMEOUT_MS, CLI_DOWNLOAD_TMP_PREFIX, CLI_DOWNLOAD_TMP_SUFFIX, CLI_CONNECT_TIMEOUT_MS, CLI_FETCH_MAX_ATTEMPTS, CLI_FETCH_RETRY_BASE_DELAY_MS, CLIUtils;
598
733
  var init_cliUtils = __esm({
599
734
  "src/cli/cliUtils.ts"() {
600
735
  "use strict";
@@ -611,6 +746,9 @@ var init_cliUtils = __esm({
611
746
  CLI_DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1e3;
612
747
  CLI_DOWNLOAD_TMP_PREFIX = "downloaded_file_";
613
748
  CLI_DOWNLOAD_TMP_SUFFIX = ".zip";
749
+ CLI_CONNECT_TIMEOUT_MS = Number(process.env.BROWSERSTACK_CLI_CONNECT_TIMEOUT_MS) || 60 * 1e3;
750
+ CLI_FETCH_MAX_ATTEMPTS = 3;
751
+ CLI_FETCH_RETRY_BASE_DELAY_MS = 500;
614
752
  CLIUtils = class _CLIUtils {
615
753
  static automationFrameworkDetail = {};
616
754
  static testFrameworkDetail = {};
@@ -635,6 +773,7 @@ var init_cliUtils = __esm({
635
773
  modifiedOpts.browserStackLocalOptions = modifiedOpts.opts;
636
774
  delete modifiedOpts.opts;
637
775
  }
776
+ delete modifiedOpts.testManagementOptions;
638
777
  modifiedOpts.testContextOptions = {
639
778
  skipSessionName: isFalse(modifiedOpts.setSessionName),
640
779
  skipSessionStatus: isFalse(modifiedOpts.setSessionStatus),
@@ -653,6 +792,8 @@ var init_cliUtils = __esm({
653
792
  options.testObservability
654
793
  );
655
794
  const observabilityOptions = options.testObservabilityOptions || {};
795
+ const testManagementOptions = options.testManagementOptions || {};
796
+ const testPlanId = typeof testManagementOptions.testPlanId === "string" ? testManagementOptions.testPlanId.trim() : "";
656
797
  const binconfig = {
657
798
  userName: observabilityOptions.user || config.user,
658
799
  accessKey: observabilityOptions.key || config.key,
@@ -664,26 +805,26 @@ var init_cliUtils = __esm({
664
805
  binconfig.buildName = observabilityOptions.buildName || binconfig.buildName;
665
806
  binconfig.projectName = observabilityOptions.projectName || binconfig.projectName;
666
807
  binconfig.buildTag = this.getObservabilityBuildTags(observabilityOptions, buildTag) || [];
667
- let caps = capabilities;
668
- if (capabilities && !Array.isArray(capabilities)) {
669
- caps = [capabilities];
670
- }
671
- if (Array.isArray(caps)) {
672
- for (const cap of caps) {
673
- const platform4 = {};
674
- const capability = cap;
675
- Object.keys(capability).filter((key) => key !== "bstack:options").forEach((key) => {
676
- platform4[key] = capability[key];
808
+ if (testPlanId.length > 0) {
809
+ binconfig.testManagementOptions = {
810
+ testPlanId
811
+ };
812
+ }
813
+ const caps = Array.isArray(capabilities) ? capabilities : [capabilities];
814
+ for (const cap of caps) {
815
+ const platform4 = {};
816
+ const capability = cap;
817
+ Object.keys(capability).filter((key) => key !== "bstack:options").forEach((key) => {
818
+ platform4[key] = capability[key];
819
+ });
820
+ if (capability["bstack:options"]) {
821
+ Object.keys(
822
+ capability["bstack:options"]
823
+ ).forEach((key) => {
824
+ platform4[key] = capability["bstack:options"][key];
677
825
  });
678
- if (capability["bstack:options"]) {
679
- Object.keys(
680
- capability["bstack:options"]
681
- ).forEach((key) => {
682
- platform4[key] = capability["bstack:options"][key];
683
- });
684
- }
685
- binconfig.platforms.push(platform4);
686
826
  }
827
+ binconfig.platforms.push(platform4);
687
828
  }
688
829
  return JSON.stringify(binconfig);
689
830
  }
@@ -694,10 +835,10 @@ var init_cliUtils = __esm({
694
835
  return "ECMAScript";
695
836
  }
696
837
  static async setupCliPath(config) {
697
- BStackLogger.debug("Configuring Cli path.");
838
+ BStackLogger2.debug("Configuring Cli path.");
698
839
  const developmentBinaryPath = process.env.SDK_CLI_BIN_PATH || null;
699
840
  if (!isNullOrEmpty(developmentBinaryPath)) {
700
- BStackLogger.debug(`Development Cli Path: ${developmentBinaryPath}`);
841
+ BStackLogger2.debug(`Development Cli Path: ${developmentBinaryPath}`);
701
842
  return developmentBinaryPath;
702
843
  }
703
844
  try {
@@ -711,10 +852,10 @@ var init_cliUtils = __esm({
711
852
  cliDir,
712
853
  config
713
854
  );
714
- BStackLogger.debug(`Resolved binary path: ${finalBinaryPath}`);
855
+ BStackLogger2.debug(`Resolved binary path: ${finalBinaryPath}`);
715
856
  return finalBinaryPath;
716
857
  } catch (err) {
717
- BStackLogger.debug(
858
+ BStackLogger2.warn(
718
859
  `Error in setting up cli path directory, Exception: ${util.format(err)}`
719
860
  );
720
861
  }
@@ -722,18 +863,18 @@ var init_cliUtils = __esm({
722
863
  }
723
864
  static async checkAndUpdateCli(existingCliPath, cliDir, config) {
724
865
  if (process.env.BROWSERSTACK_TESTHUB_JWT) {
725
- BStackLogger.debug(
866
+ BStackLogger2.debug(
726
867
  `Worker process detected, skipping CLI update. Using existing: ${existingCliPath}`
727
868
  );
728
- if (existingCliPath && fs2.existsSync(existingCliPath)) {
869
+ if (existingCliPath && fs3.existsSync(existingCliPath)) {
729
870
  return existingCliPath;
730
871
  }
731
- BStackLogger.warn(
872
+ BStackLogger2.warn(
732
873
  "Worker process has no existing CLI binary, attempting download as fallback."
733
874
  );
734
875
  }
735
876
  PerformanceTester.start(EVENTS.SDK_CLI_CHECK_UPDATE);
736
- BStackLogger.info(`Current CLI Path Found: ${existingCliPath}`);
877
+ BStackLogger2.info(`Current CLI Path Found: ${existingCliPath}`);
737
878
  const queryParams = {
738
879
  sdk_version: _CLIUtils.getSdkVersion(),
739
880
  os: platform(),
@@ -742,18 +883,29 @@ var init_cliUtils = __esm({
742
883
  sdk_language: this.getSdkLanguage()
743
884
  };
744
885
  if (!isNullOrEmpty(existingCliPath)) {
745
- queryParams.cli_version = await this.runShellCommand(
886
+ if (this.isBinaryBusy(existingCliPath)) {
887
+ BStackLogger2.warn(`Existing binary is currently in use, skipping update: ${existingCliPath}`);
888
+ PerformanceTester.end(EVENTS.SDK_CLI_CHECK_UPDATE);
889
+ return existingCliPath;
890
+ }
891
+ const version3 = await this.runShellCommand(
746
892
  `${existingCliPath} version`
747
893
  );
894
+ if (version3.toLowerCase().includes("text file busy")) {
895
+ BStackLogger2.warn(`Binary busy during version check, skipping update: ${existingCliPath}`);
896
+ PerformanceTester.end(EVENTS.SDK_CLI_CHECK_UPDATE);
897
+ return existingCliPath;
898
+ }
899
+ queryParams.cli_version = version3;
748
900
  }
749
901
  const response = await this.requestToUpdateCLI(queryParams, config);
750
902
  if (nestedKeyValue(response, ["updated_cli_version"])) {
751
- BStackLogger.debug(
903
+ BStackLogger2.debug(
752
904
  `Need to update binary, current binary version: ${queryParams.cli_version}`
753
905
  );
754
906
  const browserStackBinaryUrl = process.env.BROWSERSTACK_BINARY_URL || null;
755
907
  if (!isNullOrEmpty(browserStackBinaryUrl)) {
756
- BStackLogger.debug(
908
+ BStackLogger2.debug(
757
909
  `Using BROWSERSTACK_BINARY_URL: ${browserStackBinaryUrl}`
758
910
  );
759
911
  response.url = browserStackBinaryUrl;
@@ -774,13 +926,13 @@ var init_cliUtils = __esm({
774
926
  if (isNullOrEmpty(writableDir)) {
775
927
  throw new Error("No writable directory available for the CLI");
776
928
  }
777
- const cliDirPath = path2.join(writableDir, "cli");
778
- if (!fs2.existsSync(cliDirPath)) {
929
+ const cliDirPath = path3.join(writableDir, "cli");
930
+ if (!fs3.existsSync(cliDirPath)) {
779
931
  createDir(cliDirPath);
780
932
  }
781
933
  return cliDirPath;
782
934
  } catch (err) {
783
- BStackLogger.error(
935
+ BStackLogger2.error(
784
936
  `Error in getting writable directory, writableDir=${util.format(err)}`
785
937
  );
786
938
  return "";
@@ -789,39 +941,39 @@ var init_cliUtils = __esm({
789
941
  static getWritableDir() {
790
942
  const writableDirOptions = [
791
943
  process.env.BROWSERSTACK_FILES_DIR,
792
- path2.join(homedir(), ".browserstack"),
793
- path2.join("tmp", ".browserstack")
944
+ path3.join(homedir(), ".browserstack"),
945
+ path3.join("tmp", ".browserstack")
794
946
  ];
795
- for (const path21 of writableDirOptions) {
796
- if (isNullOrEmpty(path21)) {
947
+ for (const path22 of writableDirOptions) {
948
+ if (isNullOrEmpty(path22)) {
797
949
  continue;
798
950
  }
799
951
  try {
800
- if (fs2.existsSync(path21)) {
801
- BStackLogger.debug(`File ${path21} already exist`);
802
- if (!isWritable(path21)) {
803
- BStackLogger.debug(`Giving write permission to ${path21}`);
804
- const success = setReadWriteAccess(path21);
952
+ if (fs3.existsSync(path22)) {
953
+ BStackLogger2.debug(`File ${path22} already exist`);
954
+ if (!isWritable(path22)) {
955
+ BStackLogger2.debug(`Giving write permission to ${path22}`);
956
+ const success = setReadWriteAccess(path22);
805
957
  if (!isTrue(success)) {
806
- BStackLogger.warn(
807
- `Unable to provide write permission to ${path21}`
958
+ BStackLogger2.warn(
959
+ `Unable to provide write permission to ${path22}`
808
960
  );
809
961
  }
810
962
  }
811
963
  } else {
812
- BStackLogger.debug(`File does not exist: ${path21}`);
813
- createDir(path21);
814
- BStackLogger.debug(`Giving write permission to ${path21}`);
815
- const success = setReadWriteAccess(path21);
964
+ BStackLogger2.debug(`File does not exist: ${path22}`);
965
+ createDir(path22);
966
+ BStackLogger2.debug(`Giving write permission to ${path22}`);
967
+ const success = setReadWriteAccess(path22);
816
968
  if (!isTrue(success)) {
817
- BStackLogger.warn(
818
- `Unable to provide write permission to ${path21}`
969
+ BStackLogger2.warn(
970
+ `Unable to provide write permission to ${path22}`
819
971
  );
820
972
  }
821
973
  }
822
- return path21;
974
+ return path22;
823
975
  } catch (err) {
824
- BStackLogger.error(
976
+ BStackLogger2.error(
825
977
  `Unable to get writable directory, exception ${util.format(err)}`
826
978
  );
827
979
  }
@@ -830,16 +982,16 @@ var init_cliUtils = __esm({
830
982
  }
831
983
  static getExistingCliPath(cliDir) {
832
984
  try {
833
- if (!fs2.existsSync(cliDir) || !fs2.statSync(cliDir).isDirectory()) {
985
+ if (!fs3.existsSync(cliDir) || !fs3.statSync(cliDir).isDirectory()) {
834
986
  return "";
835
987
  }
836
- const allBinaries = fs2.readdirSync(cliDir).map((file) => path2.join(cliDir, file)).filter(
837
- (filePath) => fs2.statSync(filePath).isFile() && path2.basename(filePath).startsWith("binary-")
988
+ const allBinaries = fs3.readdirSync(cliDir).map((file) => path3.join(cliDir, file)).filter(
989
+ (filePath) => fs3.statSync(filePath).isFile() && path3.basename(filePath).startsWith("binary-")
838
990
  );
839
991
  if (allBinaries.length > 0) {
840
992
  const latestBinary = allBinaries.map((filePath) => ({
841
993
  filePath,
842
- mtime: fs2.statSync(filePath).mtime
994
+ mtime: fs3.statSync(filePath).mtime
843
995
  })).reduce(
844
996
  (latest, current) => {
845
997
  if (!latest || !latest.mtime) {
@@ -856,10 +1008,62 @@ var init_cliUtils = __esm({
856
1008
  }
857
1009
  return "";
858
1010
  } catch (err) {
859
- BStackLogger.error(`Error while reading CLI path: ${util.format(err)}`);
1011
+ BStackLogger2.error(`Error while reading CLI path: ${util.format(err)}`);
860
1012
  return "";
861
1013
  }
862
1014
  }
1015
+ static isBinaryBusy(binaryPath) {
1016
+ if (isNullOrEmpty(binaryPath)) {
1017
+ return false;
1018
+ }
1019
+ if (platform() === "darwin") {
1020
+ return false;
1021
+ }
1022
+ if (!fs3.existsSync(binaryPath)) {
1023
+ return false;
1024
+ }
1025
+ try {
1026
+ const fd = fs3.openSync(binaryPath, "r+");
1027
+ fs3.closeSync(fd);
1028
+ return false;
1029
+ } catch (err) {
1030
+ if (BINARY_BUSY_ERROR_CODES.includes(err.code)) {
1031
+ BStackLogger2.debug(`Binary is busy: ${binaryPath}`);
1032
+ return true;
1033
+ }
1034
+ BStackLogger2.debug(`Error checking if binary is busy: ${err.message}`);
1035
+ return false;
1036
+ }
1037
+ }
1038
+ /**
1039
+ * fetch wrapper for CLI network calls that (a) raises undici's connect timeout
1040
+ * above the non-overridable 10s default of global fetch and (b) retries a few
1041
+ * times with linear backoff on transient connection failures. Both are needed
1042
+ * for reliability in constrained CI/containerised networks (SDK-6152).
1043
+ */
1044
+ static fetchWithRetry = async (input, init, label) => {
1045
+ let lastError;
1046
+ for (let attempt = 1; attempt <= CLI_FETCH_MAX_ATTEMPTS; attempt++) {
1047
+ try {
1048
+ return await _fetch(input, init, { connectTimeoutMs: CLI_CONNECT_TIMEOUT_MS });
1049
+ } catch (err) {
1050
+ lastError = err;
1051
+ const reason = (
1052
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1053
+ err?.cause?.code || err?.code || err?.message
1054
+ );
1055
+ BStackLogger2.warn(
1056
+ `${label} attempt ${attempt}/${CLI_FETCH_MAX_ATTEMPTS} failed: ${reason}`
1057
+ );
1058
+ if (attempt < CLI_FETCH_MAX_ATTEMPTS) {
1059
+ await new Promise(
1060
+ (resolve) => setTimeout(resolve, CLI_FETCH_RETRY_BASE_DELAY_MS * attempt)
1061
+ );
1062
+ }
1063
+ }
1064
+ }
1065
+ throw lastError;
1066
+ };
863
1067
  static requestToUpdateCLI = async (queryParams, config) => {
864
1068
  const params = new URLSearchParams(queryParams);
865
1069
  const requestInit = {
@@ -868,12 +1072,13 @@ var init_cliUtils = __esm({
868
1072
  Authorization: `Basic ${Buffer.from(`${getBrowserStackUser(config)}:${getBrowserStackKey(config)}`).toString("base64")}`
869
1073
  }
870
1074
  };
871
- const response = await _fetch(
1075
+ const response = await this.fetchWithRetry(
872
1076
  `${APIUtils.BROWSERSTACK_AUTOMATE_API_URL}/${UPDATED_CLI_ENDPOINT}?${params.toString()}`,
873
- requestInit
1077
+ requestInit,
1078
+ "update_cli request"
874
1079
  );
875
1080
  const jsonResponse = await response.json();
876
- BStackLogger.debug(`response ${JSON.stringify(jsonResponse)}`);
1081
+ BStackLogger2.debug(`response ${JSON.stringify(jsonResponse)}`);
877
1082
  return jsonResponse;
878
1083
  };
879
1084
  static runShellCommand(cmdCommand, workingDir = "") {
@@ -895,11 +1100,11 @@ var init_cliUtils = __esm({
895
1100
  });
896
1101
  }
897
1102
  static downloadLatestBinary = async (binDownloadUrl, cliDir) => {
898
- const lockPath = path2.join(cliDir, "download.lock");
1103
+ const lockPath = path3.join(cliDir, "download.lock");
899
1104
  const sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
900
1105
  const parseLockFile = () => {
901
1106
  try {
902
- const content = fs2.readFileSync(lockPath, "utf8").trim();
1107
+ const content = fs3.readFileSync(lockPath, "utf8").trim();
903
1108
  const [pidLine, timestampLine] = content.split("\n");
904
1109
  const pid = Number.parseInt(pidLine, 10);
905
1110
  const timestamp = Number.parseInt(timestampLine, 10);
@@ -923,20 +1128,20 @@ var init_cliUtils = __esm({
923
1128
  const start = Date.now();
924
1129
  while (true) {
925
1130
  try {
926
- const fd = fs2.openSync(lockPath, "wx");
1131
+ const fd = fs3.openSync(lockPath, "wx");
927
1132
  try {
928
- fs2.writeFileSync(fd, `${process.pid}
1133
+ fs3.writeFileSync(fd, `${process.pid}
929
1134
  ${Date.now()}
930
1135
  `);
931
1136
  } catch {
932
1137
  }
933
1138
  return () => {
934
1139
  try {
935
- fs2.closeSync(fd);
1140
+ fs3.closeSync(fd);
936
1141
  } catch {
937
1142
  }
938
1143
  try {
939
- fs2.unlinkSync(lockPath);
1144
+ fs3.unlinkSync(lockPath);
940
1145
  } catch {
941
1146
  }
942
1147
  };
@@ -948,19 +1153,19 @@ ${Date.now()}
948
1153
  const lockAge = Date.now() - lockMeta.timestamp;
949
1154
  const running = isProcessRunning(lockMeta.pid);
950
1155
  if (!running || lockAge > timeoutMs) {
951
- BStackLogger.warn(
1156
+ BStackLogger2.warn(
952
1157
  `Stale CLI download lock detected (pid=${lockMeta.pid}, age=${lockAge}ms). Removing lock.`
953
1158
  );
954
1159
  try {
955
- fs2.unlinkSync(lockPath);
1160
+ fs3.unlinkSync(lockPath);
956
1161
  } catch {
957
1162
  }
958
1163
  continue;
959
1164
  }
960
1165
  }
961
1166
  const existingBinary = _CLIUtils.getExistingCliPath(cliDir);
962
- if (existingBinary && fs2.existsSync(existingBinary) && fs2.statSync(existingBinary).size > 0) {
963
- BStackLogger.debug(
1167
+ if (existingBinary && fs3.existsSync(existingBinary) && fs3.statSync(existingBinary).size > 0) {
1168
+ BStackLogger2.debug(
964
1169
  `Binary appeared while waiting for lock: ${existingBinary}`
965
1170
  );
966
1171
  return { alreadyExists: existingBinary };
@@ -980,14 +1185,17 @@ ${Date.now()}
980
1185
  const cleanupTemporaryDownloads = (maxAgeMs = CLI_LOCK_TIMEOUT_MS) => {
981
1186
  try {
982
1187
  const now2 = Date.now();
983
- for (const entry of fs2.readdirSync(cliDir)) {
984
- if (!entry.startsWith(CLI_DOWNLOAD_TMP_PREFIX) || !entry.endsWith(CLI_DOWNLOAD_TMP_SUFFIX)) {
1188
+ const tmpExtractRe = /\.tmp\.\d+$/;
1189
+ for (const entry of fs3.readdirSync(cliDir)) {
1190
+ const isDownloadZip = entry.startsWith(CLI_DOWNLOAD_TMP_PREFIX) && entry.endsWith(CLI_DOWNLOAD_TMP_SUFFIX);
1191
+ const isExtractTmp = tmpExtractRe.test(entry);
1192
+ if (!isDownloadZip && !isExtractTmp) {
985
1193
  continue;
986
1194
  }
987
- const filePath = path2.join(cliDir, entry);
1195
+ const filePath = path3.join(cliDir, entry);
988
1196
  let stats;
989
1197
  try {
990
- stats = fs2.statSync(filePath);
1198
+ stats = fs3.statSync(filePath);
991
1199
  } catch {
992
1200
  continue;
993
1201
  }
@@ -995,21 +1203,21 @@ ${Date.now()}
995
1203
  continue;
996
1204
  }
997
1205
  try {
998
- fs2.unlinkSync(filePath);
1206
+ fs3.unlinkSync(filePath);
999
1207
  } catch (err) {
1000
- BStackLogger.debug(
1001
- `Failed to delete temp CLI zip file ${filePath}: ${util.format(err)}`
1208
+ BStackLogger2.debug(
1209
+ `Failed to delete temp CLI file ${filePath}: ${util.format(err)}`
1002
1210
  );
1003
1211
  }
1004
1212
  }
1005
1213
  } catch (err) {
1006
- BStackLogger.debug(
1007
- `Failed to scan temp CLI downloads in ${cliDir}: ${util.format(err)}`
1214
+ BStackLogger2.debug(
1215
+ `Failed to scan temp CLI files in ${cliDir}: ${util.format(err)}`
1008
1216
  );
1009
1217
  }
1010
1218
  };
1011
1219
  PerformanceTester.start(EVENTS.SDK_CLI_DOWNLOAD);
1012
- BStackLogger.debug(`Downloading SDK binary from: ${binDownloadUrl}`);
1220
+ BStackLogger2.debug(`Downloading SDK binary from: ${binDownloadUrl}`);
1013
1221
  let downloadEnded = false;
1014
1222
  const endDownload = (success = true, errMsg) => {
1015
1223
  if (downloadEnded) {
@@ -1035,8 +1243,8 @@ ${Date.now()}
1035
1243
  }
1036
1244
  releaseLock = lockResult;
1037
1245
  const existingBinary = _CLIUtils.getExistingCliPath(cliDir);
1038
- if (existingBinary && fs2.existsSync(existingBinary) && fs2.statSync(existingBinary).size > 0) {
1039
- BStackLogger.debug(
1246
+ if (existingBinary && fs3.existsSync(existingBinary) && fs3.statSync(existingBinary).size > 0) {
1247
+ BStackLogger2.debug(
1040
1248
  `Binary already exists after acquiring lock: ${existingBinary}`
1041
1249
  );
1042
1250
  endDownload();
@@ -1044,13 +1252,12 @@ ${Date.now()}
1044
1252
  return existingBinary;
1045
1253
  }
1046
1254
  cleanupTemporaryDownloads();
1047
- const zipFilePath = path2.join(
1255
+ const zipFilePath = path3.join(
1048
1256
  cliDir,
1049
1257
  `${CLI_DOWNLOAD_TMP_PREFIX}${process.pid}_${Date.now()}${CLI_DOWNLOAD_TMP_SUFFIX}`
1050
1258
  );
1051
- const downloadedFileStream = fs2.createWriteStream(zipFilePath);
1259
+ const downloadedFileStream = fs3.createWriteStream(zipFilePath);
1052
1260
  return new Promise((resolve, reject) => {
1053
- const binaryName = null;
1054
1261
  const processDownload = async () => {
1055
1262
  const abortController = new AbortController();
1056
1263
  const timeout = setTimeout(
@@ -1059,9 +1266,11 @@ ${Date.now()}
1059
1266
  );
1060
1267
  let response;
1061
1268
  try {
1062
- response = await _fetch(binDownloadUrl, {
1063
- signal: abortController.signal
1064
- });
1269
+ response = await _fetch(
1270
+ binDownloadUrl,
1271
+ { signal: abortController.signal },
1272
+ { connectTimeoutMs: CLI_CONNECT_TIMEOUT_MS }
1273
+ );
1065
1274
  } finally {
1066
1275
  clearTimeout(timeout);
1067
1276
  }
@@ -1069,7 +1278,7 @@ ${Date.now()}
1069
1278
  throw new Error("No response body received");
1070
1279
  }
1071
1280
  downloadedFileStream.on("error", function(err) {
1072
- BStackLogger.error(
1281
+ BStackLogger2.error(
1073
1282
  `Got Error while downloading cli binary file: ${err}`
1074
1283
  );
1075
1284
  endDownload(false, util.format(err));
@@ -1084,7 +1293,6 @@ ${Date.now()}
1084
1293
  nodeStream.pipe(downloadedFileStream);
1085
1294
  _CLIUtils.downloadFileStream(
1086
1295
  downloadedFileStream,
1087
- binaryName,
1088
1296
  zipFilePath,
1089
1297
  cliDir,
1090
1298
  (result) => {
@@ -1099,7 +1307,7 @@ ${Date.now()}
1099
1307
  }
1100
1308
  );
1101
1309
  } catch (err) {
1102
- BStackLogger.error(
1310
+ BStackLogger2.error(
1103
1311
  `Got Error in cli binary downloading request ${util.format(err)}`
1104
1312
  );
1105
1313
  endDownload(false, util.format(err));
@@ -1112,46 +1320,110 @@ ${Date.now()}
1112
1320
  } catch (err) {
1113
1321
  releaseLock?.();
1114
1322
  endDownload(false, util.format(err));
1115
- BStackLogger.debug(
1323
+ BStackLogger2.debug(
1116
1324
  `Failed to download binary, Exception: ${util.format(err)}`
1117
1325
  );
1118
1326
  return null;
1119
1327
  }
1120
1328
  };
1121
- static downloadFileStream(downloadedFileStream, binaryName, zipFilePath, cliDir, resolve, reject) {
1329
+ static downloadFileStream(downloadedFileStream, zipFilePath, cliDir, resolve, reject) {
1122
1330
  downloadedFileStream.on("close", async function() {
1123
1331
  const yauzlOpenPromise = promisify(yauzl.open);
1124
1332
  try {
1125
1333
  const zipfile = await yauzlOpenPromise(zipFilePath, {
1126
1334
  lazyEntries: true
1127
1335
  });
1336
+ let resolvedBinaryPath = null;
1128
1337
  zipfile.readEntry();
1129
1338
  zipfile.on("entry", async (entry) => {
1130
- if (!binaryName) {
1131
- binaryName = entry.fileName;
1132
- }
1133
1339
  if (/\/$/.test(entry.fileName)) {
1134
1340
  zipfile.readEntry();
1135
- } else {
1136
- const writeStream = fs2.createWriteStream(
1137
- path2.join(cliDir, entry.fileName)
1138
- );
1139
- const openReadStreamPromise = promisify(
1341
+ return;
1342
+ }
1343
+ const candidatePath = path3.join(cliDir, entry.fileName);
1344
+ const resolvedCandidate = path3.resolve(candidatePath);
1345
+ const resolvedDir = path3.resolve(cliDir) + path3.sep;
1346
+ if (!resolvedCandidate.startsWith(resolvedDir)) {
1347
+ zipfile.close();
1348
+ reject(new Error(`Zip-slip detected: entry "${entry.fileName}" resolves outside ${cliDir}`));
1349
+ return;
1350
+ }
1351
+ const isBinaryEntry = path3.basename(entry.fileName).startsWith("binary-");
1352
+ if (!isBinaryEntry) {
1353
+ const directStream = fs3.createWriteStream(candidatePath);
1354
+ directStream.on("error", (writeErr) => {
1355
+ zipfile.close();
1356
+ reject(writeErr);
1357
+ });
1358
+ const openReadStreamPromise2 = promisify(
1140
1359
  zipfile.openReadStream
1141
1360
  ).bind(zipfile);
1142
1361
  try {
1143
- const readStream = await openReadStreamPromise(entry);
1362
+ const readStream = await openReadStreamPromise2(entry);
1144
1363
  readStream.on("end", function() {
1145
- writeStream.close();
1146
- zipfile.readEntry();
1364
+ directStream.end();
1365
+ directStream.on("close", () => zipfile.readEntry());
1147
1366
  });
1148
- readStream.pipe(writeStream);
1367
+ readStream.pipe(directStream);
1149
1368
  } catch (zipErr) {
1369
+ zipfile.close();
1150
1370
  reject(zipErr);
1151
1371
  }
1152
- if (entry.fileName === binaryName) {
1372
+ return;
1373
+ }
1374
+ const finalPath = candidatePath;
1375
+ const tempPath = path3.join(cliDir, `${entry.fileName}.tmp.${process.pid}`);
1376
+ const writeStream = fs3.createWriteStream(tempPath);
1377
+ let writeStreamErrored = false;
1378
+ writeStream.on("error", (writeErr) => {
1379
+ writeStreamErrored = true;
1380
+ fsp.unlink(tempPath).catch(() => {
1381
+ });
1382
+ zipfile.close();
1383
+ reject(writeErr);
1384
+ });
1385
+ writeStream.on("close", async () => {
1386
+ if (writeStreamErrored) {
1387
+ return;
1388
+ }
1389
+ try {
1390
+ await fsp.chmod(tempPath, "0755");
1391
+ try {
1392
+ await fsp.rename(tempPath, finalPath);
1393
+ } catch (renameErr) {
1394
+ if (renameErr.code !== "EXDEV") {
1395
+ throw renameErr;
1396
+ }
1397
+ BStackLogger2.warn(`Atomic rename failed (cross-device), falling back to copy: ${renameErr.message}`);
1398
+ await fsp.copyFile(tempPath, finalPath);
1399
+ await fsp.unlink(tempPath).catch(() => {
1400
+ });
1401
+ }
1402
+ if (!resolvedBinaryPath) {
1403
+ resolvedBinaryPath = finalPath;
1404
+ }
1405
+ zipfile.readEntry();
1406
+ } catch (err) {
1407
+ await fsp.unlink(tempPath).catch(() => {
1408
+ });
1153
1409
  zipfile.close();
1410
+ reject(err);
1154
1411
  }
1412
+ });
1413
+ const openReadStreamPromise = promisify(
1414
+ zipfile.openReadStream
1415
+ ).bind(zipfile);
1416
+ try {
1417
+ const readStream = await openReadStreamPromise(entry);
1418
+ readStream.on("end", function() {
1419
+ writeStream.end();
1420
+ });
1421
+ readStream.pipe(writeStream);
1422
+ } catch (zipErr) {
1423
+ fsp.unlink(tempPath).catch(() => {
1424
+ });
1425
+ zipfile.close();
1426
+ reject(zipErr);
1155
1427
  }
1156
1428
  });
1157
1429
  zipfile.on("error", (zipErr) => {
@@ -1159,16 +1431,15 @@ ${Date.now()}
1159
1431
  });
1160
1432
  zipfile.once("end", () => {
1161
1433
  fsp.unlink(zipFilePath).catch(() => {
1162
- BStackLogger.warn(
1163
- `Failed to delete zip file: ${zipFilePath}`
1164
- );
1165
- });
1166
- fsp.chmod(`${cliDir}/${binaryName}`, "0755").then(() => {
1167
- resolve(`${cliDir}/${binaryName}`);
1168
- }).catch((err) => {
1169
- reject(err);
1434
+ BStackLogger2.warn(`Failed to delete zip file: ${zipFilePath}`);
1170
1435
  });
1436
+ if (!resolvedBinaryPath) {
1437
+ zipfile.close();
1438
+ reject(new Error("No binary-* entry found in zip; cannot complete CLI binary extraction"));
1439
+ return;
1440
+ }
1171
1441
  zipfile.close();
1442
+ resolve(resolvedBinaryPath);
1172
1443
  });
1173
1444
  } catch (err) {
1174
1445
  reject(err);
@@ -1191,7 +1462,7 @@ ${Date.now()}
1191
1462
  }
1192
1463
  static setFrameworkDetail(testFramework, automationFramework) {
1193
1464
  if (!testFramework || !automationFramework) {
1194
- BStackLogger.debug(
1465
+ BStackLogger2.debug(
1195
1466
  `Test or Automation framework not provided testFramework=${testFramework}, automationFramework=${automationFramework}`
1196
1467
  );
1197
1468
  }
@@ -1273,12 +1544,12 @@ ${Date.now()}
1273
1544
 
1274
1545
  // src/instrumentation/performance/performance-tester.ts
1275
1546
  import { createObjectCsvWriter } from "csv-writer";
1276
- import fs3 from "node:fs";
1547
+ import fs4 from "node:fs";
1277
1548
  import fsPromise from "node:fs/promises";
1278
1549
  import { performance, PerformanceObserver } from "node:perf_hooks";
1279
1550
  import util2 from "node:util";
1280
1551
  import worker from "node:worker_threads";
1281
- import path3 from "node:path";
1552
+ import path4 from "node:path";
1282
1553
  import { arch as arch2, hostname, platform as platform2, type, version } from "node:os";
1283
1554
  var PerformanceTester;
1284
1555
  var init_performance_tester = __esm({
@@ -1303,11 +1574,11 @@ var init_performance_tester = __esm({
1303
1574
  static browser;
1304
1575
  static scenarioThatRan;
1305
1576
  static jsonReportDirName = "performance-report";
1306
- static jsonReportDirPath = path3.join(process.cwd(), "logs", this.jsonReportDirName);
1577
+ static jsonReportDirPath = path4.join(process.cwd(), "logs", this.jsonReportDirName);
1307
1578
  static jsonReportFileName = `${this.jsonReportDirPath}/performance-report-${_PerformanceTester.getProcessId()}.json`;
1308
1579
  static startMonitoring(csvName = "performance-report.csv") {
1309
- if (!fs3.existsSync(this.jsonReportDirPath)) {
1310
- fs3.mkdirSync(this.jsonReportDirPath, { recursive: true });
1580
+ if (!fs4.existsSync(this.jsonReportDirPath)) {
1581
+ fs4.mkdirSync(this.jsonReportDirPath, { recursive: true });
1311
1582
  }
1312
1583
  this._observer = new PerformanceObserver((list) => {
1313
1584
  list.getEntries().filter((entry) => entry.entryType === "measure").forEach(
@@ -1317,10 +1588,10 @@ var init_performance_tester = __esm({
1317
1588
  if (typeof finalEntry.startTime === "number" && typeof performance.timeOrigin === "number") {
1318
1589
  const originalStartTime = finalEntry.startTime;
1319
1590
  finalEntry.startTime = performance.timeOrigin + finalEntry.startTime;
1320
- BStackLogger2.debug(`Timestamp conversion for ${entry.name}: ${originalStartTime} -> ${finalEntry.startTime} (timeOrigin: ${performance.timeOrigin})`);
1591
+ BStackLogger.debug(`Timestamp conversion for ${entry.name}: ${originalStartTime} -> ${finalEntry.startTime} (timeOrigin: ${performance.timeOrigin})`);
1321
1592
  }
1322
1593
  } catch (e) {
1323
- BStackLogger2.debug(`Error converting startTime to epoch: ${util2.format(e)}`);
1594
+ BStackLogger.debug(`Error converting startTime to epoch: ${util2.format(e)}`);
1324
1595
  }
1325
1596
  if (this.details[entry.name]) {
1326
1597
  finalEntry = Object.assign(finalEntry, this.details[entry.name]);
@@ -1360,7 +1631,7 @@ var init_performance_tester = __esm({
1360
1631
  const timeTaken = methods.reduce((a, c) => {
1361
1632
  return times[c] + (a || 0);
1362
1633
  }, 0);
1363
- BStackLogger2.debug(`Time for ${methods} is ${timeTaken}`);
1634
+ BStackLogger.debug(`Time for ${methods} is ${timeTaken}`);
1364
1635
  return timeTaken;
1365
1636
  }
1366
1637
  static async stopAndGenerate(filename = "performance-own.html") {
@@ -1372,7 +1643,7 @@ var init_performance_tester = __esm({
1372
1643
  const finalJSONStr = eventsJson.slice(1, -1) + ",";
1373
1644
  await fsPromise.appendFile(this.jsonReportFileName, finalJSONStr);
1374
1645
  } catch (er) {
1375
- BStackLogger2.debug(`Failed to write events of the worker to ${this.jsonReportFileName}: ${util2.format(er)}`);
1646
+ BStackLogger.debug(`Failed to write events of the worker to ${this.jsonReportFileName}: ${util2.format(er)}`);
1376
1647
  }
1377
1648
  this._observer.disconnect();
1378
1649
  if (!process.env[PERF_MEASUREMENT_ENV]) {
@@ -1381,12 +1652,12 @@ var init_performance_tester = __esm({
1381
1652
  this.started = false;
1382
1653
  this.generateCSV(this._events);
1383
1654
  const content = this.generateReport(this._events);
1384
- const dir = path3.join(process.cwd(), filename);
1655
+ const dir = path4.join(process.cwd(), filename);
1385
1656
  try {
1386
1657
  await fsPromise.writeFile(dir, content);
1387
- BStackLogger2.info(`Performance report is at ${path3}`);
1658
+ BStackLogger.info(`Performance report is at ${path4}`);
1388
1659
  } catch (err) {
1389
- BStackLogger2.error(`Error in writing html ${util2.format(err)}`);
1660
+ BStackLogger.error(`Error in writing html ${util2.format(err)}`);
1390
1661
  }
1391
1662
  }
1392
1663
  static generateReport(entries) {
@@ -1417,7 +1688,7 @@ var init_performance_tester = __esm({
1417
1688
  time: value
1418
1689
  };
1419
1690
  });
1420
- this._csvWriter.writeRecords(dat).then(() => BStackLogger2.info("Performance CSV report generated successfully")).catch((error) => console.error(error));
1691
+ this._csvWriter.writeRecords(dat).then(() => BStackLogger.info("Performance CSV report generated successfully")).catch((error) => console.error(error));
1421
1692
  }
1422
1693
  static Measure(label, details = {}) {
1423
1694
  const self = this;
@@ -1525,6 +1796,7 @@ var init_performance_tester = __esm({
1525
1796
  static end(event, success = true, failure, details = {}) {
1526
1797
  performance.mark(event + "-end");
1527
1798
  performance.measure(event, event + "-start", event + "-end");
1799
+ delete this.eventsMap[event + "-start"];
1528
1800
  this.details[event] = Object.assign({ success, failure: util2.format(failure) }, Object.assign(Object.assign({
1529
1801
  clientWorkerId: _PerformanceTester.getClientWorkerId(),
1530
1802
  worker: _PerformanceTester.getProcessId(),
@@ -1550,16 +1822,16 @@ var init_performance_tester = __esm({
1550
1822
  this.start(EVENTS.SDK_SEND_KEY_METRICS);
1551
1823
  try {
1552
1824
  const workerId = `${process.pid}`;
1553
- BStackLogger2.debug(`[Performance Upload] Starting upload for worker ${workerId}`);
1825
+ BStackLogger.debug(`[Performance Upload] Starting upload for worker ${workerId}`);
1554
1826
  this.start(EVENTS.SDK_KEY_METRICS_PREPARATION);
1555
1827
  let measures = [];
1556
1828
  if (await fsPromise.access(this.jsonReportDirPath).then(() => true).catch(() => false)) {
1557
- const files = (await fsPromise.readdir(this.jsonReportDirPath)).map((file) => path3.resolve(this.jsonReportDirPath, file));
1829
+ const files = (await fsPromise.readdir(this.jsonReportDirPath)).map((file) => path4.resolve(this.jsonReportDirPath, file));
1558
1830
  measures = (await Promise.all(files.map((file) => fsPromise.readFile(file, "utf-8")))).map((el) => `[${el.slice(0, -1)}]`).map((el) => JSON.parse(el)).flat();
1559
1831
  }
1560
- BStackLogger2.debug(`[Performance Upload] Total events from files: ${measures.length}`);
1832
+ BStackLogger.debug(`[Performance Upload] Total events from files: ${measures.length}`);
1561
1833
  if (this._measuredEvents.length > 0) {
1562
- BStackLogger2.debug(`[Performance Upload] Adding ${this._measuredEvents.length} in-memory events`);
1834
+ BStackLogger.debug(`[Performance Upload] Adding ${this._measuredEvents.length} in-memory events`);
1563
1835
  measures = measures.concat(
1564
1836
  this._measuredEvents.map((e) => {
1565
1837
  if (typeof e.toJSON === "function") {
@@ -1620,10 +1892,10 @@ var init_performance_tester = __esm({
1620
1892
  },
1621
1893
  body: JSON.stringify(payload)
1622
1894
  });
1623
- BStackLogger2.debug(`[Performance Upload] Successfully uploaded to EDS: ${util2.format(await result.text())}`);
1895
+ BStackLogger.debug(`[Performance Upload] Successfully uploaded to EDS: ${util2.format(await result.text())}`);
1624
1896
  this.end(EVENTS.SDK_SEND_KEY_METRICS, true);
1625
1897
  } catch (er) {
1626
- BStackLogger2.debug(`[Performance Upload] Failed to upload events: ${util2.format(er)}`);
1898
+ BStackLogger.debug(`[Performance Upload] Failed to upload events: ${util2.format(er)}`);
1627
1899
  this.end(EVENTS.SDK_KEY_METRICS_PREPARATION, false, er);
1628
1900
  this.end(EVENTS.SDK_SEND_KEY_METRICS, false, er);
1629
1901
  }
@@ -1631,12 +1903,12 @@ var init_performance_tester = __esm({
1631
1903
  if (await fsPromise.access(this.jsonReportDirPath).then(() => true, () => false)) {
1632
1904
  const files = await fsPromise.readdir(this.jsonReportDirPath);
1633
1905
  for (const file of files) {
1634
- await fsPromise.unlink(path3.join(this.jsonReportDirPath, file));
1906
+ await fsPromise.unlink(path4.join(this.jsonReportDirPath, file));
1635
1907
  }
1636
- BStackLogger2.debug(`[Performance Upload] Cleaned up ${files.length} temporary report files`);
1908
+ BStackLogger.debug(`[Performance Upload] Cleaned up ${files.length} temporary report files`);
1637
1909
  }
1638
1910
  } catch (er) {
1639
- BStackLogger2.debug(`[Performance Upload] Failed to delete temporary files: ${util2.format(er)}`);
1911
+ BStackLogger.debug(`[Performance Upload] Failed to delete temporary files: ${util2.format(er)}`);
1640
1912
  }
1641
1913
  }
1642
1914
  };
@@ -1644,7 +1916,7 @@ var init_performance_tester = __esm({
1644
1916
  });
1645
1917
 
1646
1918
  // src/testorchestration/testorcherstrationutils.ts
1647
- import fs4 from "node:fs";
1919
+ import fs5 from "node:fs";
1648
1920
  var RUN_SMART_SELECTION, ALLOWED_ORCHESTRATION_KEYS, isPlainObject, asString, TestOrdering, OrchestrationUtils;
1649
1921
  var init_testorcherstrationutils = __esm({
1650
1922
  "src/testorchestration/testorcherstrationutils.ts"() {
@@ -1712,7 +1984,7 @@ var init_testorcherstrationutils = __esm({
1712
1984
  for (const service of services) {
1713
1985
  if (Array.isArray(service) && service[0] === "browserstack" && isPlainObject(service[1]) && isPlainObject(service[1].testOrchestrationOptions)) {
1714
1986
  testOrchOptions = service[1].testOrchestrationOptions;
1715
- BStackLogger2.debug("[constructor] Found testOrchestrationOptions in browserstack service config");
1987
+ BStackLogger.debug("[constructor] Found testOrchestrationOptions in browserstack service config");
1716
1988
  break;
1717
1989
  }
1718
1990
  }
@@ -1741,9 +2013,9 @@ var init_testorcherstrationutils = __esm({
1741
2013
  }
1742
2014
  });
1743
2015
  }
1744
- BStackLogger2.debug(`[_extractBuildDetails] Extracted - projectName: ${this.projectName}, buildName: ${this.buildName}, buildIdentifier: ${this.buildIdentifier}`);
2016
+ BStackLogger.debug(`[_extractBuildDetails] Extracted - projectName: ${this.projectName}, buildName: ${this.buildName}, buildIdentifier: ${this.buildIdentifier}`);
1745
2017
  } catch (error) {
1746
- BStackLogger2.error(`[_extractBuildDetails] ${error}`);
2018
+ BStackLogger.error(`[_extractBuildDetails] ${error}`);
1747
2019
  }
1748
2020
  }
1749
2021
  _parseCapability(capability) {
@@ -1841,7 +2113,7 @@ var init_testorcherstrationutils = __esm({
1841
2113
  this.projectName = projectName;
1842
2114
  this.buildName = buildName;
1843
2115
  this.buildIdentifier = buildIdentifier;
1844
- BStackLogger2.debug(`[setBuildDetails] Set - projectName: ${this.projectName}, buildName: ${this.buildName}, buildIdentifier: ${this.buildIdentifier}`);
2116
+ BStackLogger.debug(`[setBuildDetails] Set - projectName: ${this.projectName}, buildName: ${this.buildName}, buildIdentifier: ${this.buildIdentifier}`);
1845
2117
  }
1846
2118
  /**
1847
2119
  * Set run smart selection
@@ -1851,27 +2123,27 @@ var init_testorcherstrationutils = __esm({
1851
2123
  this.runSmartSelection = isValidEnabledValue(enabled);
1852
2124
  this.smartSelectionMode = mode;
1853
2125
  this.smartSelectionSource = [];
1854
- BStackLogger2.debug(`Setting runSmartSelection: enabled=${this.runSmartSelection}, mode=${this.smartSelectionMode}`);
2126
+ BStackLogger.debug(`Setting runSmartSelection: enabled=${this.runSmartSelection}, mode=${this.smartSelectionMode}`);
1855
2127
  if (this.runSmartSelection) {
1856
2128
  const validModes = [SMART_SELECTION_MODE_RELEVANT_FIRST, SMART_SELECTION_MODE_RELEVANT_ONLY];
1857
2129
  if (!validModes.includes(this.smartSelectionMode)) {
1858
- BStackLogger2.warn(`Invalid smart selection mode '${this.smartSelectionMode}' provided. Defaulting to '${SMART_SELECTION_MODE_RELEVANT_FIRST}'.`);
2130
+ BStackLogger.warn(`Invalid smart selection mode '${this.smartSelectionMode}' provided. Defaulting to '${SMART_SELECTION_MODE_RELEVANT_FIRST}'.`);
1859
2131
  this.smartSelectionMode = SMART_SELECTION_MODE_RELEVANT_FIRST;
1860
2132
  }
1861
2133
  if (source === null) {
1862
2134
  this.smartSelectionSource = null;
1863
- BStackLogger2.debug("No source provided for smart selection; defaulting to null.");
2135
+ BStackLogger.debug("No source provided for smart selection; defaulting to null.");
1864
2136
  } else if (Array.isArray(source)) {
1865
2137
  this.smartSelectionSource = source;
1866
- BStackLogger2.debug(`Smart selection source set to array: ${JSON.stringify(source)}`);
2138
+ BStackLogger.debug(`Smart selection source set to array: ${JSON.stringify(source)}`);
1867
2139
  } else if (typeof source === "string" && source.endsWith(".json")) {
1868
2140
  this.smartSelectionSource = this._loadSourceFromFile(source) || [];
1869
- BStackLogger2.debug(`Smart selection source loaded from file: ${source}`);
2141
+ BStackLogger.debug(`Smart selection source loaded from file: ${source}`);
1870
2142
  }
1871
2143
  this._setTestOrdering();
1872
2144
  }
1873
2145
  } catch (e) {
1874
- BStackLogger2.error(`[_setRunSmartSelection] ${e}`);
2146
+ BStackLogger.error(`[_setRunSmartSelection] ${e}`);
1875
2147
  }
1876
2148
  }
1877
2149
  /**
@@ -1881,17 +2153,17 @@ var init_testorcherstrationutils = __esm({
1881
2153
  * @returns Formatted list of repository configurations
1882
2154
  */
1883
2155
  _loadSourceFromFile(filePath) {
1884
- if (!fs4.existsSync(filePath)) {
1885
- BStackLogger2.error(`Source file '${filePath}' does not exist.`);
2156
+ if (!fs5.existsSync(filePath)) {
2157
+ BStackLogger.error(`Source file '${filePath}' does not exist.`);
1886
2158
  return [];
1887
2159
  }
1888
2160
  let data = null;
1889
2161
  try {
1890
- const fileContent = fs4.readFileSync(filePath, "utf8");
2162
+ const fileContent = fs5.readFileSync(filePath, "utf8");
1891
2163
  data = JSON.parse(fileContent);
1892
2164
  } catch (error) {
1893
2165
  const message = error instanceof Error ? error.message : String(error);
1894
- BStackLogger2.error(`Error parsing JSON from source file '${filePath}': ${message}`);
2166
+ BStackLogger.error(`Error parsing JSON from source file '${filePath}': ${message}`);
1895
2167
  return [];
1896
2168
  }
1897
2169
  let featureBranchEnvMap = null;
@@ -1907,9 +2179,9 @@ var init_testorcherstrationutils = __esm({
1907
2179
  return acc;
1908
2180
  }, {});
1909
2181
  } catch (error) {
1910
- BStackLogger2.error(`Error parsing feature branch mappings: ${error}`);
2182
+ BStackLogger.error(`Error parsing feature branch mappings: ${error}`);
1911
2183
  }
1912
- BStackLogger2.debug(`Feature branch mappings from env: ${JSON.stringify(envMap)}`);
2184
+ BStackLogger.debug(`Feature branch mappings from env: ${JSON.stringify(envMap)}`);
1913
2185
  return envMap;
1914
2186
  };
1915
2187
  featureBranchEnvMap = loadFeatureBranchMaps();
@@ -1931,23 +2203,23 @@ var init_testorcherstrationutils = __esm({
1931
2203
  }
1932
2204
  const typedRepoInfo = repoInfo;
1933
2205
  if (!typedRepoInfo.url || typeof typedRepoInfo.url !== "string") {
1934
- BStackLogger2.warn(`Repository URL is missing or invalid for source '${name}': ${JSON.stringify(repoInfo)}`);
2206
+ BStackLogger.warn(`Repository URL is missing or invalid for source '${name}': ${JSON.stringify(repoInfo)}`);
1935
2207
  continue;
1936
2208
  }
1937
2209
  if (typedRepoInfo.baseBranch !== void 0 && typeof typedRepoInfo.baseBranch !== "string") {
1938
- BStackLogger2.warn(`Base branch must be a string for source '${name}': ${JSON.stringify(repoInfo)}`);
2210
+ BStackLogger.warn(`Base branch must be a string for source '${name}': ${JSON.stringify(repoInfo)}`);
1939
2211
  continue;
1940
2212
  }
1941
2213
  if (typedRepoInfo.featureBranch !== void 0 && typeof typedRepoInfo.featureBranch !== "string") {
1942
- BStackLogger2.warn(`Feature branch must be a string for source '${name}': ${JSON.stringify(repoInfo)}`);
2214
+ BStackLogger.warn(`Feature branch must be a string for source '${name}': ${JSON.stringify(repoInfo)}`);
1943
2215
  continue;
1944
2216
  }
1945
2217
  if (!namePattern.test(name)) {
1946
- BStackLogger2.warn(`Invalid source identifier format for '${name}': ${JSON.stringify(repoInfo)}`);
2218
+ BStackLogger.warn(`Invalid source identifier format for '${name}': ${JSON.stringify(repoInfo)}`);
1947
2219
  continue;
1948
2220
  }
1949
2221
  if (name.length > 30 || name.length < 1) {
1950
- BStackLogger2.warn(`Source identifier '${name}' must have a length between 1 and 30 characters.`);
2222
+ BStackLogger.warn(`Source identifier '${name}' must have a length between 1 and 30 characters.`);
1951
2223
  continue;
1952
2224
  }
1953
2225
  const featureBranch = getFeatureBranch(name, typedRepoInfo);
@@ -1960,11 +2232,11 @@ var init_testorcherstrationutils = __esm({
1960
2232
  filteredRepoInfo.baseBranch = typedRepoInfo.baseBranch;
1961
2233
  }
1962
2234
  if (!filteredRepoInfo.featureBranch || filteredRepoInfo.featureBranch === "") {
1963
- BStackLogger2.warn(`Feature branch not specified for source '${name}': ${JSON.stringify(repoInfo)}`);
2235
+ BStackLogger.warn(`Feature branch not specified for source '${name}': ${JSON.stringify(repoInfo)}`);
1964
2236
  continue;
1965
2237
  }
1966
2238
  if (filteredRepoInfo.baseBranch && filteredRepoInfo.baseBranch === filteredRepoInfo.featureBranch) {
1967
- BStackLogger2.warn(`Feature branch and base branch cannot be the same for source '${name}': ${JSON.stringify(repoInfo)}`);
2239
+ BStackLogger.warn(`Feature branch and base branch cannot be the same for source '${name}': ${JSON.stringify(repoInfo)}`);
1968
2240
  continue;
1969
2241
  }
1970
2242
  formattedData.push(filteredRepoInfo);
@@ -2074,17 +2346,17 @@ var init_crash_reporter = __esm({
2074
2346
  this.credentialsForCrashReportUpload = process.env.CREDENTIALS_FOR_CRASH_REPORTING !== void 0 ? JSON.parse(process.env.CREDENTIALS_FOR_CRASH_REPORTING) : this.credentialsForCrashReportUpload;
2075
2347
  }
2076
2348
  } catch (error) {
2077
- return BStackLogger2.error(`[Crash_Report_Upload] Failed to parse user credentials while reporting crash due to ${error}`);
2349
+ return BStackLogger.error(`[Crash_Report_Upload] Failed to parse user credentials while reporting crash due to ${error}`);
2078
2350
  }
2079
2351
  if (!this.credentialsForCrashReportUpload.username || !this.credentialsForCrashReportUpload.password) {
2080
- return BStackLogger2.error("[Crash_Report_Upload] Failed to parse user credentials while reporting crash");
2352
+ return BStackLogger.error("[Crash_Report_Upload] Failed to parse user credentials while reporting crash");
2081
2353
  }
2082
2354
  try {
2083
2355
  if (Object.keys(this.userConfigForReporting).length === 0) {
2084
2356
  this.userConfigForReporting = process.env.USER_CONFIG_FOR_REPORTING !== void 0 ? JSON.parse(process.env.USER_CONFIG_FOR_REPORTING) : {};
2085
2357
  }
2086
2358
  } catch (error) {
2087
- BStackLogger2.error(`[Crash_Report_Upload] Failed to parse user config while reporting crash due to ${error}`);
2359
+ BStackLogger.error(`[Crash_Report_Upload] Failed to parse user config while reporting crash due to ${error}`);
2088
2360
  this.userConfigForReporting = {};
2089
2361
  }
2090
2362
  const data = {
@@ -2116,9 +2388,9 @@ var init_crash_reporter = __esm({
2116
2388
  body = JSON.stringify(JSON.parse(body));
2117
2389
  } catch {
2118
2390
  }
2119
- BStackLogger2.debug(`[Crash_Report_Upload] Success response: ${body}`);
2391
+ BStackLogger.debug(`[Crash_Report_Upload] Success response: ${body}`);
2120
2392
  } else {
2121
- BStackLogger2.error(`[Crash_Report_Upload] Failed due to ${response.body}`);
2393
+ BStackLogger.error(`[Crash_Report_Upload] Failed due to ${response.body}`);
2122
2394
  }
2123
2395
  }
2124
2396
  static recursivelyRedactKeysFromObject(obj, keys) {
@@ -2178,7 +2450,7 @@ var init_crash_reporter = __esm({
2178
2450
  }
2179
2451
  }
2180
2452
  } catch (err) {
2181
- BStackLogger2.error(`Error in parsing user config PII with error ${err ? err.stack || err : err}`);
2453
+ BStackLogger.error(`Error in parsing user config PII with error ${err ? err.stack || err : err}`);
2182
2454
  return configWithoutPII;
2183
2455
  }
2184
2456
  configWithoutPII.services = finalServices;
@@ -2213,7 +2485,7 @@ var init_featureStats = __esm({
2213
2485
  this.failed(groupId);
2214
2486
  break;
2215
2487
  default:
2216
- BStackLogger2.debug("Request to mark usage for unknown status - " + status);
2488
+ BStackLogger.debug("Request to mark usage for unknown status - " + status);
2217
2489
  break;
2218
2490
  }
2219
2491
  }
@@ -2449,7 +2721,7 @@ var init_usageStats = __esm({
2449
2721
  try {
2450
2722
  usage.events = this.getEventsData();
2451
2723
  } catch (e) {
2452
- BStackLogger2.debug("exception in getFormattedData: " + e);
2724
+ BStackLogger.debug("exception in getFormattedData: " + e);
2453
2725
  }
2454
2726
  return usage;
2455
2727
  }
@@ -2459,7 +2731,7 @@ var init_usageStats = __esm({
2459
2731
  const usageStatsForWorker = _UsageStats.fromJSON(workerData.usageStats);
2460
2732
  this.add(usageStatsForWorker);
2461
2733
  } catch (e) {
2462
- BStackLogger2.debug("Exception in adding workerData: " + e);
2734
+ BStackLogger.debug("Exception in adding workerData: " + e);
2463
2735
  }
2464
2736
  });
2465
2737
  }
@@ -2513,9 +2785,9 @@ var init_usageStats = __esm({
2513
2785
  });
2514
2786
 
2515
2787
  // src/scripts/accessibility-scripts.ts
2516
- import path4 from "node:path";
2517
- import fs5 from "node:fs";
2518
- import os from "node:os";
2788
+ import path5 from "node:path";
2789
+ import fs6 from "node:fs";
2790
+ import os2 from "node:os";
2519
2791
  var AccessibilityScripts, accessibility_scripts_default;
2520
2792
  var init_accessibility_scripts = __esm({
2521
2793
  "src/scripts/accessibility-scripts.ts"() {
@@ -2533,7 +2805,7 @@ var init_accessibility_scripts = __esm({
2533
2805
  // don't allow to create instances from it other than through `checkAndGetInstance`
2534
2806
  constructor() {
2535
2807
  this.browserstackFolderPath = this.getWritableDir();
2536
- this.commandsPath = path4.join(this.browserstackFolderPath, "commands.json");
2808
+ this.commandsPath = path5.join(this.browserstackFolderPath, "commands.json");
2537
2809
  }
2538
2810
  static checkAndGetInstance() {
2539
2811
  if (!_AccessibilityScripts.instance) {
@@ -2545,17 +2817,17 @@ var init_accessibility_scripts = __esm({
2545
2817
  /* eslint-disable @typescript-eslint/no-unused-vars */
2546
2818
  getWritableDir() {
2547
2819
  const orderedPaths = [
2548
- path4.join(os.homedir(), ".browserstack"),
2820
+ path5.join(os2.homedir(), ".browserstack"),
2549
2821
  process.cwd(),
2550
- os.tmpdir()
2822
+ os2.tmpdir()
2551
2823
  ];
2552
2824
  for (const orderedPath of orderedPaths) {
2553
2825
  try {
2554
- if (fs5.existsSync(orderedPath)) {
2555
- fs5.accessSync(orderedPath);
2826
+ if (fs6.existsSync(orderedPath)) {
2827
+ fs6.accessSync(orderedPath);
2556
2828
  return orderedPath;
2557
2829
  }
2558
- fs5.mkdirSync(orderedPath, { recursive: true });
2830
+ fs6.mkdirSync(orderedPath, { recursive: true });
2559
2831
  return orderedPath;
2560
2832
  } catch (error) {
2561
2833
  }
@@ -2564,8 +2836,8 @@ var init_accessibility_scripts = __esm({
2564
2836
  }
2565
2837
  readFromExistingFile() {
2566
2838
  try {
2567
- if (fs5.existsSync(this.commandsPath)) {
2568
- const data = fs5.readFileSync(this.commandsPath, "utf8");
2839
+ if (fs6.existsSync(this.commandsPath)) {
2840
+ const data = fs6.readFileSync(this.commandsPath, "utf8");
2569
2841
  if (data) {
2570
2842
  this.update(JSON.parse(data));
2571
2843
  }
@@ -2588,10 +2860,10 @@ var init_accessibility_scripts = __esm({
2588
2860
  }
2589
2861
  }
2590
2862
  store() {
2591
- if (!fs5.existsSync(this.browserstackFolderPath)) {
2592
- fs5.mkdirSync(this.browserstackFolderPath);
2863
+ if (!fs6.existsSync(this.browserstackFolderPath)) {
2864
+ fs6.mkdirSync(this.browserstackFolderPath);
2593
2865
  }
2594
- fs5.writeFileSync(this.commandsPath, JSON.stringify({
2866
+ fs6.writeFileSync(this.commandsPath, JSON.stringify({
2595
2867
  commands: this.commandsToWrap,
2596
2868
  scripts: {
2597
2869
  scan: this.performScan,
@@ -2610,17 +2882,15 @@ var init_accessibility_scripts = __esm({
2610
2882
  // src/util.ts
2611
2883
  import { hostname as hostname2, platform as platform3, type as type2, version as version2, arch as arch3, tmpdir } from "node:os";
2612
2884
  import crypto from "node:crypto";
2613
- import fs6 from "node:fs";
2885
+ import fs7 from "node:fs";
2614
2886
  import zlib from "node:zlib";
2615
2887
  import { format, promisify as promisify2 } from "node:util";
2616
- import path5 from "node:path";
2888
+ import path6 from "node:path";
2617
2889
  import util3 from "node:util";
2618
2890
  import gitRepoInfo from "git-repo-info";
2619
2891
  import gitconfig from "gitconfiglocal";
2620
- import { FormData as FormData2 } from "formdata-node";
2621
2892
  import { performance as performance2 } from "node:perf_hooks";
2622
2893
  import { create } from "tar";
2623
- import { fileFromPath } from "formdata-node/file-from-path";
2624
2894
  function getBrowserDescription(cap) {
2625
2895
  cap = cap || {};
2626
2896
  if (cap["bstack:options"]) {
@@ -2656,7 +2926,7 @@ function getParentSuiteName(fullTitle, testSuiteTitle) {
2656
2926
  return parentSuiteName.trim();
2657
2927
  }
2658
2928
  function processError(error, fn, args) {
2659
- BStackLogger2.error(`Error in executing ${fn.name} with args ${args}: ${error}`);
2929
+ BStackLogger.error(`Error in executing ${fn.name} with args ${args}: ${error}`);
2660
2930
  let argsString;
2661
2931
  try {
2662
2932
  argsString = JSON.stringify(args);
@@ -2694,7 +2964,7 @@ async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout =
2694
2964
  clearTimeout(timeoutId);
2695
2965
  return await response.json();
2696
2966
  } catch (error) {
2697
- BStackLogger2.debug(`Error in firing request ${apiUrl}/${apiEndpoint}: ${format(error)}`);
2967
+ BStackLogger.debug(`Error in firing request ${apiUrl}/${apiEndpoint}: ${format(error)}`);
2698
2968
  const isLogUpload = apiEndpoint === UPLOAD_LOGS_ENDPOINT;
2699
2969
  if (error && error.response) {
2700
2970
  const errorMessageJson = error.response.body ? JSON.parse(error.response.body.toString()) : null;
@@ -2702,9 +2972,9 @@ async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout =
2702
2972
  if (errorMessage) {
2703
2973
  const message = `${errorMessage} - ${error.stack}`;
2704
2974
  if (isLogUpload) {
2705
- BStackLogger2.debug(message);
2975
+ BStackLogger.debug(message);
2706
2976
  } else {
2707
- BStackLogger2.error(message);
2977
+ BStackLogger.error(message);
2708
2978
  }
2709
2979
  }
2710
2980
  if (isLogUpload) {
@@ -2713,10 +2983,10 @@ async function nodeRequest(requestType, apiEndpoint, options, apiUrl, timeout =
2713
2983
  throw error;
2714
2984
  } else {
2715
2985
  if (isLogUpload) {
2716
- BStackLogger2.debug(`Failed to fire api request due to ${error} - ${error.stack}`);
2986
+ BStackLogger.debug(`Failed to fire api request due to ${error} - ${error.stack}`);
2717
2987
  return;
2718
2988
  }
2719
- BStackLogger2.debug(`Failed to fire api request due to ${error} - ${error.stack}`);
2989
+ BStackLogger.debug(`Failed to fire api request due to ${error} - ${error.stack}`);
2720
2990
  throw error;
2721
2991
  }
2722
2992
  }
@@ -3136,9 +3406,9 @@ async function batchAndPostEvents(eventUrl, kind, data) {
3136
3406
  },
3137
3407
  body: JSON.stringify(data)
3138
3408
  });
3139
- BStackLogger2.debug(`[${kind}] Success response: ${JSON.stringify(await response.json())}`);
3409
+ BStackLogger.debug(`[${kind}] Success response: ${JSON.stringify(await response.json())}`);
3140
3410
  } catch (error) {
3141
- BStackLogger2.debug(`[${kind}] EXCEPTION IN ${kind} REQUEST TO TEST REPORTING AND ANALYTICS : ${error}`);
3411
+ BStackLogger.debug(`[${kind}] EXCEPTION IN ${kind} REQUEST TO TEST REPORTING AND ANALYTICS : ${error}`);
3142
3412
  throw new Error("Exception in request " + error);
3143
3413
  }
3144
3414
  }
@@ -3176,7 +3446,7 @@ function getObservabilityBuild(options, bstackBuildName) {
3176
3446
  if (options.testObservabilityOptions && options.testObservabilityOptions.buildName) {
3177
3447
  return options.testObservabilityOptions.buildName;
3178
3448
  }
3179
- return bstackBuildName || path5.basename(path5.resolve(process.cwd()));
3449
+ return bstackBuildName || path6.basename(path6.resolve(process.cwd()));
3180
3450
  }
3181
3451
  function getObservabilityBuildTags(options, bstackBuildTag) {
3182
3452
  if (process.env.TEST_OBSERVABILITY_BUILD_TAG) {
@@ -3190,6 +3460,25 @@ function getObservabilityBuildTags(options, bstackBuildTag) {
3190
3460
  }
3191
3461
  return [];
3192
3462
  }
3463
+ function getTestPlanId(options) {
3464
+ if (process.env[BROWSERSTACK_TEST_PLAN_ID]) {
3465
+ return process.env[BROWSERSTACK_TEST_PLAN_ID];
3466
+ }
3467
+ const CLI_ARG = "--browserstack.testManagementOptions.testPlanId";
3468
+ const argIndex = process.argv.indexOf(CLI_ARG);
3469
+ if (argIndex !== -1 && process.argv[argIndex + 1]) {
3470
+ return process.argv[argIndex + 1];
3471
+ }
3472
+ const argWithEquals = process.argv.find((arg) => arg.startsWith(`${CLI_ARG}=`));
3473
+ if (argWithEquals) {
3474
+ return argWithEquals.split("=")[1];
3475
+ }
3476
+ const testPlanId = options.testManagementOptions?.testPlanId;
3477
+ if (typeof testPlanId === "string" && testPlanId.trim().length > 0) {
3478
+ return testPlanId.trim();
3479
+ }
3480
+ return void 0;
3481
+ }
3193
3482
  function getBrowserStackUser(config) {
3194
3483
  if (process.env.BROWSERSTACK_USERNAME) {
3195
3484
  return process.env.BROWSERSTACK_USERNAME;
@@ -3235,23 +3524,39 @@ function getFailureObject(error) {
3235
3524
  };
3236
3525
  }
3237
3526
  async function uploadLogs(user, key, clientBuildUuid) {
3527
+ const eventName = EVENTS.SDK_UPLOAD_LOGS;
3528
+ let success = true;
3529
+ let failure;
3530
+ PerformanceTester.start(eventName);
3238
3531
  try {
3239
3532
  if (!user || !key) {
3240
- BStackLogger2.debug("Uploading logs failed due to no credentials");
3533
+ success = false;
3534
+ failure = "skipped: missing_credentials";
3535
+ BStackLogger.debug("Uploading logs failed due to no credentials");
3241
3536
  return;
3242
3537
  }
3243
3538
  const tmpDir = tmpdir();
3244
- const tarPath = path5.join(tmpDir, "logs.tar");
3245
- const tarGzPath = path5.join(tmpDir, "logs.tar.gz");
3539
+ const tarPath = path6.join(tmpDir, "logs.tar");
3540
+ const tarGzPath = path6.join(tmpDir, "logs.tar.gz");
3246
3541
  const filesToArchive = [
3247
- BStackLogger2.logFilePath,
3542
+ BStackLogger.logFilePath,
3248
3543
  CLI_DEBUG_LOGS_FILE
3249
- ].filter((f) => fs6.existsSync(f));
3544
+ ].filter((f) => fs7.existsSync(f));
3250
3545
  const copiedFileNames = [];
3546
+ const archiveAddFailures = [];
3251
3547
  for (const f of filesToArchive) {
3252
- const dest = path5.join(tmpDir, path5.basename(f));
3253
- fs6.copyFileSync(f, dest);
3254
- copiedFileNames.push(path5.basename(f));
3548
+ try {
3549
+ const dest = path6.join(tmpDir, path6.basename(f));
3550
+ fs7.copyFileSync(f, dest);
3551
+ copiedFileNames.push(path6.basename(f));
3552
+ } catch (copyErr) {
3553
+ const msg = copyErr?.message || String(copyErr);
3554
+ archiveAddFailures.push(`${path6.basename(f)}: ${msg}`);
3555
+ }
3556
+ }
3557
+ if (archiveAddFailures.length > 0 && failure === void 0) {
3558
+ success = false;
3559
+ failure = `archive_add_failed [${archiveAddFailures.length}]: ${archiveAddFailures.join("; ")}`.substring(0, 300);
3255
3560
  }
3256
3561
  await create(
3257
3562
  {
@@ -3263,15 +3568,15 @@ async function uploadLogs(user, key, clientBuildUuid) {
3263
3568
  copiedFileNames
3264
3569
  );
3265
3570
  await new Promise((resolve, reject) => {
3266
- const source = fs6.createReadStream(tarPath);
3267
- const dest = fs6.createWriteStream(tarGzPath);
3571
+ const source = fs7.createReadStream(tarPath);
3572
+ const dest = fs7.createWriteStream(tarGzPath);
3268
3573
  const gzip = zlib.createGzip({ level: 1 });
3269
3574
  source.pipe(gzip).pipe(dest);
3270
3575
  dest.on("finish", resolve);
3271
3576
  dest.on("error", reject);
3272
3577
  });
3273
- const formData = new FormData2();
3274
- const file = await fileFromPath(tarGzPath);
3578
+ const formData = new FormData();
3579
+ const file = await fs7.openAsBlob(tarGzPath, { type: "application/x-gzip" });
3275
3580
  formData.append("data", file, "logs.tar.gz");
3276
3581
  formData.append("clientBuildUuid", clientBuildUuid);
3277
3582
  const auth = Buffer.from(`${user}:${key}`).toString("base64");
@@ -3287,21 +3592,32 @@ async function uploadLogs(user, key, clientBuildUuid) {
3287
3592
  requestOptions,
3288
3593
  APIUtils.UPLOAD_LOGS_ADDRESS
3289
3594
  );
3290
- fs6.unlinkSync(tarPath);
3291
- fs6.unlinkSync(tarGzPath);
3595
+ fs7.unlinkSync(tarPath);
3596
+ fs7.unlinkSync(tarGzPath);
3292
3597
  for (const f of copiedFileNames) {
3293
- const filePath = path5.join(tmpDir, f);
3294
- if (fs6.existsSync(filePath)) {
3295
- fs6.unlinkSync(filePath);
3598
+ const filePath = path6.join(tmpDir, f);
3599
+ if (fs7.existsSync(filePath)) {
3600
+ fs7.unlinkSync(filePath);
3296
3601
  }
3297
3602
  }
3298
- if (fs6.existsSync(CLI_DEBUG_LOGS_FILE)) {
3299
- fs6.unlinkSync(CLI_DEBUG_LOGS_FILE);
3603
+ if (fs7.existsSync(CLI_DEBUG_LOGS_FILE)) {
3604
+ fs7.unlinkSync(CLI_DEBUG_LOGS_FILE);
3605
+ }
3606
+ if (!response) {
3607
+ success = false;
3608
+ failure = "upload_no_response";
3609
+ } else if (response.status && response.status !== "success") {
3610
+ success = false;
3611
+ failure = `upload_status: ${response.status}${response.message ? " - " + String(response.message).slice(0, 200) : ""}`;
3300
3612
  }
3301
3613
  return response;
3302
3614
  } catch (error) {
3303
- BStackLogger2.error(`Error while uploading logs: ${getErrorString(error)}`);
3615
+ success = false;
3616
+ failure = `uploadLogs exception: ${getErrorString(error)}`;
3617
+ BStackLogger.error(`Error while uploading logs: ${getErrorString(error)}`);
3304
3618
  return null;
3619
+ } finally {
3620
+ PerformanceTester.end(eventName, success, failure);
3305
3621
  }
3306
3622
  }
3307
3623
  function truncateString(field, truncateSizeInBytes) {
@@ -3315,7 +3631,7 @@ function truncateString(field, truncateSizeInBytes) {
3315
3631
  return truncatedString;
3316
3632
  }
3317
3633
  } catch (error) {
3318
- BStackLogger2.debug(`Error while truncating field, nothing was truncated here: ${error}`);
3634
+ BStackLogger.debug(`Error while truncating field, nothing was truncated here: ${error}`);
3319
3635
  }
3320
3636
  return field;
3321
3637
  }
@@ -3324,7 +3640,7 @@ function getSizeOfJsonObjectInBytes(jsonData) {
3324
3640
  const buffer = Buffer.from(JSON.stringify(jsonData));
3325
3641
  return buffer.length;
3326
3642
  } catch (error) {
3327
- BStackLogger2.debug(`Something went wrong while calculating size of JSON object: ${error}`);
3643
+ BStackLogger.debug(`Something went wrong while calculating size of JSON object: ${error}`);
3328
3644
  }
3329
3645
  return -1;
3330
3646
  }
@@ -3334,7 +3650,7 @@ function checkAndTruncateVCSInfo(gitMetaData) {
3334
3650
  const truncateSize = gitMetaDataSizeInBytes - MAX_GIT_META_DATA_SIZE_IN_BYTES;
3335
3651
  const truncatedCommitMessage = truncateString(gitMetaData.commit_message, truncateSize);
3336
3652
  gitMetaData.commit_message = truncatedCommitMessage;
3337
- BStackLogger2.info(`The commit has been truncated. Size of commit after truncation is ${getSizeOfJsonObjectInBytes(gitMetaData) / 1024} KB`);
3653
+ BStackLogger.info(`The commit has been truncated. Size of commit after truncation is ${getSizeOfJsonObjectInBytes(gitMetaData) / 1024} KB`);
3338
3654
  }
3339
3655
  return gitMetaData;
3340
3656
  }
@@ -3346,7 +3662,7 @@ function getObservabilityProduct(options, isAppAutomate) {
3346
3662
  }
3347
3663
  async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()) {
3348
3664
  params.timestamp = Math.round(Date.now() / 1e3);
3349
- BStackLogger2.debug(`current timestamp ${params.timestamp}`);
3665
+ BStackLogger.debug(`current timestamp ${params.timestamp}`);
3350
3666
  try {
3351
3667
  const response = await makeGetRequest(url3, params, headers);
3352
3668
  const responseData = await response.json();
@@ -3358,9 +3674,9 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
3358
3674
  } catch (error) {
3359
3675
  if (error.response && error.response.status === 404) {
3360
3676
  const nextPollTime = parseInt(error.response.headers.get("next_poll_time"), 10) * 1e3;
3361
- BStackLogger2.debug(`timeInMillis ${nextPollTime}`);
3677
+ BStackLogger.debug(`timeInMillis ${nextPollTime}`);
3362
3678
  if (isNaN(nextPollTime)) {
3363
- BStackLogger2.warn("Invalid or missing `nextPollTime` header. Stopping polling.");
3679
+ BStackLogger.warn("Invalid or missing `nextPollTime` header. Stopping polling.");
3364
3680
  return {
3365
3681
  data: {},
3366
3682
  headers: error.response.headers,
@@ -3368,18 +3684,18 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
3368
3684
  };
3369
3685
  }
3370
3686
  const elapsedTime = nextPollTime - Date.now();
3371
- BStackLogger2.debug(
3687
+ BStackLogger.debug(
3372
3688
  `elapsedTime ${elapsedTime} timeInMillis ${nextPollTime} upperLimit ${upperLimit}`
3373
3689
  );
3374
3690
  if (nextPollTime > upperLimit) {
3375
- BStackLogger2.warn("Polling stopped due to upper time limit.");
3691
+ BStackLogger.warn("Polling stopped due to upper time limit.");
3376
3692
  return {
3377
3693
  data: {},
3378
3694
  headers: error.response.headers,
3379
3695
  message: "Polling stopped due to upper time limit."
3380
3696
  };
3381
3697
  }
3382
- BStackLogger2.debug(`Polling again in ${elapsedTime}ms with params:`, params);
3698
+ BStackLogger.debug(`Polling again in ${elapsedTime}ms with params:`, params);
3383
3699
  await new Promise((resolve) => setTimeout(resolve, elapsedTime));
3384
3700
  return pollApi(url3, params, headers, upperLimit, startTime);
3385
3701
  } else if (error.response) {
@@ -3388,7 +3704,7 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
3388
3704
  const parsedError = JSON.parse(error.response.json());
3389
3705
  errorMessage = parsedError.message;
3390
3706
  } catch {
3391
- BStackLogger2.debug(`Error parsing pollApi request body ${error.response.body}`);
3707
+ BStackLogger.debug(`Error parsing pollApi request body ${error.response.body}`);
3392
3708
  errorMessage = "Unknown error";
3393
3709
  }
3394
3710
  throw {
@@ -3397,7 +3713,7 @@ async function pollApi(url3, params, headers, upperLimit, startTime = Date.now()
3397
3713
  message: errorMessage
3398
3714
  };
3399
3715
  } else {
3400
- BStackLogger2.error(`Unexpected error occurred: ${error}`);
3716
+ BStackLogger.error(`Unexpected error occurred: ${error}`);
3401
3717
  return { data: {}, headers: {}, message: "Unexpected error occurred." };
3402
3718
  }
3403
3719
  }
@@ -3506,28 +3822,28 @@ function nestedKeyValue(hash, keys) {
3506
3822
  return keys.reduce((hash2, key) => isHash(hash2) ? hash2[key] : void 0, hash);
3507
3823
  }
3508
3824
  function removeDir(dir) {
3509
- const list = fs6.readdirSync(dir);
3825
+ const list = fs7.readdirSync(dir);
3510
3826
  for (let i = 0; i < list.length; i++) {
3511
- const filename = path5.join(dir, list[i]);
3512
- const stat = fs6.statSync(filename);
3827
+ const filename = path6.join(dir, list[i]);
3828
+ const stat = fs7.statSync(filename);
3513
3829
  if (filename === "." || filename === "..") {
3514
3830
  } else if (stat.isDirectory()) {
3515
3831
  removeDir(filename);
3516
3832
  } else {
3517
- fs6.unlinkSync(filename);
3833
+ fs7.unlinkSync(filename);
3518
3834
  }
3519
3835
  }
3520
- fs6.rmdirSync(dir);
3836
+ fs7.rmdirSync(dir);
3521
3837
  }
3522
3838
  function createDir(dir) {
3523
- if (fs6.existsSync(dir)) {
3839
+ if (fs7.existsSync(dir)) {
3524
3840
  removeDir(dir);
3525
3841
  }
3526
- fs6.mkdirSync(dir, { recursive: true });
3842
+ fs7.mkdirSync(dir, { recursive: true });
3527
3843
  }
3528
3844
  function isWritable(dirPath) {
3529
3845
  try {
3530
- fs6.accessSync(dirPath, fs6.constants.W_OK);
3846
+ fs7.accessSync(dirPath, fs7.constants.W_OK);
3531
3847
  return true;
3532
3848
  } catch {
3533
3849
  return false;
@@ -3535,10 +3851,10 @@ function isWritable(dirPath) {
3535
3851
  }
3536
3852
  function setReadWriteAccess(dirPath) {
3537
3853
  try {
3538
- fs6.chmodSync(dirPath, 438);
3539
- BStackLogger2.debug(`Directory ${dirPath} is now read/write accessible.`);
3854
+ fs7.chmodSync(dirPath, 438);
3855
+ BStackLogger.debug(`Directory ${dirPath} is now read/write accessible.`);
3540
3856
  } catch (err) {
3541
- BStackLogger2.error(`Failed to set directory access: ${err.stack}`);
3857
+ BStackLogger.error(`Failed to set directory access: ${err.stack}`);
3542
3858
  }
3543
3859
  }
3544
3860
  function getMochaTestHierarchy(test) {
@@ -3566,7 +3882,7 @@ function isMultiRemoteCaps(capabilities) {
3566
3882
  (cap) => Object.values(cap).length > 0 && Object.values(cap).every((c) => c !== null && typeof c === "object" && c.capabilities)
3567
3883
  );
3568
3884
  }
3569
- var pGitconfig, DEFAULT_REQUEST_CONFIG, COLORS, processTestObservabilityResponse, jsonifyAccessibilityArray, processAccessibilityResponse, processLaunchBuildResponse, launchTestSession, validateCapsWithAppA11y, validateCapsWithA11y, validateCapsWithNonBstackA11y, shouldScanTestForAccessibility, isAccessibilityAutomationSession, isAppAccessibilityAutomationSession, formatString, _getParamsForAppAccessibility, performA11yScan, getA11yResults, getAppA11yResults, getAppA11yResultsSummary, getAppA11yResultResponse, getA11yResultsSummary, stopBuildUpstream, patchConsoleLogs, sleep, isObject, ObjectsAreEqual, getPlatformVersion, getBasicAuthHeader, isObjectEmpty, getErrorString, hasBrowserName, isValidCapsForHealing, performO11ySync;
3885
+ var pGitconfig, DEFAULT_REQUEST_CONFIG, COLORS, processTestObservabilityResponse, jsonifyAccessibilityArray, processAccessibilityResponse, processLaunchBuildResponse, launchTestSession, validateCapsWithAppA11y, validateCapsWithA11y, validateCapsWithNonBstackA11y, shouldScanTestForAccessibility, isAccessibilityAutomationSession, isAppAccessibilityAutomationSession, formatString, _getParamsForAppAccessibility, performA11yScan, getA11yResults, getAppA11yResults, getAppA11yResultsSummary, getAppA11yResultResponse, getA11yResultsSummary, stopBuildUpstream, patchConsoleLogs, sleep, isObject, ObjectsAreEqual, getPlatformVersion, getResolvedDeviceName, getBasicAuthHeader, isObjectEmpty, getErrorString, hasBrowserName, isValidCapsForHealing, performO11ySync;
3570
3886
  var init_util = __esm({
3571
3887
  "src/util.ts"() {
3572
3888
  "use strict";
@@ -3640,7 +3956,7 @@ var init_util = __esm({
3640
3956
  };
3641
3957
  if (scannerVersion) {
3642
3958
  process.env.BSTACK_A11Y_SCANNER_VERSION = scannerVersion;
3643
- BStackLogger2.debug(`Accessibility scannerVersion ${scannerVersion}`);
3959
+ BStackLogger.debug(`Accessibility scannerVersion ${scannerVersion}`);
3644
3960
  }
3645
3961
  if (accessibilityToken) {
3646
3962
  process.env.BSTACK_A11Y_JWT = accessibilityToken;
@@ -3698,7 +4014,10 @@ var init_util = __esm({
3698
4014
  },
3699
4015
  product_map: getProductMapForBuildStartCall(bStackConfig, accessibilityAutomation),
3700
4016
  config: {},
3701
- test_orchestration: OrchestrationUtils.getInstance(config)?.getBuildStartData() || {}
4017
+ test_orchestration: OrchestrationUtils.getInstance(config)?.getBuildStartData() || {},
4018
+ test_management: {
4019
+ test_plan_id: getTestPlanId(options)
4020
+ }
3702
4021
  };
3703
4022
  if (accessibilityAutomation && (isTurboScale(options) || data.browserstackAutomation === false)) {
3704
4023
  data.accessibility.settings ??= {};
@@ -3709,7 +4028,7 @@ var init_util = __esm({
3709
4028
  CrashReporter.userConfigForReporting = process.env.USER_CONFIG_FOR_REPORTING !== void 0 ? JSON.parse(process.env.USER_CONFIG_FOR_REPORTING) : {};
3710
4029
  }
3711
4030
  } catch (error) {
3712
- return BStackLogger2.error(`[Crash_Report_Upload] Failed to parse user config while sending build start event due to ${error}`);
4031
+ return BStackLogger.error(`[Crash_Report_Upload] Failed to parse user config while sending build start event due to ${error}`);
3713
4032
  }
3714
4033
  data.config = CrashReporter.userConfigForReporting;
3715
4034
  try {
@@ -3726,7 +4045,8 @@ var init_util = __esm({
3726
4045
  });
3727
4046
  const jsonResponse = await response.json();
3728
4047
  delete data?.accessibility?.settings?.includeEncodedExtension;
3729
- BStackLogger2.debug(`[Start_Build] Success response: ${JSON.stringify(jsonResponse)}`);
4048
+ BStackLogger.debug(`[Start_Build] Success response: ${JSON.stringify(jsonResponse)}`);
4049
+ BStackLogger.debug(`Test Plan Id sent in request: ${getTestPlanId(options)}`);
3730
4050
  process.env[TESTOPS_BUILD_COMPLETED_ENV] = "true";
3731
4051
  if (jsonResponse.jwt) {
3732
4052
  process.env[BROWSERSTACK_TESTHUB_JWT] = jsonResponse.jwt;
@@ -3734,13 +4054,13 @@ var init_util = __esm({
3734
4054
  if (jsonResponse.build_hashed_id) {
3735
4055
  process.env[BROWSERSTACK_TESTHUB_UUID] = jsonResponse.build_hashed_id;
3736
4056
  testOpsConfig_default.getInstance().buildHashedId = jsonResponse.build_hashed_id;
3737
- BStackLogger2.info(`Testhub started with id: ${testOpsConfig_default.getInstance()?.buildHashedId}`);
4057
+ BStackLogger.info(`Testhub started with id: ${testOpsConfig_default.getInstance()?.buildHashedId}`);
3738
4058
  }
3739
4059
  processLaunchBuildResponse(jsonResponse, options);
3740
4060
  launchBuildUsage.success();
3741
4061
  return jsonResponse;
3742
4062
  } catch (error) {
3743
- BStackLogger2.debug(`TestHub build start failed: ${format(error)}`);
4063
+ BStackLogger.debug(`TestHub build start failed: ${format(error)}`);
3744
4064
  if (!error.success) {
3745
4065
  launchBuildUsage.failed(error);
3746
4066
  logBuildError(error);
@@ -3750,7 +4070,7 @@ var init_util = __esm({
3750
4070
  }));
3751
4071
  validateCapsWithAppA11y = (platformMeta) => {
3752
4072
  if (platformMeta?.platform_name && String(platformMeta?.platform_name).toLowerCase() === "android" && (platformMeta?.platform_version && parseInt(platformMeta?.platform_version?.toString()) < 11)) {
3753
- BStackLogger2.warn("App Accessibility Automation tests are supported on OS version 11 and above for Android devices.");
4073
+ BStackLogger.warn("App Accessibility Automation tests are supported on OS version 11 and above for Android devices.");
3754
4074
  return false;
3755
4075
  }
3756
4076
  return true;
@@ -3758,38 +4078,79 @@ var init_util = __esm({
3758
4078
  validateCapsWithA11y = (deviceName, platformMeta, chromeOptions) => {
3759
4079
  try {
3760
4080
  if (deviceName) {
3761
- BStackLogger2.warn("Accessibility Automation will run only on Desktop browsers.");
3762
- return false;
3763
- }
3764
- if (platformMeta?.browser_name?.toLowerCase() !== "chrome") {
3765
- BStackLogger2.warn("Accessibility Automation will run only on Chrome browsers.");
4081
+ BStackLogger.warn("Accessibility Automation will run only on Desktop browsers.");
3766
4082
  return false;
3767
4083
  }
4084
+ const browserName = platformMeta?.browser_name?.toLowerCase();
3768
4085
  const browserVersion = platformMeta?.browser_version;
3769
- if (!isUndefined(browserVersion) && !(browserVersion === "latest" || parseFloat(browserVersion + "") > 94)) {
3770
- BStackLogger2.warn("Accessibility Automation will run only on Chrome browser version greater than 94.");
4086
+ const validBrowsers = SUPPORTED_BROWSERS_FOR_ACCESSIBILITY;
4087
+ if (!browserName || !validBrowsers.includes(browserName)) {
4088
+ BStackLogger.warn(`Accessibility Automation supports Chrome 95+, Chrome for Testing 141+, and Safari 18.4+. Current browser: ${browserName}`);
3771
4089
  return false;
3772
4090
  }
3773
- if (chromeOptions?.args?.includes("--headless")) {
3774
- BStackLogger2.warn("Accessibility Automation will not run on legacy headless mode. Switch to new headless mode or avoid using headless mode.");
3775
- return false;
4091
+ if (browserName === "chrome" || browserName === "chromefortesting") {
4092
+ const minVersion = MIN_BROWSER_VERSIONS_A11Y[browserName];
4093
+ if (browserVersion && browserVersion !== "latest") {
4094
+ const version3 = parseInt(browserVersion.toString().split(".")[0] || "0", 10);
4095
+ if (version3 < minVersion) {
4096
+ BStackLogger.warn(`Accessibility Automation requires ${browserName === "chrome" ? "Chrome" : "Chrome for Testing"} version ${minVersion} or higher.`);
4097
+ return false;
4098
+ }
4099
+ }
4100
+ if (chromeOptions?.args?.includes("--headless")) {
4101
+ BStackLogger.warn("Accessibility Automation will not run on legacy headless mode. Switch to new headless mode or avoid using headless mode.");
4102
+ return false;
4103
+ }
4104
+ }
4105
+ if (browserName === "safari") {
4106
+ if (browserVersion && browserVersion !== "latest") {
4107
+ const [currentMajor = 0, currentMinor = 0] = browserVersion.toString().split(".").map(Number);
4108
+ const [requiredMajor = 0, requiredMinor = 0] = MIN_BROWSER_VERSIONS_A11Y.safari.toString().split(".").map(Number);
4109
+ if (currentMajor < requiredMajor || currentMajor === requiredMajor && currentMinor < requiredMinor) {
4110
+ BStackLogger.warn(`Accessibility Automation requires Safari version ${MIN_BROWSER_VERSIONS_A11Y.safari} or higher.`);
4111
+ return false;
4112
+ }
4113
+ }
3776
4114
  }
3777
4115
  return true;
3778
4116
  } catch (error) {
3779
- BStackLogger2.debug(`Exception in checking capabilities compatibility with Accessibility. Error: ${error}`);
4117
+ BStackLogger.debug(`Exception in checking capabilities compatibility with Accessibility. Error: ${error}`);
3780
4118
  }
3781
4119
  return false;
3782
4120
  };
3783
4121
  validateCapsWithNonBstackA11y = (browserName, browserVersion) => {
3784
- if (browserName?.toLowerCase() !== "chrome") {
3785
- BStackLogger2.warn("Accessibility Automation will run only on Chrome browsers.");
3786
- return false;
3787
- }
3788
- if (!isUndefined(browserVersion) && !(browserVersion === "latest" || parseFloat(browserVersion + "") > 100)) {
3789
- BStackLogger2.warn("Accessibility Automation will run only on Chrome browser version greater than 100.");
3790
- return false;
4122
+ try {
4123
+ const browser = browserName?.toLowerCase();
4124
+ const validBrowsers = ["chrome", "chromefortesting", "safari"];
4125
+ if (!browser || !validBrowsers.includes(browser)) {
4126
+ BStackLogger.warn("Accessibility Automation on non-BrowserStack infrastructure supports Chrome 100+, Chrome for Testing 141+, and Safari 18.4+.");
4127
+ return false;
4128
+ }
4129
+ if (browser === "chrome" || browser === "chromefortesting") {
4130
+ const minVersion = MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK[browser];
4131
+ if (browserVersion && browserVersion !== "latest") {
4132
+ const version3 = parseInt(browserVersion.toString().split(".")[0] || "0", 10);
4133
+ if (version3 < minVersion) {
4134
+ BStackLogger.warn(`Accessibility Automation requires ${browser === "chrome" ? "Chrome" : "Chrome for Testing"} version ${minVersion}+ on non-BrowserStack infrastructure.`);
4135
+ return false;
4136
+ }
4137
+ }
4138
+ }
4139
+ if (browser === "safari") {
4140
+ if (browserVersion && browserVersion !== "latest") {
4141
+ const [currentMajor = 0, currentMinor = 0] = browserVersion.toString().split(".").map(Number);
4142
+ const [requiredMajor = 0, requiredMinor = 0] = MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK.safari.toString().split(".").map(Number);
4143
+ if (currentMajor < requiredMajor || currentMajor === requiredMajor && currentMinor < requiredMinor) {
4144
+ BStackLogger.warn(`Accessibility Automation requires Safari version ${MIN_BROWSER_VERSIONS_A11Y_NON_BSTACK.safari}+ on non-BrowserStack infrastructure.`);
4145
+ return false;
4146
+ }
4147
+ }
4148
+ }
4149
+ return true;
4150
+ } catch (error) {
4151
+ BStackLogger.debug(`Exception in checking capabilities compatibility with Accessibility. Error: ${error}`);
3791
4152
  }
3792
- return true;
4153
+ return false;
3793
4154
  };
3794
4155
  shouldScanTestForAccessibility = (suiteTitle, testTitle, accessibilityOptions, world, isCucumber) => {
3795
4156
  try {
@@ -3807,7 +4168,7 @@ var init_util = __esm({
3807
4168
  const included = includeTags?.length === 0 || includeTags?.some((include) => fullTestName.includes(include));
3808
4169
  return !excluded && included;
3809
4170
  } catch (error) {
3810
- BStackLogger2.debug(`Error while validating test case for accessibility before scanning. Error : ${error}`);
4171
+ BStackLogger.debug(`Error while validating test case for accessibility before scanning. Error : ${error}`);
3811
4172
  }
3812
4173
  return false;
3813
4174
  };
@@ -3816,7 +4177,7 @@ var init_util = __esm({
3816
4177
  const hasA11yJwtToken = typeof process.env.BSTACK_A11Y_JWT === "string" && process.env.BSTACK_A11Y_JWT.length > 0 && process.env.BSTACK_A11Y_JWT !== "null" && process.env.BSTACK_A11Y_JWT !== "undefined";
3817
4178
  return accessibilityFlag && hasA11yJwtToken;
3818
4179
  } catch (error) {
3819
- BStackLogger2.debug(`Exception in verifying the Accessibility session with error : ${error}`);
4180
+ BStackLogger.debug(`Exception in verifying the Accessibility session with error : ${error}`);
3820
4181
  }
3821
4182
  return false;
3822
4183
  };
@@ -3847,43 +4208,43 @@ var init_util = __esm({
3847
4208
  };
3848
4209
  performA11yScan = async (isAppAutomate, browser, isBrowserStackSession, isAccessibility, commandName, testName) => {
3849
4210
  if (!isAccessibilityAutomationSession(isAccessibility)) {
3850
- BStackLogger2.warn("Not an Accessibility Automation session, cannot perform Accessibility scan.");
4211
+ BStackLogger.warn("Not an Accessibility Automation session, cannot perform Accessibility scan.");
3851
4212
  return;
3852
4213
  }
3853
4214
  try {
3854
4215
  if (isAppAccessibilityAutomationSession(isAccessibility, isAppAutomate)) {
3855
4216
  const results = await browser.execute(formatString(accessibility_scripts_default.performScan, JSON.stringify(_getParamsForAppAccessibility(commandName, testName))), {});
3856
- BStackLogger2.debug(util3.format(results));
4217
+ BStackLogger.debug(util3.format(results));
3857
4218
  return results;
3858
4219
  }
3859
4220
  if (accessibility_scripts_default.performScan) {
3860
4221
  const results = await executeAccessibilityScript(browser, accessibility_scripts_default.performScan, { method: commandName || "" });
3861
4222
  return results;
3862
4223
  }
3863
- BStackLogger2.error("AccessibilityScripts.performScan is null");
4224
+ BStackLogger.error("AccessibilityScripts.performScan is null");
3864
4225
  return;
3865
4226
  } catch (err) {
3866
- BStackLogger2.error("Accessibility Scan could not be performed : " + err);
4227
+ BStackLogger.error("Accessibility Scan could not be performed : " + err);
3867
4228
  return;
3868
4229
  }
3869
4230
  };
3870
4231
  getA11yResults = PerformanceTester.measureWrapper(A11Y_EVENTS.GET_RESULTS, async (isAppAutomate, browser, isBrowserStackSession, isAccessibility) => {
3871
4232
  if (!isAccessibilityAutomationSession(isAccessibility)) {
3872
- BStackLogger2.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results.");
4233
+ BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results.");
3873
4234
  return [];
3874
4235
  }
3875
4236
  try {
3876
- BStackLogger2.debug("Performing scan before getting results");
4237
+ BStackLogger.debug("Performing scan before getting results");
3877
4238
  await performA11yScan(isAppAutomate, browser, isBrowserStackSession, isAccessibility);
3878
4239
  if (accessibility_scripts_default.getResults) {
3879
4240
  const results = await executeAccessibilityScript(browser, accessibility_scripts_default.getResults);
3880
4241
  return results;
3881
4242
  }
3882
- BStackLogger2.error("AccessibilityScripts.getResults is null");
4243
+ BStackLogger.error("AccessibilityScripts.getResults is null");
3883
4244
  return [];
3884
4245
  } catch (error) {
3885
- BStackLogger2.error("No accessibility results were found.");
3886
- BStackLogger2.debug(`getA11yResults Failed. Error: ${error}`);
4246
+ BStackLogger.error("No accessibility results were found.");
4247
+ BStackLogger.debug(`getA11yResults Failed. Error: ${error}`);
3887
4248
  return [];
3888
4249
  }
3889
4250
  });
@@ -3892,18 +4253,18 @@ var init_util = __esm({
3892
4253
  return [];
3893
4254
  }
3894
4255
  if (!isAppAccessibilityAutomationSession(isAccessibility, isAppAutomate)) {
3895
- BStackLogger2.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
4256
+ BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
3896
4257
  return [];
3897
4258
  }
3898
4259
  try {
3899
4260
  const apiUrl = `${APIUtils.APP_ALLY_ENDPOINT}/${APP_ALLY_ISSUES_ENDPOINT}`;
3900
4261
  const apiRespone = await getAppA11yResultResponse(apiUrl, isAppAutomate, browser, testName, isBrowserStackSession, isAccessibility, sessionId);
3901
4262
  const result = apiRespone?.data?.data?.issues;
3902
- BStackLogger2.debug(`Polling Result: ${JSON.stringify(result)}`);
4263
+ BStackLogger.debug(`Polling Result: ${JSON.stringify(result)}`);
3903
4264
  return result;
3904
4265
  } catch (error) {
3905
- BStackLogger2.error("No accessibility summary was found.");
3906
- BStackLogger2.debug(`getAppA11yResults Failed. Error: ${error}`);
4266
+ BStackLogger.error("No accessibility summary was found.");
4267
+ BStackLogger.debug(`getAppA11yResults Failed. Error: ${error}`);
3907
4268
  return [];
3908
4269
  }
3909
4270
  });
@@ -3912,46 +4273,46 @@ var init_util = __esm({
3912
4273
  return {};
3913
4274
  }
3914
4275
  if (!isAppAccessibilityAutomationSession(isAccessibility, isAppAutomate)) {
3915
- BStackLogger2.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
4276
+ BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
3916
4277
  return {};
3917
4278
  }
3918
4279
  try {
3919
4280
  const apiUrl = `${APIUtils.APP_ALLY_ENDPOINT}/${APP_ALLY_ISSUES_SUMMARY_ENDPOINT}`;
3920
4281
  const apiRespone = await getAppA11yResultResponse(apiUrl, isAppAutomate, browser, testName, isBrowserStackSession, isAccessibility, sessionId);
3921
4282
  const result = apiRespone?.data?.data?.summary;
3922
- BStackLogger2.debug(`Polling Result: ${JSON.stringify(result)}`);
4283
+ BStackLogger.debug(`Polling Result: ${JSON.stringify(result)}`);
3923
4284
  return result;
3924
4285
  } catch {
3925
- BStackLogger2.error("No accessibility summary was found.");
4286
+ BStackLogger.error("No accessibility summary was found.");
3926
4287
  return {};
3927
4288
  }
3928
4289
  });
3929
4290
  getAppA11yResultResponse = async (apiUrl, isAppAutomate, browser, testName, isBrowserStackSession, isAccessibility, sessionId) => {
3930
- BStackLogger2.debug("Performing scan before getting results summary");
4291
+ BStackLogger.debug("Performing scan before getting results summary");
3931
4292
  await performA11yScan(isAppAutomate, browser, isBrowserStackSession, isAccessibility, void 0, testName);
3932
4293
  const upperTimeLimit = process.env.BSTACK_A11Y_POLLING_TIMEOUT ? Date.now() + parseInt(process.env.BSTACK_A11Y_POLLING_TIMEOUT) * 1e3 : Date.now() + 3e4;
3933
4294
  const params = { test_run_uuid: process.env.TEST_ANALYTICS_ID, session_id: sessionId, timestamp: Date.now() };
3934
4295
  const header = { Authorization: `Bearer ${process.env.BSTACK_A11Y_JWT}` };
3935
4296
  const apiRespone = await pollApi(apiUrl, params, header, upperTimeLimit);
3936
- BStackLogger2.debug(`Polling Result: ${JSON.stringify(apiRespone)}`);
4297
+ BStackLogger.debug(`Polling Result: ${JSON.stringify(apiRespone)}`);
3937
4298
  return apiRespone;
3938
4299
  };
3939
4300
  getA11yResultsSummary = PerformanceTester.measureWrapper(A11Y_EVENTS.GET_RESULTS_SUMMARY, async (isAppAutomate, browser, isBrowserStackSession, isAccessibility) => {
3940
4301
  if (!isAccessibilityAutomationSession(isAccessibility)) {
3941
- BStackLogger2.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
4302
+ BStackLogger.warn("Not an Accessibility Automation session, cannot retrieve Accessibility results summary.");
3942
4303
  return {};
3943
4304
  }
3944
4305
  try {
3945
- BStackLogger2.debug("Performing scan before getting results summary");
4306
+ BStackLogger.debug("Performing scan before getting results summary");
3946
4307
  await performA11yScan(isAppAutomate, browser, isBrowserStackSession, isAccessibility);
3947
4308
  if (accessibility_scripts_default.getResultsSummary) {
3948
4309
  const summaryResults = await executeAccessibilityScript(browser, accessibility_scripts_default.getResultsSummary);
3949
4310
  return summaryResults;
3950
4311
  }
3951
- BStackLogger2.error("AccessibilityScripts.getResultsSummary is null");
4312
+ BStackLogger.error("AccessibilityScripts.getResultsSummary is null");
3952
4313
  return {};
3953
4314
  } catch {
3954
- BStackLogger2.error("No accessibility summary was found.");
4315
+ BStackLogger.error("No accessibility summary was found.");
3955
4316
  return {};
3956
4317
  }
3957
4318
  });
@@ -3967,7 +4328,7 @@ var init_util = __esm({
3967
4328
  }
3968
4329
  if (!process.env[BROWSERSTACK_TESTHUB_JWT]) {
3969
4330
  stopBuildUsage.failed("Token/buildID is undefined, build creation might have failed");
3970
- BStackLogger2.debug("[STOP_BUILD] Missing Authentication Token/ Build ID");
4331
+ BStackLogger.debug("[STOP_BUILD] Missing Authentication Token/ Build ID");
3971
4332
  return {
3972
4333
  status: "error",
3973
4334
  message: "Token/buildID is undefined, build creation might have failed"
@@ -3986,7 +4347,7 @@ var init_util = __esm({
3986
4347
  },
3987
4348
  body: JSON.stringify(data)
3988
4349
  });
3989
- BStackLogger2.debug(`[STOP_BUILD] Success response: ${await response.text()}`);
4350
+ BStackLogger.debug(`[STOP_BUILD] Success response: ${await response.text()}`);
3990
4351
  stopBuildUsage.success();
3991
4352
  return {
3992
4353
  status: "success",
@@ -3994,7 +4355,7 @@ var init_util = __esm({
3994
4355
  };
3995
4356
  } catch (error) {
3996
4357
  stopBuildUsage.failed(error);
3997
- BStackLogger2.debug(`[STOP_BUILD] Failed. Error: ${error}`);
4358
+ BStackLogger.debug(`[STOP_BUILD] Failed. Error: ${error}`);
3998
4359
  return {
3999
4360
  status: "error",
4000
4361
  message: error.message
@@ -4005,7 +4366,7 @@ var init_util = __esm({
4005
4366
  const BSTestOpsPatcher = new logPatcher_default({});
4006
4367
  Object.keys(consoleHolder).forEach((method) => {
4007
4368
  if (!(method in console) || method === "Console" || typeof console[method] !== "function") {
4008
- BStackLogger2.debug(`Skipping method: ${method}, exists: ${method in console}, type: ${typeof console[method]}`);
4369
+ BStackLogger.debug(`Skipping method: ${method}, exists: ${method in console}, type: ${typeof console[method]}`);
4009
4370
  return;
4010
4371
  }
4011
4372
  const origMethod = console[method].bind(console);
@@ -4018,7 +4379,7 @@ var init_util = __esm({
4018
4379
  BSTestOpsPatcher[method](...args);
4019
4380
  }
4020
4381
  } catch (error) {
4021
- BStackLogger2.debug(`Error while patching console logs : ${error}`);
4382
+ BStackLogger.debug(`Error while patching console logs : ${error}`);
4022
4383
  origMethod(...args);
4023
4384
  }
4024
4385
  };
@@ -4052,18 +4413,57 @@ var init_util = __esm({
4052
4413
  const keys = ["platformVersion", "platform_version", "osVersion", "os_version"];
4053
4414
  for (const key of keys) {
4054
4415
  if (caps?.[key]) {
4055
- BStackLogger2.debug(`Got ${key} from driver caps`);
4416
+ BStackLogger.debug(`Got ${key} from driver caps`);
4056
4417
  return String(caps?.[key]);
4057
4418
  } else if (bstackOptions && bstackOptions?.[key]) {
4058
- BStackLogger2.debug(`Got ${key} from user bstack options`);
4419
+ BStackLogger.debug(`Got ${key} from user bstack options`);
4059
4420
  return String(bstackOptions?.[key]);
4060
4421
  } else if (userCaps[key]) {
4061
- BStackLogger2.debug(`Got ${key} from user caps`);
4422
+ BStackLogger.debug(`Got ${key} from user caps`);
4062
4423
  return String(userCaps[key]);
4063
4424
  }
4064
4425
  }
4065
4426
  return void 0;
4066
4427
  });
4428
+ getResolvedDeviceName = o11yErrorHandler(function getResolvedDeviceName2(driverCaps, requestedCaps) {
4429
+ const flattenMultiremote = (caps) => {
4430
+ if (!caps) {
4431
+ return [];
4432
+ }
4433
+ const obj = caps;
4434
+ if (obj["deviceModel"] || obj["appium:deviceModel"] || obj["deviceName"] || obj["bstack:options"]) {
4435
+ return [caps];
4436
+ }
4437
+ return Object.values(obj).filter((v) => v !== null && typeof v === "object" && "capabilities" in v).map((v) => v.capabilities).filter(Boolean);
4438
+ };
4439
+ const sources = [
4440
+ ...flattenMultiremote(driverCaps),
4441
+ ...flattenMultiremote(requestedCaps)
4442
+ ];
4443
+ if (!sources.length) {
4444
+ return void 0;
4445
+ }
4446
+ const pickString = (obj, key) => {
4447
+ const v = obj?.[key];
4448
+ return typeof v === "string" && v.length > 0 ? v : void 0;
4449
+ };
4450
+ const paths = [
4451
+ (c) => pickString(c, "deviceModel"),
4452
+ (c) => pickString(c, "appium:deviceModel"),
4453
+ (c) => pickString(c["bstack:options"], "deviceName"),
4454
+ (c) => pickString(c, "appium:deviceName"),
4455
+ (c) => pickString(c, "deviceName")
4456
+ ];
4457
+ for (const path22 of paths) {
4458
+ for (const src of sources) {
4459
+ const v = path22(src);
4460
+ if (v) {
4461
+ return v;
4462
+ }
4463
+ }
4464
+ }
4465
+ return void 0;
4466
+ });
4067
4467
  getBasicAuthHeader = (username, password) => {
4068
4468
  const encodedAuth = Buffer.from(`${username}:${password}`, "utf8").toString("base64");
4069
4469
  return `Basic ${encodedAuth}`;
@@ -4107,20 +4507,20 @@ var init_util = __esm({
4107
4507
  });
4108
4508
 
4109
4509
  // src/bstackLogger.ts
4110
- import path6 from "node:path";
4111
- import fs7 from "node:fs";
4510
+ import path7 from "node:path";
4511
+ import fs8 from "node:fs";
4112
4512
  import chalk2 from "chalk";
4113
4513
  import logger2 from "@wdio/logger";
4114
- var log2, BStackLogger2;
4514
+ var log2, BStackLogger;
4115
4515
  var init_bstackLogger = __esm({
4116
4516
  "src/bstackLogger.ts"() {
4117
4517
  "use strict";
4118
4518
  init_constants();
4119
4519
  init_util();
4120
4520
  log2 = logger2("@wdio/browserstack-service");
4121
- BStackLogger2 = class {
4122
- static logFilePath = path6.join(process.cwd(), LOGS_FILE);
4123
- static logFolderPath = path6.join(process.cwd(), "logs");
4521
+ BStackLogger = class {
4522
+ static logFilePath = path7.join(process.cwd(), LOGS_FILE);
4523
+ static logFolderPath = path7.join(process.cwd(), "logs");
4124
4524
  static logFileStream;
4125
4525
  static redactCredentials(logMessage) {
4126
4526
  return logMessage.replace(/(["']?(?:username|userName|accesskey|accessKey|user|key)["']?\s*[:=]\s*["']?)([^"'\s,}]+)/gi, "$1").replace(/([?&](?:username|userName|access_key|accesskey|accessKey|user|key)=)([^&#\s]+)/gi, "$1");
@@ -4130,7 +4530,7 @@ var init_bstackLogger = __esm({
4130
4530
  const redactedMessage = this.redactCredentials(logMessage);
4131
4531
  if (!this.logFileStream) {
4132
4532
  this.ensureLogsFolder();
4133
- this.logFileStream = fs7.createWriteStream(this.logFilePath, { flags: "a" });
4533
+ this.logFileStream = fs8.createWriteStream(this.logFilePath, { flags: "a" });
4134
4534
  }
4135
4535
  if (this.logFileStream && this.logFileStream.writable) {
4136
4536
  this.logFileStream.write(this.formatLog(redactedMessage, logLevel));
@@ -4179,13 +4579,13 @@ var init_bstackLogger = __esm({
4179
4579
  this.logFileStream = null;
4180
4580
  }
4181
4581
  static clearLogFile() {
4182
- if (fs7.existsSync(this.logFilePath)) {
4183
- fs7.truncateSync(this.logFilePath);
4582
+ if (fs8.existsSync(this.logFilePath)) {
4583
+ fs8.truncateSync(this.logFilePath);
4184
4584
  }
4185
4585
  }
4186
4586
  static ensureLogsFolder() {
4187
- if (!fs7.existsSync(this.logFolderPath)) {
4188
- fs7.mkdirSync(this.logFolderPath);
4587
+ if (!fs8.existsSync(this.logFolderPath)) {
4588
+ fs8.mkdirSync(this.logFolderPath);
4189
4589
  }
4190
4590
  }
4191
4591
  };
@@ -4201,13 +4601,14 @@ var init_utils = __esm({
4201
4601
  init_bstackLogger();
4202
4602
  init_util();
4203
4603
  getProductMap = (config) => {
4204
- return {
4205
- observability: config.testObservability.enabled,
4206
- accessibility: config.accessibility,
4207
- percy: config.percy,
4208
- automate: config.automate,
4209
- app_automate: config.appAutomate
4210
- };
4604
+ const entries = [
4605
+ ["observability", config.testObservability.enabled],
4606
+ ["accessibility", !!config.accessibility],
4607
+ ["percy", config.percy],
4608
+ ["automate", config.automate],
4609
+ ["app_automate", config.appAutomate]
4610
+ ];
4611
+ return Object.fromEntries(entries.filter(([, v]) => v !== null));
4211
4612
  };
4212
4613
  shouldProcessEventForTesthub = (eventType) => {
4213
4614
  if (isTrue(process.env[BROWSERSTACK_OBSERVABILITY])) {
@@ -4231,7 +4632,7 @@ var init_utils = __esm({
4231
4632
  };
4232
4633
  logBuildError = (error, product = "") => {
4233
4634
  if (!error || !error.errors) {
4234
- BStackLogger2.error(`${product.toUpperCase()} Build creation failed ${error}`);
4635
+ BStackLogger.error(`${product.toUpperCase()} Build creation failed ${error}`);
4235
4636
  return;
4236
4637
  }
4237
4638
  for (const errorJson of error.errors) {
@@ -4240,35 +4641,36 @@ var init_utils = __esm({
4240
4641
  if (errorMessage) {
4241
4642
  switch (errorType) {
4242
4643
  case "ERROR_INVALID_CREDENTIALS":
4243
- BStackLogger2.error(errorMessage);
4644
+ BStackLogger.error(errorMessage);
4244
4645
  break;
4245
4646
  case "ERROR_ACCESS_DENIED":
4246
- BStackLogger2.info(errorMessage);
4647
+ BStackLogger.info(errorMessage);
4247
4648
  break;
4248
4649
  case "ERROR_SDK_DEPRECATED":
4249
- BStackLogger2.error(errorMessage);
4650
+ BStackLogger.error(errorMessage);
4250
4651
  break;
4251
4652
  default:
4252
- BStackLogger2.error(errorMessage);
4653
+ BStackLogger.error(errorMessage);
4253
4654
  }
4254
4655
  }
4255
4656
  }
4256
4657
  };
4257
4658
  getProductMapForBuildStartCall = (config, accessibilityAutomation) => {
4258
- return {
4259
- observability: config.testObservability.enabled,
4260
- accessibility: accessibilityAutomation,
4261
- percy: config.percy,
4262
- automate: config.automate,
4263
- app_automate: config.appAutomate
4264
- };
4659
+ const entries = [
4660
+ ["observability", config.testObservability.enabled],
4661
+ ["accessibility", accessibilityAutomation],
4662
+ ["percy", config.percy],
4663
+ ["automate", config.automate],
4664
+ ["app_automate", config.appAutomate]
4665
+ ];
4666
+ return Object.fromEntries(entries.filter(([, v]) => v !== null));
4265
4667
  };
4266
4668
  }
4267
4669
  });
4268
4670
 
4269
4671
  // src/Percy/PercyLogger.ts
4270
- import path7 from "node:path";
4271
- import fs8 from "node:fs";
4672
+ import path8 from "node:path";
4673
+ import fs9 from "node:fs";
4272
4674
  import chalk3 from "chalk";
4273
4675
  import logger3 from "@wdio/logger";
4274
4676
  var log3, PercyLogger;
@@ -4279,16 +4681,16 @@ var init_PercyLogger = __esm({
4279
4681
  init_util();
4280
4682
  log3 = logger3("@wdio/browserstack-service");
4281
4683
  PercyLogger = class {
4282
- static logFilePath = path7.join(process.cwd(), PERCY_LOGS_FILE);
4283
- static logFolderPath = path7.join(process.cwd(), "logs");
4684
+ static logFilePath = path8.join(process.cwd(), PERCY_LOGS_FILE);
4685
+ static logFolderPath = path8.join(process.cwd(), "logs");
4284
4686
  static logFileStream;
4285
4687
  static logToFile(logMessage, logLevel) {
4286
4688
  try {
4287
4689
  if (!this.logFileStream) {
4288
- if (!fs8.existsSync(this.logFolderPath)) {
4289
- fs8.mkdirSync(this.logFolderPath);
4690
+ if (!fs9.existsSync(this.logFolderPath)) {
4691
+ fs9.mkdirSync(this.logFolderPath);
4290
4692
  }
4291
- this.logFileStream = fs8.createWriteStream(this.logFilePath, { flags: "a" });
4693
+ this.logFileStream = fs9.createWriteStream(this.logFilePath, { flags: "a" });
4292
4694
  }
4293
4695
  if (this.logFileStream && this.logFileStream.writable) {
4294
4696
  this.logFileStream.write(this.formatLog(logMessage, logLevel));
@@ -4332,8 +4734,8 @@ var init_PercyLogger = __esm({
4332
4734
  this.logFileStream = null;
4333
4735
  }
4334
4736
  static clearLogFile() {
4335
- if (fs8.existsSync(this.logFilePath)) {
4336
- fs8.truncateSync(this.logFilePath);
4737
+ if (fs9.existsSync(this.logFilePath)) {
4738
+ fs9.truncateSync(this.logFilePath);
4337
4739
  }
4338
4740
  }
4339
4741
  };
@@ -4341,7 +4743,7 @@ var init_PercyLogger = __esm({
4341
4743
  });
4342
4744
 
4343
4745
  // src/cli/grpcClient.ts
4344
- import path12 from "node:path";
4746
+ import path13 from "node:path";
4345
4747
  import util5, { promisify as promisify3 } from "node:util";
4346
4748
  import {
4347
4749
  SDKClient,
@@ -4359,7 +4761,7 @@ import {
4359
4761
  DriverInitRequestConstructor,
4360
4762
  FetchDriverExecuteParamsEventRequestConstructor
4361
4763
  } from "@browserstack/wdio-browserstack-service";
4362
- var GrpcClient;
4764
+ var GRPC_MESSAGE_LIMIT, GrpcClient;
4363
4765
  var init_grpcClient = __esm({
4364
4766
  "src/cli/grpcClient.ts"() {
4365
4767
  "use strict";
@@ -4367,13 +4769,14 @@ var init_grpcClient = __esm({
4367
4769
  init_performance_tester();
4368
4770
  init_constants2();
4369
4771
  init_cliLogger();
4772
+ GRPC_MESSAGE_LIMIT = 20 * 1024 * 1024;
4370
4773
  GrpcClient = class _GrpcClient {
4371
4774
  static #instance = null;
4372
4775
  binSessionId;
4373
4776
  listenAddress;
4374
4777
  channel = null;
4375
4778
  client = null;
4376
- logger = BStackLogger;
4779
+ logger = BStackLogger2;
4377
4780
  constructor() {
4378
4781
  }
4379
4782
  /**
@@ -4428,17 +4831,20 @@ var init_grpcClient = __esm({
4428
4831
  if (!listenAddress) {
4429
4832
  throw new Error("Unable to determine gRPC server listen address");
4430
4833
  }
4834
+ const channelOptions = {
4835
+ "grpc.keepalive_time_ms": 1e4,
4836
+ "grpc.max_send_message_length": GRPC_MESSAGE_LIMIT,
4837
+ "grpc.max_receive_message_length": GRPC_MESSAGE_LIMIT
4838
+ };
4431
4839
  this.channel = new grpcChannel(
4432
4840
  listenAddress,
4433
4841
  grpcCredentials.createInsecure(),
4434
- {
4435
- "grpc.keepalive_time_ms": 1e4
4436
- }
4842
+ channelOptions
4437
4843
  );
4438
4844
  this.client = new SDKClient(
4439
4845
  listenAddress,
4440
4846
  grpcCredentials.createInsecure(),
4441
- {}
4847
+ channelOptions
4442
4848
  );
4443
4849
  this.logger.info(`Connected to gRPC server at ${listenAddress}`);
4444
4850
  }
@@ -4462,7 +4868,7 @@ var init_grpcClient = __esm({
4462
4868
  sdkLanguage: CLIUtils.getSdkLanguage(),
4463
4869
  sdkVersion: packageVersion,
4464
4870
  pathProject: process.cwd(),
4465
- pathConfig: path12.resolve(process.cwd(), "browserstack.yml"),
4871
+ pathConfig: path13.resolve(process.cwd(), "browserstack.yml"),
4466
4872
  cliArgs: process.argv.slice(2),
4467
4873
  frameworks: [automationFrameworkDetail.name, testFrameworkDetail.name],
4468
4874
  frameworkVersions,
@@ -4908,7 +5314,7 @@ var init_baseModule = __esm({
4908
5314
  this.platformIndex = platformIndex;
4909
5315
  this.client = client;
4910
5316
  this.config = config;
4911
- BStackLogger.debug(`Configured module ${this.getModuleName()} with binSessionId=${binSessionId}, platformIndex=${platformIndex}`);
5317
+ BStackLogger2.debug(`Configured module ${this.getModuleName()} with binSessionId=${binSessionId}, platformIndex=${platformIndex}`);
4912
5318
  }
4913
5319
  };
4914
5320
  }
@@ -5179,7 +5585,7 @@ var init_testFramework = __esm({
5179
5585
  * @returns {void}
5180
5586
  */
5181
5587
  trackEvent(testFrameworkState, hookState, args = {}) {
5182
- BStackLogger.info(`trackEvent: testFrameworkState=${testFrameworkState}; hookState=${hookState}; args=${args}`);
5588
+ BStackLogger2.info(`trackEvent: testFrameworkState=${testFrameworkState}; hookState=${hookState}; args=${args}`);
5183
5589
  }
5184
5590
  /**
5185
5591
  * run test hooks
@@ -5189,7 +5595,7 @@ var init_testFramework = __esm({
5189
5595
  * @param {*} args
5190
5596
  */
5191
5597
  async runHooks(instance, testFrameworkState, hookState, args = {}) {
5192
- BStackLogger.info(`runHooks: instance=${instance} automationFrameworkState=${testFrameworkState} hookState=${hookState}`);
5598
+ BStackLogger2.info(`runHooks: instance=${instance} automationFrameworkState=${testFrameworkState} hookState=${hookState}`);
5193
5599
  const hookRegistryKey = CLIUtils.getHookRegistryKey(testFrameworkState, hookState);
5194
5600
  await eventDispatcher.notifyObserver(hookRegistryKey, args);
5195
5601
  }
@@ -5453,7 +5859,7 @@ var init_automationFramework = __esm({
5453
5859
  * @returns {void}
5454
5860
  */
5455
5861
  async trackEvent(automationFrameworkState, hookState, args = {}) {
5456
- BStackLogger.info(`trackEvent: automationFrameworkState=${automationFrameworkState} hookState=${hookState} args=${args}`);
5862
+ BStackLogger2.info(`trackEvent: automationFrameworkState=${automationFrameworkState} hookState=${hookState} args=${args}`);
5457
5863
  }
5458
5864
  /**
5459
5865
  *
@@ -5463,7 +5869,7 @@ var init_automationFramework = __esm({
5463
5869
  * @param {*} args
5464
5870
  */
5465
5871
  async runHooks(instance, automationFrameworkState, hookState, args = {}) {
5466
- BStackLogger.info(`runHooks: automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
5872
+ BStackLogger2.info(`runHooks: automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
5467
5873
  const hookRegistryKey = CLIUtils.getHookRegistryKey(automationFrameworkState, hookState);
5468
5874
  await eventDispatcher.notifyObserver(hookRegistryKey, args);
5469
5875
  }
@@ -5481,7 +5887,7 @@ var init_automationFramework = __esm({
5481
5887
  * @returns {void}
5482
5888
  */
5483
5889
  static setTrackedInstance(context, instance) {
5484
- BStackLogger.debug(`setTrackedInstance: ${context.getId()}`);
5890
+ BStackLogger2.debug(`setTrackedInstance: ${context.getId()}`);
5485
5891
  _AutomationFramework.instances.set(context.getId(), instance);
5486
5892
  }
5487
5893
  /**
@@ -5489,7 +5895,7 @@ var init_automationFramework = __esm({
5489
5895
  * @returns {TrackedInstance} The tracked instance
5490
5896
  */
5491
5897
  static getTrackedInstance() {
5492
- BStackLogger.debug(`getTrackedInstance: ${CLIUtils.getCurrentInstanceName()}`);
5898
+ BStackLogger2.debug(`getTrackedInstance: ${CLIUtils.getCurrentInstanceName()}`);
5493
5899
  const context = TrackedInstance.createContext(CLIUtils.getCurrentInstanceName());
5494
5900
  return _AutomationFramework.instances.get(context.getId());
5495
5901
  }
@@ -5617,7 +6023,7 @@ var init_automateModule = __esm({
5617
6023
  init_automationFrameworkState();
5618
6024
  init_fetchWrapper();
5619
6025
  AutomateModule = class _AutomateModule extends BaseModule {
5620
- logger = BStackLogger;
6026
+ logger = BStackLogger2;
5621
6027
  browserStackConfig;
5622
6028
  sessionMap = /* @__PURE__ */ new Map();
5623
6029
  static MODULE_NAME = "AutomateModule";
@@ -5678,12 +6084,12 @@ var init_automateModule = __esm({
5678
6084
  async onAfterTest(args) {
5679
6085
  this.logger.debug("onAfterTest: inside automate module after test hook!");
5680
6086
  const instace = args.instance;
5681
- const { error, passed } = args.result;
6087
+ const { error, passed, skipped } = args.result;
5682
6088
  const _failReasons = [];
5683
- if (!passed) {
6089
+ if (!passed && !skipped) {
5684
6090
  _failReasons.push(error && error.message || "Unknown Error");
5685
6091
  }
5686
- const status = passed ? "passed" : "failed";
6092
+ const status = passed || skipped ? "passed" : "failed";
5687
6093
  const reason = _failReasons.length > 0 ? _failReasons.join("\n") : void 0;
5688
6094
  const autoInstance = AutomationFramework.getTrackedInstance();
5689
6095
  const sessionId = AutomationFramework.getState(autoInstance, AutomationFrameworkConstants.KEY_FRAMEWORK_SESSION_ID);
@@ -5933,7 +6339,7 @@ var init_testFrameworkInstance = __esm({
5933
6339
 
5934
6340
  // src/cli/frameworks/wdioMochaTestFramework.ts
5935
6341
  import { v4 as uuidv42 } from "uuid";
5936
- import path13 from "node:path";
6342
+ import path14 from "node:path";
5937
6343
  var WdioMochaTestFramework;
5938
6344
  var init_wdioMochaTestFramework = __esm({
5939
6345
  "src/cli/frameworks/wdioMochaTestFramework.ts"() {
@@ -5967,11 +6373,11 @@ var init_wdioMochaTestFramework = __esm({
5967
6373
  * @param {*} args
5968
6374
  */
5969
6375
  async trackEvent(testFrameworkState, hookState, args = {}) {
5970
- BStackLogger.info(`trackEvent: testFrameworkState=${testFrameworkState} hookState=${hookState}`);
6376
+ BStackLogger2.info(`trackEvent: testFrameworkState=${testFrameworkState} hookState=${hookState}`);
5971
6377
  await super.trackEvent(testFrameworkState, hookState, args);
5972
6378
  const instance = this.resolveInstance(testFrameworkState, hookState, args);
5973
6379
  if (instance === null) {
5974
- BStackLogger.error(`trackEvent: instance not found for testFrameworkState=${testFrameworkState} hookState=${hookState}`);
6380
+ BStackLogger2.error(`trackEvent: instance not found for testFrameworkState=${testFrameworkState} hookState=${hookState}`);
5975
6381
  return;
5976
6382
  }
5977
6383
  try {
@@ -5983,7 +6389,7 @@ var init_wdioMochaTestFramework = __esm({
5983
6389
  if (!TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_ID) && hookState === HookState.PRE && testFrameworkState === TestFrameworkState.TEST) {
5984
6390
  const test = args.test;
5985
6391
  const testData = await this.getTestData(instance, test);
5986
- BStackLogger.info(`trackEvent: instanceData=${JSON.stringify(Object.fromEntries(instance.getAllData()))}`);
6392
+ BStackLogger2.info(`trackEvent: instanceData=${JSON.stringify(Object.fromEntries(instance.getAllData()))}`);
5987
6393
  instance.updateMultipleEntries(testData);
5988
6394
  }
5989
6395
  if (testFrameworkState === TestFrameworkState.TEST) {
@@ -6001,13 +6407,13 @@ var init_wdioMochaTestFramework = __esm({
6001
6407
  logEntry.uuid = TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOK_ID);
6002
6408
  this.loadLogEntries(instance, testFrameworkState, hookState, logEntry);
6003
6409
  } else if (testFrameworkState === TestFrameworkState.LOG_REPORT && hookState === HookState.POST) {
6004
- BStackLogger.info("trackEvent: load test results");
6410
+ BStackLogger2.info("trackEvent: load test results");
6005
6411
  this.loadTestResult(instance, args);
6006
6412
  }
6007
6413
  await this.trackHookEvents(instance, testFrameworkState, hookState, args);
6008
- BStackLogger.debug(`trackEvent: tracked instance data=${JSON.stringify(Object.fromEntries(instance.getAllData()))}`);
6414
+ BStackLogger2.debug(`trackEvent: tracked instance data=${JSON.stringify(Object.fromEntries(instance.getAllData()))}`);
6009
6415
  } catch (error) {
6010
- BStackLogger.error(`trackEvent: Error in tracking events: ${error} hookState=${hookState} testFrameworkState=${testFrameworkState}`);
6416
+ BStackLogger2.error(`trackEvent: Error in tracking events: ${error} hookState=${hookState} testFrameworkState=${testFrameworkState}`);
6011
6417
  }
6012
6418
  args.instance = instance;
6013
6419
  await this.runHooks(instance, testFrameworkState, hookState, args);
@@ -6021,7 +6427,7 @@ var init_wdioMochaTestFramework = __esm({
6021
6427
  */
6022
6428
  resolveInstance(testFrameworkState, hookState, args = {}) {
6023
6429
  let instance = null;
6024
- BStackLogger.info(`resolveInstance: resolving instance for testFrameworkState=${testFrameworkState} hookState=${hookState}`);
6430
+ BStackLogger2.info(`resolveInstance: resolving instance for testFrameworkState=${testFrameworkState} hookState=${hookState}`);
6025
6431
  if (testFrameworkState === TestFrameworkState.INIT_TEST || testFrameworkState === TestFrameworkState.NONE) {
6026
6432
  this.trackWdioMochaInstance(testFrameworkState, args);
6027
6433
  }
@@ -6038,7 +6444,7 @@ var init_wdioMochaTestFramework = __esm({
6038
6444
  const target = CLIUtils.getCurrentInstanceName();
6039
6445
  const trackedContext = TrackedInstance.createContext(target);
6040
6446
  let instance = null;
6041
- BStackLogger.info(`trackWdioMochaInstance: created instance for target=${target}, state=${testFrameworkState}, args=${args}`);
6447
+ BStackLogger2.info(`trackWdioMochaInstance: created instance for target=${target}, state=${testFrameworkState}, args=${args}`);
6042
6448
  instance = new TestFrameworkInstance(
6043
6449
  trackedContext,
6044
6450
  this.getTestFrameworks(),
@@ -6061,7 +6467,7 @@ var init_wdioMochaTestFramework = __esm({
6061
6467
  process.env[TEST_ANALYTICS_ID] = instanceEntries[TestFrameworkConstants.KEY_TEST_UUID];
6062
6468
  instance.updateMultipleEntries(instanceEntries);
6063
6469
  TestFramework.setTrackedInstance(trackedContext, instance);
6064
- BStackLogger.info(`trackWdioMochaInstance: saved instance contextId=${trackedContext.getId()} target=${target}`);
6470
+ BStackLogger2.info(`trackWdioMochaInstance: saved instance contextId=${trackedContext.getId()} target=${target}`);
6065
6471
  }
6066
6472
  async getTestData(instance, test) {
6067
6473
  const framework = TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_FRAMEWORK_NAME);
@@ -6072,8 +6478,8 @@ var init_wdioMochaTestFramework = __esm({
6072
6478
  [TestFrameworkConstants.KEY_TEST_ID]: getUniqueIdentifier(test, framework),
6073
6479
  [TestFrameworkConstants.KEY_TEST_NAME]: test.title || test.description,
6074
6480
  [TestFrameworkConstants.KEY_TEST_CODE]: test.body || "",
6075
- [TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ? path13.relative(gitConfig.root, filename) : void 0,
6076
- [TestFrameworkConstants.KEY_TEST_LOCATION]: filename ? path13.relative(process.cwd(), filename) : void 0,
6481
+ [TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ? path14.relative(gitConfig.root, filename) : void 0,
6482
+ [TestFrameworkConstants.KEY_TEST_LOCATION]: filename ? path14.relative(process.cwd(), filename) : void 0,
6077
6483
  [TestFrameworkConstants.KEY_TEST_SCOPE]: fullTitle,
6078
6484
  [TestFrameworkConstants.KEY_TEST_SCOPES]: getMochaTestHierarchy(test)
6079
6485
  };
@@ -6081,13 +6487,17 @@ var init_wdioMochaTestFramework = __esm({
6081
6487
  }
6082
6488
  loadTestResult(instance, args) {
6083
6489
  const results = args.result;
6084
- const { error, passed } = results;
6490
+ const { error, passed, skipped } = results;
6085
6491
  let result = "passed";
6086
6492
  let failure = null;
6087
6493
  let failureReason = null;
6088
6494
  let failureType = null;
6089
6495
  if (!passed) {
6090
- result = error && error.message && error.message.includes("sync skip; aborting execution") ? "ignore" : "failed";
6496
+ if (skipped) {
6497
+ result = "skipped";
6498
+ } else {
6499
+ result = error && error.message && error.message.includes("sync skip; aborting execution") ? "ignore" : "failed";
6500
+ }
6091
6501
  if (error && result !== "skipped") {
6092
6502
  failure = [{ backtrace: [removeAnsiColors(error.message), removeAnsiColors(error.stack || "")] }];
6093
6503
  failureReason = removeAnsiColors(error.message);
@@ -6122,7 +6532,7 @@ var init_wdioMochaTestFramework = __esm({
6122
6532
  if (lastActiveHook) {
6123
6533
  const hookLogs = lastActiveHook[TestFrameworkConstants.KEY_HOOK_LOGS];
6124
6534
  hookLogs.push(logRecord);
6125
- BStackLogger.debug(`hooks after update logs ${TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_STARTED)} ${TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_FINISHED)}`);
6535
+ BStackLogger2.debug(`hooks after update logs ${TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_STARTED)} ${TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_FINISHED)}`);
6126
6536
  return;
6127
6537
  }
6128
6538
  const entries = TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_LOGS);
@@ -6223,15 +6633,15 @@ var init_wdioMochaTestFramework = __esm({
6223
6633
  [TestFrameworkConstants.KEY_EVENT_STARTED_AT]: (/* @__PURE__ */ new Date()).toISOString(),
6224
6634
  [TestFrameworkConstants.KEY_HOOK_LOGS]: [],
6225
6635
  [TestFrameworkConstants.KEY_HOOK_NAME]: test.title || test.description,
6226
- [TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ? path13.relative(gitConfig.root, filename) : void 0,
6227
- [TestFrameworkConstants.KEY_TEST_LOCATION]: filename ? path13.relative(process.cwd(), filename) : void 0
6636
+ [TestFrameworkConstants.KEY_TEST_FILE_PATH]: gitConfig?.root && filename ? path14.relative(gitConfig.root, filename) : void 0,
6637
+ [TestFrameworkConstants.KEY_TEST_LOCATION]: filename ? path14.relative(process.cwd(), filename) : void 0
6228
6638
  };
6229
6639
  hooksStarted.get(key)?.push(hook);
6230
6640
  updates[_WdioMochaTestFramework.KEY_HOOK_LAST_STARTED] = key;
6231
- BStackLogger.info(`Hook Started in PRE key = ${key} & hook = ${JSON.stringify(hook)}`);
6641
+ BStackLogger2.info(`Hook Started in PRE key = ${key} & hook = ${JSON.stringify(hook)}`);
6232
6642
  } else if (hookState === HookState.POST) {
6233
6643
  const hooksList = hooksStarted.get(key) || [];
6234
- BStackLogger.info(`Hook List in Post ${JSON.stringify(hooksList)}`);
6644
+ BStackLogger2.info(`Hook List in Post ${JSON.stringify(hooksList)}`);
6235
6645
  if (hooksList.length > 0) {
6236
6646
  const hook = hooksList.pop();
6237
6647
  const result = testResult.status;
@@ -6244,7 +6654,7 @@ var init_wdioMochaTestFramework = __esm({
6244
6654
  }
6245
6655
  }
6246
6656
  instance.updateMultipleEntries(updates);
6247
- BStackLogger.info(`trackHookEvents: hook state=${key}.${hookState}, hooks started=${JSON.stringify(hooksStarted)}, hooks finished=${JSON.stringify(hooksFinished)}`);
6657
+ BStackLogger2.info(`trackHookEvents: hook state=${key}.${hookState}, hooks started=${JSON.stringify(hooksStarted)}, hooks finished=${JSON.stringify(hooksFinished)}`);
6248
6658
  }
6249
6659
  };
6250
6660
  }
@@ -6268,7 +6678,7 @@ var init_testHubModule = __esm({
6268
6678
  init_automationFramework();
6269
6679
  init_automationFrameworkConstants();
6270
6680
  TestHubModule = class _TestHubModule extends BaseModule {
6271
- logger = BStackLogger;
6681
+ logger = BStackLogger2;
6272
6682
  testhubConfig;
6273
6683
  name;
6274
6684
  static MODULE_NAME = "TestHubModule";
@@ -6541,11 +6951,11 @@ var init_wdioAutomationFramework = __esm({
6541
6951
  * @param {*} args
6542
6952
  */
6543
6953
  async trackEvent(automationFrameworkState, hookState, args = {}) {
6544
- BStackLogger.info(`trackEvent: automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
6954
+ BStackLogger2.info(`trackEvent: automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
6545
6955
  await super.trackEvent(automationFrameworkState, hookState, args);
6546
6956
  const instance = this.resolveInstance(automationFrameworkState, hookState, args);
6547
6957
  if (instance === null) {
6548
- BStackLogger.error(`trackEvent: instance not found for automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
6958
+ BStackLogger2.error(`trackEvent: instance not found for automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
6549
6959
  return;
6550
6960
  }
6551
6961
  args.instance = instance;
@@ -6560,7 +6970,7 @@ var init_wdioAutomationFramework = __esm({
6560
6970
  */
6561
6971
  resolveInstance(automationFrameworkState, hookState, args = {}) {
6562
6972
  let instance = null;
6563
- BStackLogger.info(`resolveInstance: resolving instance for automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
6973
+ BStackLogger2.info(`resolveInstance: resolving instance for automationFrameworkState=${automationFrameworkState} hookState=${hookState}`);
6564
6974
  if (automationFrameworkState === AutomationFrameworkState.CREATE || automationFrameworkState === AutomationFrameworkState.NONE) {
6565
6975
  this.trackWebdriverIOInstance(automationFrameworkState, args);
6566
6976
  }
@@ -6576,13 +6986,13 @@ var init_wdioAutomationFramework = __esm({
6576
6986
  // !args.browser &&
6577
6987
  AutomationFramework.getTrackedInstance()
6578
6988
  ) {
6579
- BStackLogger.info("trackWebdriverIOInstance: instance already exists");
6989
+ BStackLogger2.info("trackWebdriverIOInstance: instance already exists");
6580
6990
  return;
6581
6991
  }
6582
6992
  const target = CLIUtils.getCurrentInstanceName();
6583
6993
  const trackedContext = TrackedInstance.createContext(target);
6584
6994
  let instance = null;
6585
- BStackLogger.info(`trackWebdriverIOInstance: created instance for target=${target}, state=${automationFrameworkState}, args=${args}`);
6995
+ BStackLogger2.info(`trackWebdriverIOInstance: created instance for target=${target}, state=${automationFrameworkState}, args=${args}`);
6586
6996
  instance = new AutomationFrameworkInstance(
6587
6997
  trackedContext,
6588
6998
  this.getAutomationFrameworkName(),
@@ -6590,7 +7000,7 @@ var init_wdioAutomationFramework = __esm({
6590
7000
  automationFrameworkState
6591
7001
  );
6592
7002
  AutomationFramework.setTrackedInstance(trackedContext, instance);
6593
- BStackLogger.info(`trackWebdriverIOInstance: saved instance contextId=${trackedContext.getId()} target=${target}`);
7003
+ BStackLogger2.info(`trackWebdriverIOInstance: saved instance contextId=${trackedContext.getId()} target=${target}`);
6594
7004
  }
6595
7005
  };
6596
7006
  }
@@ -6616,7 +7026,7 @@ var init_webdriverIOModule = __esm({
6616
7026
  browserVersion;
6617
7027
  platforms;
6618
7028
  testRunId;
6619
- logger = BStackLogger;
7029
+ logger = BStackLogger2;
6620
7030
  static MODULE_NAME = "WebdriverIOModule";
6621
7031
  /**
6622
7032
  * Create a new WebdriverIOModule
@@ -6744,7 +7154,7 @@ var init_accessibilityModule = __esm({
6744
7154
  init_constants2();
6745
7155
  init_grpcClient();
6746
7156
  AccessibilityModule = class extends BaseModule {
6747
- logger = BStackLogger;
7157
+ logger = BStackLogger2;
6748
7158
  name;
6749
7159
  scriptInstance;
6750
7160
  accessibility = false;
@@ -7028,7 +7438,7 @@ var init_accessibilityModule = __esm({
7028
7438
  formatString(this.scriptInstance.performScan, JSON.stringify(_getParamsForAppAccessibility(commandName, testName))),
7029
7439
  {}
7030
7440
  );
7031
- BStackLogger.debug(util9.format(results2));
7441
+ BStackLogger2.debug(util9.format(results2));
7032
7442
  return results2;
7033
7443
  }
7034
7444
  const results = await browser.executeAsync(
@@ -7151,7 +7561,7 @@ var init_observabilityModule = __esm({
7151
7561
  init_cliLogger();
7152
7562
  init_util();
7153
7563
  ObservabilityModule = class _ObservabilityModule extends BaseModule {
7154
- logger = BStackLogger;
7564
+ logger = BStackLogger2;
7155
7565
  observabilityConfig;
7156
7566
  name;
7157
7567
  static MODULE_NAME = "ObservabilityModule";
@@ -7254,22 +7664,22 @@ var init_request_handler = __esm({
7254
7664
  throw new Error("Test Reporting and Analytics build start not completed yet.");
7255
7665
  }
7256
7666
  this.queue.push(event);
7257
- BStackLogger2.debug(`Added data to request queue. Queue length = ${this.queue.length}`);
7667
+ BStackLogger.debug(`Added data to request queue. Queue length = ${this.queue.length}`);
7258
7668
  const shouldProceed = this.shouldProceed();
7259
7669
  if (shouldProceed) {
7260
7670
  this.sendBatch().catch((e) => {
7261
- BStackLogger2.debug("Exception in sending batch: " + e);
7671
+ BStackLogger.debug("Exception in sending batch: " + e);
7262
7672
  });
7263
7673
  }
7264
7674
  }
7265
7675
  async shutdown() {
7266
- BStackLogger2.debug("shutdown started");
7676
+ BStackLogger.debug("shutdown started");
7267
7677
  this.removeEventBatchPolling("Shutting down");
7268
7678
  while (this.queue.length > 0) {
7269
7679
  const data = this.queue.splice(0, DATA_BATCH_SIZE);
7270
7680
  await this.callCallback(data, "SHUTDOWN_QUEUE");
7271
7681
  }
7272
- BStackLogger2.debug("shutdown ended");
7682
+ BStackLogger.debug("shutdown ended");
7273
7683
  }
7274
7684
  startEventBatchPolling() {
7275
7685
  this.pollEventBatchInterval = setInterval(this.sendBatch.bind(this), DATA_BATCH_INTERVAL);
@@ -7279,11 +7689,11 @@ var init_request_handler = __esm({
7279
7689
  if (data.length === 0) {
7280
7690
  return;
7281
7691
  }
7282
- BStackLogger2.debug(`Sending data from request queue. Data length = ${data.length}, Queue length after removal = ${this.queue.length}`);
7692
+ BStackLogger.debug(`Sending data from request queue. Data length = ${data.length}, Queue length after removal = ${this.queue.length}`);
7283
7693
  await this.callCallback(data, "INTERVAL_QUEUE");
7284
7694
  }
7285
7695
  callCallback = async (data, kind) => {
7286
- BStackLogger2.debug("calling callback with kind " + kind);
7696
+ BStackLogger.debug("calling callback with kind " + kind);
7287
7697
  await this.callback?.(data);
7288
7698
  };
7289
7699
  resetEventBatchPolling() {
@@ -7292,13 +7702,13 @@ var init_request_handler = __esm({
7292
7702
  }
7293
7703
  removeEventBatchPolling(tag) {
7294
7704
  if (this.pollEventBatchInterval) {
7295
- BStackLogger2.debug(`${tag} request queue`);
7705
+ BStackLogger.debug(`${tag} request queue`);
7296
7706
  clearInterval(this.pollEventBatchInterval);
7297
7707
  }
7298
7708
  }
7299
7709
  shouldProceed() {
7300
7710
  if (_RequestQueueHandler.tearDownInvoked) {
7301
- BStackLogger2.debug("Force request-queue shutdown, as test run event is received after teardown");
7711
+ BStackLogger.debug("Force request-queue shutdown, as test run event is received after teardown");
7302
7712
  return true;
7303
7713
  }
7304
7714
  return this.queue.length >= DATA_BATCH_SIZE;
@@ -7321,7 +7731,7 @@ async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
7321
7731
  throw new Error("Build start not completed yet");
7322
7732
  }
7323
7733
  if (!process.env[BROWSERSTACK_TESTHUB_JWT]) {
7324
- BStackLogger2.debug(`[${logTag}] Missing Authentication Token/ Build ID`);
7734
+ BStackLogger.debug(`[${logTag}] Missing Authentication Token/ Build ID`);
7325
7735
  throw new Error("Token/buildID is undefined, build creation might have failed");
7326
7736
  }
7327
7737
  try {
@@ -7334,9 +7744,9 @@ async function uploadEventData(eventData, eventUrl = DATA_EVENT_ENDPOINT) {
7334
7744
  },
7335
7745
  body: JSON.stringify(eventData)
7336
7746
  });
7337
- BStackLogger2.debug(`[${logTag}] Success response: ${JSON.stringify(await data.json())}`);
7747
+ BStackLogger.debug(`[${logTag}] Success response: ${JSON.stringify(await data.json())}`);
7338
7748
  } catch (error) {
7339
- BStackLogger2.debug(`[${logTag}] Failed. Error: ${format3(error)}`);
7749
+ BStackLogger.debug(`[${logTag}] Failed. Error: ${format3(error)}`);
7340
7750
  throw error;
7341
7751
  }
7342
7752
  }
@@ -7399,7 +7809,7 @@ var init_listener = __esm({
7399
7809
  await this.uploadPending();
7400
7810
  await this.teardown();
7401
7811
  } catch (e) {
7402
- BStackLogger2.debug("Exception in onWorkerEnd: " + e);
7812
+ BStackLogger.debug("Exception in onWorkerEnd: " + e);
7403
7813
  }
7404
7814
  }
7405
7815
  async uploadPending(waitTimeout = DEFAULT_WAIT_TIMEOUT_FOR_PENDING_UPLOADS, waitInterval = DEFAULT_WAIT_INTERVAL_FOR_PENDING_UPLOADS) {
@@ -7410,10 +7820,10 @@ var init_listener = __esm({
7410
7820
  return this.uploadPending(waitTimeout - waitInterval);
7411
7821
  }
7412
7822
  async teardown() {
7413
- BStackLogger2.debug("teardown started");
7823
+ BStackLogger.debug("teardown started");
7414
7824
  RequestQueueHandler.tearDownInvoked = true;
7415
7825
  await this.requestBatcher?.shutdown();
7416
- BStackLogger2.debug("teardown ended");
7826
+ BStackLogger.debug("teardown ended");
7417
7827
  }
7418
7828
  hookStarted(hookData) {
7419
7829
  try {
@@ -7521,7 +7931,7 @@ var init_listener = __esm({
7521
7931
  }
7522
7932
  markLogs(status, data) {
7523
7933
  if (!data) {
7524
- BStackLogger2.debug("No log data");
7934
+ BStackLogger.debug("No log data");
7525
7935
  return;
7526
7936
  }
7527
7937
  try {
@@ -7530,7 +7940,7 @@ var init_listener = __esm({
7530
7940
  this.logEvents.mark(status, LOG_KIND_USAGE_MAP[kind] || kind);
7531
7941
  }
7532
7942
  } catch (e) {
7533
- BStackLogger2.debug("Exception in marking logs status " + e);
7943
+ BStackLogger.debug("Exception in marking logs status " + e);
7534
7944
  throw e;
7535
7945
  }
7536
7946
  }
@@ -7548,14 +7958,14 @@ var init_listener = __esm({
7548
7958
  }
7549
7959
  if (!this.requestBatcher) {
7550
7960
  this.requestBatcher = RequestQueueHandler.getInstance(async (data) => {
7551
- BStackLogger2.debug("callback: called with events " + data.length);
7961
+ BStackLogger.debug("callback: called with events " + data.length);
7552
7962
  try {
7553
7963
  this.pendingUploads += 1;
7554
7964
  await batchAndPostEvents(DATA_BATCH_ENDPOINT, "BATCH_DATA", data);
7555
- BStackLogger2.debug("callback: marking events success " + data.length);
7965
+ BStackLogger.debug("callback: marking events success " + data.length);
7556
7966
  this.eventsSuccess(data);
7557
7967
  } catch {
7558
- BStackLogger2.debug("callback: marking events failed " + data.length);
7968
+ BStackLogger.debug("callback: marking events failed " + data.length);
7559
7969
  this.eventsFailed(data);
7560
7970
  } finally {
7561
7971
  this.pendingUploads -= 1;
@@ -7612,7 +8022,7 @@ var init_listener = __esm({
7612
8022
  });
7613
8023
 
7614
8024
  // src/reporter.ts
7615
- import path14 from "node:path";
8025
+ import path15 from "node:path";
7616
8026
  import WDIOReporter from "@wdio/reporter";
7617
8027
  import * as url from "node:url";
7618
8028
  import { v4 as uuidv43 } from "uuid";
@@ -7705,7 +8115,7 @@ var init_reporter = __esm({
7705
8115
  filename = this._suiteName || suiteStats.file;
7706
8116
  }
7707
8117
  } catch {
7708
- BStackLogger2.debug("Error in decoding file name of suite");
8118
+ BStackLogger.debug("Error in decoding file name of suite");
7709
8119
  }
7710
8120
  }
7711
8121
  this._suiteName = filename;
@@ -7835,9 +8245,9 @@ var init_reporter = __esm({
7835
8245
  scope,
7836
8246
  scopes,
7837
8247
  identifier,
7838
- file_name: suiteFileName ? path14.relative(process.cwd(), suiteFileName) : void 0,
7839
- location: suiteFileName ? path14.relative(process.cwd(), suiteFileName) : void 0,
7840
- vc_filepath: this._gitConfigPath && suiteFileName ? path14.relative(this._gitConfigPath, suiteFileName) : void 0,
8248
+ file_name: suiteFileName ? path15.relative(process.cwd(), suiteFileName) : void 0,
8249
+ location: suiteFileName ? path15.relative(process.cwd(), suiteFileName) : void 0,
8250
+ vc_filepath: this._gitConfigPath && suiteFileName ? path15.relative(this._gitConfigPath, suiteFileName) : void 0,
7841
8251
  started_at: testStats.start && testStats.start.toISOString(),
7842
8252
  finished_at: testStats.end && testStats.end.toISOString(),
7843
8253
  framework,
@@ -7850,13 +8260,15 @@ var init_reporter = __esm({
7850
8260
  if (eventType.startsWith("TestRun") || eventType === "HookRunStarted") {
7851
8261
  const cloudProvider = getCloudProvider({ options: { hostname: this._config?.hostname } });
7852
8262
  testData.integrations = {};
8263
+ const liveBrowserCaps = globalThis?.browser?.capabilities;
7853
8264
  testData.integrations[cloudProvider] = {
7854
8265
  capabilities: this._capabilities,
7855
8266
  session_id: this._sessionId,
7856
8267
  browser: this._capabilities?.browserName,
7857
8268
  browser_version: this._capabilities?.browserVersion,
7858
8269
  platform: this._capabilities?.platformName,
7859
- platform_version: getPlatformVersion(this._capabilities, this._userCaps)
8270
+ platform_version: getPlatformVersion(this._capabilities, this._userCaps),
8271
+ device: getResolvedDeviceName(liveBrowserCaps, this._userCaps)
7860
8272
  };
7861
8273
  }
7862
8274
  if (eventType === "TestRunFinished" || eventType === "HookRunFinished") {
@@ -7886,7 +8298,7 @@ var init_reporter = __esm({
7886
8298
  });
7887
8299
 
7888
8300
  // src/insights-handler.ts
7889
- import path15 from "node:path";
8301
+ import path16 from "node:path";
7890
8302
  import { v4 as uuidv44 } from "uuid";
7891
8303
  var _InsightsHandler, InsightsHandler, insights_handler_default;
7892
8304
  var init_insights_handler = __esm({
@@ -8166,9 +8578,9 @@ var init_insights_handler = __esm({
8166
8578
  test_run_id: hookData.testRunId,
8167
8579
  scope: feature?.name,
8168
8580
  scopes: [feature?.name || ""],
8169
- file_name: uri ? path15.relative(process.cwd(), uri) : void 0,
8170
- location: uri ? path15.relative(process.cwd(), uri) : void 0,
8171
- vc_filepath: this._gitConfigPath && uri ? path15.relative(this._gitConfigPath, uri) : void 0,
8581
+ file_name: uri ? path16.relative(process.cwd(), uri) : void 0,
8582
+ location: uri ? path16.relative(process.cwd(), uri) : void 0,
8583
+ vc_filepath: this._gitConfigPath && uri ? path16.relative(this._gitConfigPath, uri) : void 0,
8172
8584
  result: "pending",
8173
8585
  framework: this._framework
8174
8586
  };
@@ -8333,7 +8745,7 @@ var init_insights_handler = __esm({
8333
8745
  this.listener.logCreated([stdLog]);
8334
8746
  }
8335
8747
  } catch (error) {
8336
- BStackLogger2.debug(`Exception in uploading log data to Test Reporting and Analytics with error : ${error}`);
8748
+ BStackLogger.debug(`Exception in uploading log data to Test Reporting and Analytics with error : ${error}`);
8337
8749
  }
8338
8750
  };
8339
8751
  async browserCommand(commandType, args, test) {
@@ -8466,9 +8878,9 @@ var init_insights_handler = __esm({
8466
8878
  scope: fullTitle,
8467
8879
  scopes: this.getHierarchy(test),
8468
8880
  identifier: fullTitle,
8469
- file_name: filename ? path15.relative(process.cwd(), filename) : void 0,
8470
- location: filename ? path15.relative(process.cwd(), filename) : void 0,
8471
- vc_filepath: this._gitConfigPath && filename ? path15.relative(this._gitConfigPath, filename) : void 0,
8881
+ file_name: filename ? path16.relative(process.cwd(), filename) : void 0,
8882
+ location: filename ? path16.relative(process.cwd(), filename) : void 0,
8883
+ vc_filepath: this._gitConfigPath && filename ? path16.relative(this._gitConfigPath, filename) : void 0,
8472
8884
  started_at: testMetaData.startedAt,
8473
8885
  finished_at: testMetaData.finishedAt,
8474
8886
  result: "pending",
@@ -8578,9 +8990,9 @@ var init_insights_handler = __esm({
8578
8990
  scope: fullNameWithExamples,
8579
8991
  scopes: [feature?.name || ""],
8580
8992
  identifier: scenario?.name,
8581
- file_name: feature && feature.path ? path15.relative(process.cwd(), feature.path) : void 0,
8582
- location: feature && feature.path ? path15.relative(process.cwd(), feature.path) : void 0,
8583
- vc_filepath: this._gitConfigPath && feature?.path ? path15.relative(this._gitConfigPath, feature?.path) : void 0,
8993
+ file_name: feature && feature.path ? path16.relative(process.cwd(), feature.path) : void 0,
8994
+ location: feature && feature.path ? path16.relative(process.cwd(), feature.path) : void 0,
8995
+ vc_filepath: this._gitConfigPath && feature?.path ? path16.relative(this._gitConfigPath, feature?.path) : void 0,
8584
8996
  framework: this._framework,
8585
8997
  result: "pending",
8586
8998
  meta: {
@@ -8633,7 +9045,7 @@ var init_insights_handler = __esm({
8633
9045
  return testData;
8634
9046
  }
8635
9047
  async flushCBTDataQueue() {
8636
- BStackLogger2.debug(`Flushing CBT Data Queue ${this.currentTestId}`);
9048
+ BStackLogger.debug(`Flushing CBT Data Queue ${this.currentTestId}`);
8637
9049
  if (isUndefined(this.currentTestId)) {
8638
9050
  return;
8639
9051
  }
@@ -8653,7 +9065,7 @@ var init_insights_handler = __esm({
8653
9065
  uuid: "",
8654
9066
  integrations: integrationsData
8655
9067
  };
8656
- BStackLogger2.debug(`Sending CBT Data ${this.currentTestId} ${JSON.stringify(cbtData)}`);
9068
+ BStackLogger.debug(`Sending CBT Data ${this.currentTestId} ${JSON.stringify(cbtData)}`);
8657
9069
  if (this.currentTestId !== void 0) {
8658
9070
  cbtData.uuid = this.currentTestId;
8659
9071
  this.listener.cbtSessionCreated(cbtData);
@@ -8664,8 +9076,8 @@ var init_insights_handler = __esm({
8664
9076
  getIntegrationsObject() {
8665
9077
  const caps = this._browser?.capabilities;
8666
9078
  const sessionId = this._browser?.sessionId;
8667
- BStackLogger2.debug(`Driver capabilities used for integration object: ${JSON.stringify(caps)}`);
8668
- BStackLogger2.debug(`User capabilities used for integration object: ${JSON.stringify(this._userCaps)}`);
9079
+ BStackLogger.debug(`Driver capabilities used for integration object: ${JSON.stringify(caps)}`);
9080
+ BStackLogger.debug(`User capabilities used for integration object: ${JSON.stringify(this._userCaps)}`);
8669
9081
  return {
8670
9082
  capabilities: caps,
8671
9083
  session_id: sessionId,
@@ -8673,7 +9085,8 @@ var init_insights_handler = __esm({
8673
9085
  browser_version: caps?.browserVersion,
8674
9086
  platform: caps?.platformName,
8675
9087
  product: this._platformMeta?.product,
8676
- platform_version: getPlatformVersion(caps, this._userCaps)
9088
+ platform_version: getPlatformVersion(caps, this._userCaps),
9089
+ device: getResolvedDeviceName(caps, this._userCaps)
8677
9090
  };
8678
9091
  }
8679
9092
  getIdentifier(test) {
@@ -8966,7 +9379,7 @@ var init_percyModule = __esm({
8966
9379
  init_Percy_Handler();
8967
9380
  init_testFrameworkConstants();
8968
9381
  PercyModule = class _PercyModule extends BaseModule {
8969
- logger = BStackLogger;
9382
+ logger = BStackLogger2;
8970
9383
  browser;
8971
9384
  static MODULE_NAME = "PercyModule";
8972
9385
  percyHandler;
@@ -9087,7 +9500,7 @@ var init_cli = __esm({
9087
9500
  cliParams = null;
9088
9501
  automationFramework = null;
9089
9502
  SDK_CLI_BIN_PATH = null;
9090
- logger = BStackLogger;
9503
+ logger = BStackLogger2;
9091
9504
  options;
9092
9505
  constructor() {
9093
9506
  this.initialized = false;
@@ -9146,7 +9559,7 @@ var init_cli = __esm({
9146
9559
  const response = await GrpcClient.getInstance().startBinSession(this.wdioConfig);
9147
9560
  const redactedStartResponse = JSON.parse(JSON.stringify(response));
9148
9561
  CrashReporter.recursivelyRedactKeysFromObject(redactedStartResponse, ["user", "username", "key", "accesskey", "password"]);
9149
- BStackLogger.debug(`start: startBinSession response=${JSON.stringify(redactedStartResponse)}`);
9562
+ BStackLogger2.debug(`start: startBinSession response=${JSON.stringify(redactedStartResponse)}`);
9150
9563
  this.loadModules(response);
9151
9564
  this.isMainConnected = true;
9152
9565
  }
@@ -9158,6 +9571,7 @@ var init_cli = __esm({
9158
9571
  this.binSessionId = startBinResponse.binSessionId;
9159
9572
  this.logger.info(`loadModules: binSessionId=${this.binSessionId}`);
9160
9573
  this.setConfig(startBinResponse);
9574
+ this.logBuildErrors(startBinResponse);
9161
9575
  APIUtils.updateURLSForGRR(this.config.apis);
9162
9576
  this.setupTestFramework();
9163
9577
  this.setupAutomationFramework();
@@ -9193,6 +9607,28 @@ var init_cli = __esm({
9193
9607
  }
9194
9608
  this.configureModules();
9195
9609
  }
9610
+ /**
9611
+ * Log any build errors the binary reported via testhub.errors. The
9612
+ * field is a JSON-encoded { [errorKey]: { message, type } } map. Called
9613
+ * early in loadModules so the user sees the actionable cause (e.g.
9614
+ * invalid credentials) before any downstream bootstrap step that
9615
+ * depends on a fully populated config.
9616
+ */
9617
+ logBuildErrors(startBinResponse) {
9618
+ const rawErrors = startBinResponse.testhub?.errors;
9619
+ if (!rawErrors || !rawErrors.length) {
9620
+ return;
9621
+ }
9622
+ try {
9623
+ const errors = JSON.parse(Buffer.from(rawErrors).toString());
9624
+ for (const [code, detail] of Object.entries(errors)) {
9625
+ const { message } = detail;
9626
+ BStackLogger2.error(`[Build] ${code}: ${message}`);
9627
+ }
9628
+ } catch (e) {
9629
+ BStackLogger2.debug(`Failed to parse testhub errors: ${e}`);
9630
+ }
9631
+ }
9196
9632
  /**
9197
9633
  * Configure modules
9198
9634
  * @returns {Promise<void>}
@@ -9223,12 +9659,61 @@ var init_cli = __esm({
9223
9659
  return Promise.resolve();
9224
9660
  }
9225
9661
  const SDK_CLI_BIN_PATH = await this.getCliBinPath();
9662
+ if (!SDK_CLI_BIN_PATH) {
9663
+ throw new Error("Failed to get CLI binary path. CLI setup failed.");
9664
+ }
9226
9665
  const cmd = [SDK_CLI_BIN_PATH, "sdk"];
9227
9666
  this.logger.debug(`spawning command='${cmd}'`);
9228
- this.process = spawn3(cmd[0], cmd.slice(1), {
9229
- env: process.env
9230
- });
9667
+ for (let attempt = 1; attempt <= MAX_SPAWN_RETRIES; attempt++) {
9668
+ try {
9669
+ await this._spawnAndAwaitReady(cmd);
9670
+ if (attempt > 1) {
9671
+ this.logger.info(`Spawn succeeded on attempt ${attempt}/${MAX_SPAWN_RETRIES}`);
9672
+ }
9673
+ PerformanceTester.end(EVENTS.SDK_CLI_START);
9674
+ return;
9675
+ } catch (err) {
9676
+ const isBusy = BINARY_BUSY_ERROR_CODES.includes(err.code) || err.message && (err.message.toLowerCase().includes("text file busy") || err.message.toLowerCase().includes("being used by another process"));
9677
+ if (isBusy && attempt < MAX_SPAWN_RETRIES) {
9678
+ this.logger.warn(
9679
+ `Spawn attempt ${attempt}/${MAX_SPAWN_RETRIES} failed with busy error, retrying in ${SPAWN_RETRY_DELAY_MS}ms: ${err.message}`
9680
+ );
9681
+ if (this.process) {
9682
+ this.process.removeAllListeners();
9683
+ this.process.stdout?.removeAllListeners();
9684
+ this.process.stderr?.removeAllListeners();
9685
+ this.process = null;
9686
+ }
9687
+ await new Promise((r) => setTimeout(r, SPAWN_RETRY_DELAY_MS));
9688
+ } else {
9689
+ PerformanceTester.end(EVENTS.SDK_CLI_START, false, err);
9690
+ throw err;
9691
+ }
9692
+ }
9693
+ }
9694
+ }
9695
+ /**
9696
+ * Spawn the CLI process and wait until it emits "ready".
9697
+ * Handles both synchronous spawn errors and async error/close events.
9698
+ */
9699
+ _spawnAndAwaitReady(cmd) {
9231
9700
  return new Promise((resolve, reject) => {
9701
+ let settled = false;
9702
+ const settle = (fn, val) => {
9703
+ if (settled) {
9704
+ return;
9705
+ }
9706
+ settled = true;
9707
+ fn(val);
9708
+ };
9709
+ try {
9710
+ this.process = spawn3(cmd[0], cmd.slice(1), {
9711
+ env: process.env
9712
+ });
9713
+ } catch (syncErr) {
9714
+ settle(reject, syncErr);
9715
+ return;
9716
+ }
9232
9717
  const cliOut = {};
9233
9718
  this.process.stdout.on("data", (data) => {
9234
9719
  const lines = data.toString().trim().split("\n");
@@ -9241,8 +9726,7 @@ var init_cli = __esm({
9241
9726
  }
9242
9727
  if (line.toLowerCase().includes("ready")) {
9243
9728
  this.loadCliParams(cliOut);
9244
- PerformanceTester.end(EVENTS.SDK_CLI_START);
9245
- resolve();
9729
+ settle(resolve);
9246
9730
  return;
9247
9731
  }
9248
9732
  }
@@ -9251,14 +9735,11 @@ var init_cli = __esm({
9251
9735
  this.logger.error(`CLI stderr: ${data.toString().trim()}`);
9252
9736
  });
9253
9737
  this.process.on("error", (err) => {
9254
- cliOut.error = `Error in start: ${err.message}`;
9255
- PerformanceTester.end(EVENTS.SDK_CLI_START, false, err);
9256
- reject(new Error(`Failed to start CLI process: ${err.message}`));
9738
+ settle(reject, err);
9257
9739
  });
9258
9740
  this.process.on("close", (code) => {
9259
- if (code !== 0) {
9260
- reject(new Error(`CLI process exited with code ${code}`));
9261
- }
9741
+ const msg = code !== 0 ? `CLI process exited with code ${code}` : "CLI process exited cleanly before emitting ready";
9742
+ settle(reject, new Error(msg));
9262
9743
  });
9263
9744
  });
9264
9745
  }
@@ -9272,7 +9753,7 @@ var init_cli = __esm({
9272
9753
  try {
9273
9754
  if (this.isMainConnected) {
9274
9755
  const response = await GrpcClient.getInstance().stopBinSession();
9275
- BStackLogger.debug(`stop: stopBinSession response=${JSON.stringify(response)}`);
9756
+ BStackLogger2.debug(`stop: stopBinSession response=${JSON.stringify(response)}`);
9276
9757
  }
9277
9758
  await this.unConfigureModules();
9278
9759
  if (this.process && this.process.pid) {
@@ -9454,8 +9935,8 @@ var init_cli = __esm({
9454
9935
  });
9455
9936
 
9456
9937
  // src/testorchestration/helpers.ts
9457
- import os5 from "node:os";
9458
- import path18 from "node:path";
9938
+ import os6 from "node:os";
9939
+ import path19 from "node:path";
9459
9940
  import { spawnSync } from "node:child_process";
9460
9941
  import logger4 from "@wdio/logger";
9461
9942
  function isValidGitRef(ref) {
@@ -9481,11 +9962,11 @@ function safeGitCommand(args, cwd) {
9481
9962
  }
9482
9963
  function getHostInfo() {
9483
9964
  return {
9484
- hostname: os5.hostname(),
9965
+ hostname: os6.hostname(),
9485
9966
  platform: process.platform,
9486
9967
  architecture: process.arch,
9487
- release: os5.release(),
9488
- username: os5.userInfo().username
9968
+ release: os6.release(),
9969
+ username: os6.userInfo().username
9489
9970
  };
9490
9971
  }
9491
9972
  function isValidGitResult(result) {
@@ -9576,7 +10057,7 @@ function getGitMetadataForAISelection(folders = []) {
9576
10057
  if (folders === null) {
9577
10058
  folders = [process.cwd()];
9578
10059
  }
9579
- const uniqueFolders = [...new Set(folders.map((f) => path18.resolve(f)))];
10060
+ const uniqueFolders = [...new Set(folders.map((f) => path19.resolve(f)))];
9580
10061
  log4.debug(`Processing ${uniqueFolders.length} unique folders out of ${folders.length} total`);
9581
10062
  const results = [];
9582
10063
  for (const folder of uniqueFolders) {
@@ -9733,14 +10214,14 @@ var init_request_utils = __esm({
9733
10214
  * Makes a request to the test orchestration split tests endpoint
9734
10215
  */
9735
10216
  static async testOrchestrationSplitTests(reqEndpoint, data) {
9736
- BStackLogger2.debug("Processing Request for testOrchestrationSplitTests");
10217
+ BStackLogger.debug("Processing Request for testOrchestrationSplitTests");
9737
10218
  return _RequestUtils.makeOrchestrationRequest("POST", reqEndpoint, { data });
9738
10219
  }
9739
10220
  /**
9740
10221
  * Gets ordered tests from the test orchestration
9741
10222
  */
9742
10223
  static async getTestOrchestrationOrderedTests(reqEndpoint) {
9743
- BStackLogger2.debug("Processing Request for getTestOrchestrationOrderedTests");
10224
+ BStackLogger.debug("Processing Request for getTestOrchestrationOrderedTests");
9744
10225
  return _RequestUtils.makeOrchestrationRequest("GET", reqEndpoint, {});
9745
10226
  }
9746
10227
  /**
@@ -9777,13 +10258,13 @@ var init_request_utils = __esm({
9777
10258
  throw new Error(`Unsupported HTTP method: ${method}`);
9778
10259
  }
9779
10260
  const response = await fetchWrap(urlObject.toString(), requestInit);
9780
- BStackLogger2.debug(`Orchestration request made to URL: ${urlObject.toString()} with method: ${method}`);
10261
+ BStackLogger.debug(`Orchestration request made to URL: ${urlObject.toString()} with method: ${method}`);
9781
10262
  const rawBody = await response.text();
9782
10263
  let responseObj = rawBody;
9783
10264
  try {
9784
10265
  responseObj = rawBody ? JSON.parse(rawBody) : {};
9785
10266
  } catch (error) {
9786
- BStackLogger2.debug(`Failed to parse JSON response: ${error} - ${rawBody}`);
10267
+ BStackLogger.debug(`Failed to parse JSON response: ${error} - ${rawBody}`);
9787
10268
  }
9788
10269
  if (responseObj && typeof responseObj === "object" && !Array.isArray(responseObj)) {
9789
10270
  return {
@@ -9794,7 +10275,7 @@ var init_request_utils = __esm({
9794
10275
  }
9795
10276
  return typeof responseObj === "string" ? responseObj : rawBody;
9796
10277
  } catch (error) {
9797
- BStackLogger2.error(`Orchestration request failed: ${error} - ${url3}`);
10278
+ BStackLogger.error(`Orchestration request failed: ${error} - ${url3}`);
9798
10279
  return null;
9799
10280
  }
9800
10281
  }
@@ -9803,7 +10284,7 @@ var init_request_utils = __esm({
9803
10284
  });
9804
10285
 
9805
10286
  // src/testorchestration/test-ordering-server.ts
9806
- import path19 from "node:path";
10287
+ import path20 from "node:path";
9807
10288
  function isSplitTestsResponse(value) {
9808
10289
  return typeof value === "object" && value !== null;
9809
10290
  }
@@ -9837,7 +10318,7 @@ var init_test_ordering_server = __esm({
9837
10318
  * Initiates the split tests request and stores the response data for polling.
9838
10319
  */
9839
10320
  async splitTests(testFiles, orchestrationStrategy, orchestrationMetadata = "{}") {
9840
- BStackLogger2.debug(`[splitTests] Initiating split tests with strategy: ${orchestrationStrategy}`);
10321
+ BStackLogger.debug(`[splitTests] Initiating split tests with strategy: ${orchestrationStrategy}`);
9841
10322
  try {
9842
10323
  let prDetails = [];
9843
10324
  const parsedMetadata = JSON.parse(orchestrationMetadata);
@@ -9847,7 +10328,7 @@ var init_test_ordering_server = __esm({
9847
10328
  const multiRepoSource = parsedMetadata.run_smart_selection?.source;
9848
10329
  prDetails = getGitMetadataForAISelection(multiRepoSource);
9849
10330
  }
9850
- BStackLogger2.debug(`PR Details for AI Selection: ${JSON.stringify(prDetails)}`);
10331
+ BStackLogger.debug(`PR Details for AI Selection: ${JSON.stringify(prDetails)}`);
9851
10332
  const payload = {
9852
10333
  tests: testFiles.map((f) => ({ filePath: f })),
9853
10334
  orchestrationStrategy,
@@ -9855,23 +10336,23 @@ var init_test_ordering_server = __esm({
9855
10336
  nodeIndex: parseInt(process.env.BROWSERSTACK_NODE_INDEX || "0"),
9856
10337
  totalNodes: parseInt(process.env.BROWSERSTACK_TOTAL_NODE_COUNT || "1"),
9857
10338
  projectName: this.config.testObservabilityOptions?.projectName || "",
9858
- buildName: this.config.testObservabilityOptions?.buildName || path19.basename(process.cwd()),
10339
+ buildName: this.config.testObservabilityOptions?.buildName || path20.basename(process.cwd()),
9859
10340
  buildRunIdentifier: process.env.BROWSERSTACK_BUILD_RUN_IDENTIFIER || "",
9860
10341
  hostInfo: getHostInfo(),
9861
10342
  prDetails
9862
10343
  };
9863
- BStackLogger2.info(`[splitTests] Split tests payload: ${JSON.stringify(payload)}`);
10344
+ BStackLogger.info(`[splitTests] Split tests payload: ${JSON.stringify(payload)}`);
9864
10345
  const response = await RequestUtils.testOrchestrationSplitTests(this.ORDERING_ENDPOINT, payload);
9865
10346
  if (isSplitTestsResponse(response)) {
9866
10347
  this.requestData = this._processSplitTestsResponse(response);
9867
- BStackLogger2.debug(`[splitTests] Split tests response: ${JSON.stringify(this.requestData)}`);
10348
+ BStackLogger.debug(`[splitTests] Split tests response: ${JSON.stringify(this.requestData)}`);
9868
10349
  } else if (response) {
9869
- BStackLogger2.error("[splitTests] Received unexpected response format from split tests request.");
10350
+ BStackLogger.error("[splitTests] Received unexpected response format from split tests request.");
9870
10351
  } else {
9871
- BStackLogger2.error("[splitTests] Failed to get split tests response.");
10352
+ BStackLogger.error("[splitTests] Failed to get split tests response.");
9872
10353
  }
9873
10354
  } catch (error) {
9874
- BStackLogger2.error(`[splitTests] Exception in sending test files:: ${error}`);
10355
+ BStackLogger.error(`[splitTests] Exception in sending test files:: ${error}`);
9875
10356
  }
9876
10357
  }
9877
10358
  /**
@@ -9889,7 +10370,7 @@ var init_test_ordering_server = __esm({
9889
10370
  const resultUrl = normalizeUrl(response.resultUrl);
9890
10371
  const timeoutUrl = normalizeUrl(response.timeoutUrl);
9891
10372
  if (response.timeout === void 0 || response.timeoutInterval === void 0 || response.timeoutUrl === void 0 || response.resultUrl === void 0) {
9892
- BStackLogger2.debug("[process_split_tests_response] Received null value(s) for some attributes in split tests API response");
10373
+ BStackLogger.debug("[process_split_tests_response] Received null value(s) for some attributes in split tests API response");
9893
10374
  }
9894
10375
  return {
9895
10376
  timeout,
@@ -9903,7 +10384,7 @@ var init_test_ordering_server = __esm({
9903
10384
  */
9904
10385
  async getOrderedTestFiles() {
9905
10386
  if (!this.requestData) {
9906
- BStackLogger2.error("[getOrderedTestFiles] No request data available to fetch ordered test files.");
10387
+ BStackLogger.error("[getOrderedTestFiles] No request data available to fetch ordered test files.");
9907
10388
  return null;
9908
10389
  }
9909
10390
  let testFilesJsonList = null;
@@ -9927,10 +10408,10 @@ var init_test_ordering_server = __esm({
9927
10408
  break;
9928
10409
  }
9929
10410
  await new Promise((resolve) => setTimeout(resolve, timeoutInterval * 1e3));
9930
- BStackLogger2.debug(`[getOrderedTestFiles] Fetching ordered tests from result URL after waiting for ${timeoutInterval} seconds.`);
10411
+ BStackLogger.debug(`[getOrderedTestFiles] Fetching ordered tests from result URL after waiting for ${timeoutInterval} seconds.`);
9931
10412
  }
9932
10413
  if (timeoutUrl && !testFilesJsonList) {
9933
- BStackLogger2.debug("[getOrderedTestFiles] Fetching ordered tests from timeout URL");
10414
+ BStackLogger.debug("[getOrderedTestFiles] Fetching ordered tests from timeout URL");
9934
10415
  const response = await RequestUtils.getTestOrchestrationOrderedTests(timeoutUrl);
9935
10416
  if (isSplitTestsResponse(response) && Array.isArray(response.tests)) {
9936
10417
  testFilesJsonList = response.tests;
@@ -9947,10 +10428,10 @@ var init_test_ordering_server = __esm({
9947
10428
  if (!testFilesJsonList) {
9948
10429
  return null;
9949
10430
  }
9950
- BStackLogger2.debug(`[getOrderedTestFiles] Ordered test files received: ${JSON.stringify(testFiles)}`);
10431
+ BStackLogger.debug(`[getOrderedTestFiles] Ordered test files received: ${JSON.stringify(testFiles)}`);
9951
10432
  return testFiles;
9952
10433
  } catch (error) {
9953
- BStackLogger2.error(`[getOrderedTestFiles] Exception in fetching ordered test files: ${error}`);
10434
+ BStackLogger.error(`[getOrderedTestFiles] Exception in fetching ordered test files: ${error}`);
9954
10435
  return null;
9955
10436
  }
9956
10437
  }
@@ -10042,10 +10523,10 @@ var init_testorcherstrationhandler = __esm({
10042
10523
  return;
10043
10524
  }
10044
10525
  if (this.config.projectName === void 0 || this.config.buildName === void 0) {
10045
- BStackLogger2.info("Test Reordering can't work as buildName or projectName is null. Please set a non-null value.");
10526
+ BStackLogger.info("Test Reordering can't work as buildName or projectName is null. Please set a non-null value.");
10046
10527
  }
10047
10528
  if (!this._isObservabilityEnabled()) {
10048
- BStackLogger2.info("Test Reordering can't work as testReporting is disabled. Please enable it from browserstack.yml file.");
10529
+ BStackLogger.info("Test Reordering can't work as testReporting is disabled. Please enable it from browserstack.yml file.");
10049
10530
  }
10050
10531
  }
10051
10532
  /**
@@ -10054,7 +10535,7 @@ var init_testorcherstrationhandler = __esm({
10054
10535
  async reorderTestFiles(testFiles) {
10055
10536
  try {
10056
10537
  if (!testFiles || testFiles.length === 0) {
10057
- BStackLogger2.debug("[reorderTestFiles] No test files provided for ordering.");
10538
+ BStackLogger.debug("[reorderTestFiles] No test files provided for ordering.");
10058
10539
  return null;
10059
10540
  }
10060
10541
  let orchestrationStrategy = null;
@@ -10063,16 +10544,16 @@ var init_testorcherstrationhandler = __esm({
10063
10544
  orchestrationStrategy = this.orchestrationUtils.getTestOrderingName();
10064
10545
  }
10065
10546
  if (orchestrationStrategy === null) {
10066
- BStackLogger2.error("Orchestration strategy is None. Cannot proceed with test orchestration session.");
10547
+ BStackLogger.error("Orchestration strategy is None. Cannot proceed with test orchestration session.");
10067
10548
  return null;
10068
10549
  }
10069
- BStackLogger2.info(`Reordering test files with orchestration strategy: ${orchestrationStrategy}`);
10550
+ BStackLogger.info(`Reordering test files with orchestration strategy: ${orchestrationStrategy}`);
10070
10551
  let orderedTestFiles = [];
10071
10552
  if (BrowserstackCLI.getInstance().isRunning()) {
10072
- BStackLogger2.info("Using CLI flow for test files orchestration.");
10553
+ BStackLogger.info("Using CLI flow for test files orchestration.");
10073
10554
  orderedTestFiles = await GrpcClient.getInstance().testOrchestrationSession(testFiles, orchestrationStrategy, JSON.stringify(orchestrationMetadata)) || [];
10074
10555
  } else {
10075
- BStackLogger2.info("Using SDK flow for test files orchestration.");
10556
+ BStackLogger.info("Using SDK flow for test files orchestration.");
10076
10557
  await this.testOrderingServerHandler.splitTests(testFiles, orchestrationStrategy, JSON.stringify(orchestrationMetadata));
10077
10558
  orderedTestFiles = await this.testOrderingServerHandler.getOrderedTestFiles() || [];
10078
10559
  }
@@ -10083,7 +10564,7 @@ var init_testorcherstrationhandler = __esm({
10083
10564
  this.addToOrderingInstrumentationData("splitTestsAPICallCount", this.testOrderingServerHandler.getSplitTestsApiCallCount());
10084
10565
  return orderedTestFiles;
10085
10566
  } catch (error) {
10086
- BStackLogger2.debug(`[reorderTestFiles] Error in ordering test classes: ${error}`);
10567
+ BStackLogger.debug(`[reorderTestFiles] Error in ordering test classes: ${error}`);
10087
10568
  }
10088
10569
  return null;
10089
10570
  }
@@ -10113,22 +10594,22 @@ import { performance as performance3 } from "node:perf_hooks";
10113
10594
  async function applyOrchestrationIfEnabled(specs, config) {
10114
10595
  const orchestrationHandler = TestOrchestrationHandler.getInstance(config);
10115
10596
  if (!orchestrationHandler) {
10116
- BStackLogger2.debug("Orchestration handler is not initialized. Skipping orchestration.");
10597
+ BStackLogger.debug("Orchestration handler is not initialized. Skipping orchestration.");
10117
10598
  return specs;
10118
10599
  }
10119
10600
  const runSmartSelectionEnabled = isValidEnabledValue(config?.testOrchestrationOptions?.runSmartSelection?.enabled);
10120
10601
  if (!runSmartSelectionEnabled) {
10121
- BStackLogger2.info("runSmartSelection is not enabled in config. Skipping orchestration.");
10602
+ BStackLogger.info("runSmartSelection is not enabled in config. Skipping orchestration.");
10122
10603
  return specs;
10123
10604
  }
10124
10605
  orchestrationHandler.addToOrderingInstrumentationData("enabled", orchestrationHandler.testOrderingEnabled());
10125
10606
  const startTime = performance3.now();
10126
- BStackLogger2.info("Test orchestration is enabled. Attempting to reorder test files.");
10607
+ BStackLogger.info("Test orchestration is enabled. Attempting to reorder test files.");
10127
10608
  const testFiles = specs;
10128
- BStackLogger2.info(`Test files to be reordered: ${testFiles.join(", ")}`);
10609
+ BStackLogger.info(`Test files to be reordered: ${testFiles.join(", ")}`);
10129
10610
  const orderedFiles = await orchestrationHandler.reorderTestFiles(testFiles);
10130
10611
  if (orderedFiles && orderedFiles.length > 0) {
10131
- BStackLogger2.info(`Tests reordered using orchestration: ${orderedFiles.join(", ")}`);
10612
+ BStackLogger.info(`Tests reordered using orchestration: ${orderedFiles.join(", ")}`);
10132
10613
  orchestrationHandler.addToOrderingInstrumentationData(
10133
10614
  "timeTakenToApply",
10134
10615
  Math.floor(performance3.now() - startTime)
@@ -10136,7 +10617,7 @@ async function applyOrchestrationIfEnabled(specs, config) {
10136
10617
  );
10137
10618
  return orderedFiles;
10138
10619
  }
10139
- BStackLogger2.info("No test files were reordered by orchestration.");
10620
+ BStackLogger.info("No test files were reordered by orchestration.");
10140
10621
  orchestrationHandler.addToOrderingInstrumentationData(
10141
10622
  "timeTakenToApply",
10142
10623
  Math.floor(performance3.now() - startTime)
@@ -10158,12 +10639,12 @@ var init_apply_orchestration = __esm({
10158
10639
  // src/launcher.ts
10159
10640
  init_utils();
10160
10641
  init_testOpsConfig();
10161
- import fs14 from "node:fs";
10642
+ import fs15 from "node:fs";
10162
10643
  import { readFile } from "node:fs/promises";
10163
- import path20 from "node:path";
10644
+ import path21 from "node:path";
10164
10645
  import { promisify as promisify4, format as format4 } from "node:util";
10165
10646
  import { performance as performance4, PerformanceObserver as PerformanceObserver2 } from "node:perf_hooks";
10166
- import os6 from "node:os";
10647
+ import os7 from "node:os";
10167
10648
  import { SevereServiceError } from "webdriverio";
10168
10649
  import * as BrowserstackLocalLauncher from "browserstack-local";
10169
10650
 
@@ -10173,9 +10654,9 @@ init_PercyLogger();
10173
10654
  // src/Percy/Percy.ts
10174
10655
  init_util();
10175
10656
  init_PercyLogger();
10176
- import fs10 from "node:fs";
10177
- import path9 from "node:path";
10178
- import os3 from "node:os";
10657
+ import fs11 from "node:fs";
10658
+ import path10 from "node:path";
10659
+ import os4 from "node:os";
10179
10660
  import { spawn as spawn2 } from "node:child_process";
10180
10661
 
10181
10662
  // src/Percy/PercyBinary.ts
@@ -10185,20 +10666,20 @@ init_constants2();
10185
10666
  init_bstackLogger();
10186
10667
  init_fetchWrapper();
10187
10668
  import yauzl2 from "yauzl";
10188
- import fs9 from "node:fs";
10669
+ import fs10 from "node:fs";
10189
10670
  import fsp2 from "node:fs/promises";
10190
10671
  import { pipeline } from "node:stream/promises";
10191
- import path8 from "node:path";
10192
- import os2 from "node:os";
10672
+ import path9 from "node:path";
10673
+ import os3 from "node:os";
10193
10674
  import { spawn } from "node:child_process";
10194
10675
  var PercyBinary = class {
10195
10676
  #hostOS = process.platform;
10196
10677
  #httpPath = null;
10197
10678
  #binaryName = "percy";
10198
10679
  #orderedPaths = [
10199
- path8.join(os2.homedir(), ".browserstack"),
10680
+ path9.join(os3.homedir(), ".browserstack"),
10200
10681
  process.cwd(),
10201
- os2.tmpdir()
10682
+ os3.tmpdir()
10202
10683
  ];
10203
10684
  constructor() {
10204
10685
  const base = "https://github.com/percy/cli/releases/latest/download";
@@ -10211,15 +10692,15 @@ var PercyBinary = class {
10211
10692
  this.#httpPath = base + "/percy-linux.zip";
10212
10693
  }
10213
10694
  }
10214
- async #makePath(path21) {
10215
- if (await this.#checkPath(path21)) {
10695
+ async #makePath(path22) {
10696
+ if (await this.#checkPath(path22)) {
10216
10697
  return true;
10217
10698
  }
10218
- return fsp2.mkdir(path21).then(() => true).catch(() => false);
10699
+ return fsp2.mkdir(path22).then(() => true).catch(() => false);
10219
10700
  }
10220
- async #checkPath(path21) {
10701
+ async #checkPath(path22) {
10221
10702
  try {
10222
- const hasDir = await fsp2.access(path21).then(() => true, () => false);
10703
+ const hasDir = await fsp2.access(path22).then(() => true, () => false);
10223
10704
  if (hasDir) {
10224
10705
  return true;
10225
10706
  }
@@ -10229,7 +10710,7 @@ var PercyBinary = class {
10229
10710
  }
10230
10711
  // Get the path for storing the ETag
10231
10712
  #getETagPath(destParentDir) {
10232
- return path8.join(destParentDir, `${this.#binaryName}.etag`);
10713
+ return path9.join(destParentDir, `${this.#binaryName}.etag`);
10233
10714
  }
10234
10715
  // Load the stored ETag if it exists
10235
10716
  async #loadETag(destParentDir) {
@@ -10239,7 +10720,7 @@ var PercyBinary = class {
10239
10720
  const data = await fsp2.readFile(etagPath, "utf8");
10240
10721
  return data.trim();
10241
10722
  } catch (err) {
10242
- BStackLogger2.warn(`Failed to read ETag file ${err}`);
10723
+ BStackLogger.warn(`Failed to read ETag file ${err}`);
10243
10724
  }
10244
10725
  }
10245
10726
  return null;
@@ -10252,23 +10733,23 @@ var PercyBinary = class {
10252
10733
  try {
10253
10734
  const etagPath = this.#getETagPath(destParentDir);
10254
10735
  await fsp2.writeFile(etagPath, etag);
10255
- BStackLogger2.debug("Saved new ETag for percy binary");
10736
+ BStackLogger.debug("Saved new ETag for percy binary");
10256
10737
  } catch (err) {
10257
- BStackLogger2.error(`Failed to save ETag file ${err}`);
10738
+ BStackLogger.error(`Failed to save ETag file ${err}`);
10258
10739
  }
10259
10740
  }
10260
10741
  async #getAvailableDirs() {
10261
10742
  for (let i = 0; i < this.#orderedPaths.length; i++) {
10262
- const path21 = this.#orderedPaths[i];
10263
- if (await this.#makePath(path21)) {
10264
- return path21;
10743
+ const path22 = this.#orderedPaths[i];
10744
+ if (await this.#makePath(path22)) {
10745
+ return path22;
10265
10746
  }
10266
10747
  }
10267
10748
  throw new Error("Error trying to download percy binary");
10268
10749
  }
10269
10750
  async getBinaryPath() {
10270
10751
  const destParentDir = await this.#getAvailableDirs();
10271
- const binaryPath = path8.join(destParentDir, this.#binaryName);
10752
+ const binaryPath = path9.join(destParentDir, this.#binaryName);
10272
10753
  let response;
10273
10754
  if (await this.#checkPath(binaryPath)) {
10274
10755
  const currentETag = await this.#loadETag(destParentDir);
@@ -10276,13 +10757,13 @@ var PercyBinary = class {
10276
10757
  try {
10277
10758
  const result = await this.#checkForUpdate(currentETag);
10278
10759
  if (!result.needsUpdate) {
10279
- BStackLogger2.debug("Percy binary is up to date (ETag unchanged)");
10760
+ BStackLogger.debug("Percy binary is up to date (ETag unchanged)");
10280
10761
  return binaryPath;
10281
10762
  }
10282
10763
  response = result.response;
10283
- BStackLogger2.debug("New Percy binary version available, downloading update");
10764
+ BStackLogger.debug("New Percy binary version available, downloading update");
10284
10765
  } catch (err) {
10285
- BStackLogger2.warn(`Failed to check for binary updates, using existing binary ${err}`);
10766
+ BStackLogger.warn(`Failed to check for binary updates, using existing binary ${err}`);
10286
10767
  return binaryPath;
10287
10768
  }
10288
10769
  }
@@ -10310,11 +10791,11 @@ var PercyBinary = class {
10310
10791
  }
10311
10792
  const newETag = response.headers.get("eTag");
10312
10793
  if (newETag) {
10313
- await this.#saveETag(path8.dirname(this.#getETagPath(await this.#getAvailableDirs())), newETag);
10794
+ await this.#saveETag(path9.dirname(this.#getETagPath(await this.#getAvailableDirs())), newETag);
10314
10795
  }
10315
10796
  return { needsUpdate: true, response };
10316
10797
  } catch (error) {
10317
- BStackLogger2.warn(`Error checking for Percy binary updates: ${error}`);
10798
+ BStackLogger.warn(`Error checking for Percy binary updates: ${error}`);
10318
10799
  throw error;
10319
10800
  }
10320
10801
  }
@@ -10337,9 +10818,9 @@ var PercyBinary = class {
10337
10818
  await fsp2.mkdir(destParentDir);
10338
10819
  }
10339
10820
  const binaryName = this.#binaryName;
10340
- const zipFilePath = path8.join(destParentDir, binaryName + ".zip");
10341
- const binaryPath = path8.join(destParentDir, binaryName);
10342
- const downloadedFileStream = fs9.createWriteStream(zipFilePath);
10821
+ const zipFilePath = path9.join(destParentDir, binaryName + ".zip");
10822
+ const binaryPath = path9.join(destParentDir, binaryName);
10823
+ const downloadedFileStream = fs10.createWriteStream(zipFilePath);
10343
10824
  if (!response) {
10344
10825
  response = await _fetch(this.#httpPath);
10345
10826
  }
@@ -10358,8 +10839,8 @@ var PercyBinary = class {
10358
10839
  if (/\/$/.test(entry.fileName)) {
10359
10840
  zipfile.readEntry();
10360
10841
  } else {
10361
- const writeStream = fs9.createWriteStream(
10362
- path8.join(destParentDir, entry.fileName)
10842
+ const writeStream = fs10.createWriteStream(
10843
+ path9.join(destParentDir, entry.fileName)
10363
10844
  );
10364
10845
  zipfile.openReadStream(entry, function(zipErr, readStream) {
10365
10846
  if (zipErr) {
@@ -10380,7 +10861,7 @@ var PercyBinary = class {
10380
10861
  reject(zipErr);
10381
10862
  });
10382
10863
  zipfile.once("end", () => {
10383
- fs9.chmod(binaryPath, "0755", function(zipErr) {
10864
+ fs10.chmod(binaryPath, "0755", function(zipErr) {
10384
10865
  if (zipErr) {
10385
10866
  reject(zipErr);
10386
10867
  }
@@ -10404,7 +10885,7 @@ init_constants2();
10404
10885
  init_apiUtils();
10405
10886
  var logDir = "logs";
10406
10887
  var Percy = class {
10407
- #logfile = path9.join(logDir, "percy.log");
10888
+ #logfile = path10.join(logDir, "percy.log");
10408
10889
  #address = process.env.PERCY_SERVER_ADDRESS || "http://127.0.0.1:5338";
10409
10890
  #binaryPath = null;
10410
10891
  #options;
@@ -10445,7 +10926,7 @@ var Percy = class {
10445
10926
  }
10446
10927
  async start() {
10447
10928
  const binaryPath = await this.#getBinaryPath();
10448
- const logStream = fs10.createWriteStream(this.#logfile, { flags: "a" });
10929
+ const logStream = fs11.createWriteStream(this.#logfile, { flags: "a" });
10449
10930
  const token = await this.fetchPercyToken();
10450
10931
  const configPath = await this.createPercyConfig();
10451
10932
  if (!token) {
@@ -10532,13 +11013,13 @@ var Percy = class {
10532
11013
  if (!this.#options.percyOptions) {
10533
11014
  return null;
10534
11015
  }
10535
- const configPath = path9.join(os3.tmpdir(), "percy.json");
11016
+ const configPath = path10.join(os4.tmpdir(), "percy.json");
10536
11017
  const percyOptions = this.#options.percyOptions;
10537
11018
  if (!percyOptions.version) {
10538
11019
  percyOptions.version = "2";
10539
11020
  }
10540
11021
  return new Promise((resolve) => {
10541
- fs10.writeFile(
11022
+ fs11.writeFile(
10542
11023
  configPath,
10543
11024
  JSON.stringify(
10544
11025
  percyOptions
@@ -10632,6 +11113,7 @@ init_constants();
10632
11113
  init_util();
10633
11114
  init_crash_reporter();
10634
11115
  init_bstackLogger();
11116
+ init_caCert();
10635
11117
  init_PercyLogger();
10636
11118
 
10637
11119
  // src/config.ts
@@ -10639,10 +11121,62 @@ init_testOpsConfig();
10639
11121
  init_util();
10640
11122
  init_bstackLogger();
10641
11123
  import { v4 as uuidv4 } from "uuid";
11124
+ var APP_AUTOMATE_CAP_KEYS = ["appium:app", "appium:bundleId", "appium:appPackage", "appium:appActivity"];
11125
+ function hasAppCap(cap) {
11126
+ if (!cap || typeof cap !== "object") {
11127
+ return false;
11128
+ }
11129
+ const record = cap;
11130
+ if (APP_AUTOMATE_CAP_KEYS.some((key) => !isUndefined(record[key]))) {
11131
+ return true;
11132
+ }
11133
+ const appiumOptions = record["appium:options"];
11134
+ return !!(appiumOptions && !isUndefined(appiumOptions.app));
11135
+ }
11136
+ function detectAppAutomate(capabilities) {
11137
+ if (!capabilities) {
11138
+ return false;
11139
+ }
11140
+ const flat = [];
11141
+ if (Array.isArray(capabilities)) {
11142
+ for (const entry of capabilities) {
11143
+ if (!entry || typeof entry !== "object") {
11144
+ continue;
11145
+ }
11146
+ if ("alwaysMatch" in entry) {
11147
+ const w3c = entry;
11148
+ flat.push(w3c.alwaysMatch);
11149
+ if (Array.isArray(w3c.firstMatch)) {
11150
+ flat.push(...w3c.firstMatch);
11151
+ }
11152
+ continue;
11153
+ }
11154
+ const values = Object.values(entry);
11155
+ const isParallelMultiremote = values.length > 0 && values.every(
11156
+ (v) => v !== null && typeof v === "object" && v.capabilities
11157
+ );
11158
+ if (isParallelMultiremote) {
11159
+ for (const v of values) {
11160
+ flat.push(v.capabilities);
11161
+ }
11162
+ } else {
11163
+ flat.push(entry);
11164
+ }
11165
+ }
11166
+ } else {
11167
+ for (const v of Object.values(capabilities)) {
11168
+ const inner = v.capabilities;
11169
+ if (inner) {
11170
+ flat.push(inner);
11171
+ }
11172
+ }
11173
+ }
11174
+ return flat.some(hasAppCap);
11175
+ }
10642
11176
  var BrowserStackConfig = class _BrowserStackConfig {
10643
- static getInstance(options, config) {
11177
+ static getInstance(options, config, capabilities, isBrowserStackInfra) {
10644
11178
  if (!this._instance && options && config) {
10645
- this._instance = new _BrowserStackConfig(options, config);
11179
+ this._instance = new _BrowserStackConfig(options, config, capabilities, isBrowserStackInfra);
10646
11180
  }
10647
11181
  return this._instance;
10648
11182
  }
@@ -10663,19 +11197,19 @@ var BrowserStackConfig = class _BrowserStackConfig {
10663
11197
  percyBuildId;
10664
11198
  isPercyAutoEnabled = false;
10665
11199
  sdkRunID;
10666
- constructor(options, config) {
11200
+ constructor(options, config, capabilities, isBrowserStackInfra = true) {
10667
11201
  this.framework = config.framework;
10668
11202
  this.userName = config.user;
10669
11203
  this.accessKey = config.key;
10670
11204
  this.testObservability = new testOpsConfig_default(options.testObservability !== false, !isUndefined(options.testObservability));
10671
11205
  this.percy = options.percy || false;
10672
- this.accessibility = options.accessibility !== void 0 ? options.accessibility : null;
11206
+ this.accessibility = options.accessibility;
10673
11207
  this.app = options.app;
10674
- this.appAutomate = !isUndefined(options.app);
10675
- this.automate = !this.appAutomate;
11208
+ this.appAutomate = isBrowserStackInfra && (!isUndefined(options.app) || detectAppAutomate(capabilities));
11209
+ this.automate = isBrowserStackInfra && !this.appAutomate;
10676
11210
  this.buildIdentifier = options.buildIdentifier;
10677
11211
  this.sdkRunID = uuidv4();
10678
- BStackLogger2.info(`BrowserStack service started with id: ${this.sdkRunID}`);
11212
+ BStackLogger.info(`BrowserStack service started with id: ${this.sdkRunID}`);
10679
11213
  }
10680
11214
  sentFunnelData() {
10681
11215
  this.funnelDataSent = true;
@@ -10685,32 +11219,32 @@ var config_default = BrowserStackConfig;
10685
11219
 
10686
11220
  // src/exitHandler.ts
10687
11221
  import { spawn as spawn4 } from "node:child_process";
10688
- import path16 from "node:path";
11222
+ import path17 from "node:path";
10689
11223
 
10690
11224
  // src/instrumentation/funnelInstrumentation.ts
10691
11225
  init_usageStats();
10692
11226
  init_bstackLogger();
10693
11227
  init_constants();
10694
- import os4 from "node:os";
11228
+ import os5 from "node:os";
10695
11229
  import util4, { format as format2 } from "node:util";
10696
- import path11 from "node:path";
10697
- import fs12 from "node:fs";
11230
+ import path12 from "node:path";
11231
+ import fs13 from "node:fs";
10698
11232
 
10699
11233
  // src/data-store.ts
10700
11234
  init_bstackLogger();
10701
- import path10 from "node:path";
10702
- import fs11 from "node:fs";
10703
- var workersDataDirPath = path10.join(process.cwd(), "logs", "worker_data");
11235
+ import path11 from "node:path";
11236
+ import fs12 from "node:fs";
11237
+ var workersDataDirPath = path11.join(process.cwd(), "logs", "worker_data");
10704
11238
  function getDataFromWorkers() {
10705
11239
  const workersData = [];
10706
- if (!fs11.existsSync(workersDataDirPath)) {
11240
+ if (!fs12.existsSync(workersDataDirPath)) {
10707
11241
  return workersData;
10708
11242
  }
10709
- const files = fs11.readdirSync(workersDataDirPath);
11243
+ const files = fs12.readdirSync(workersDataDirPath);
10710
11244
  files.forEach((file) => {
10711
- BStackLogger2.debug("Reading worker file " + file);
10712
- const filePath = path10.join(workersDataDirPath, file);
10713
- const fileContent = fs11.readFileSync(filePath, "utf8");
11245
+ BStackLogger.debug("Reading worker file " + file);
11246
+ const filePath = path11.join(workersDataDirPath, file);
11247
+ const fileContent = fs12.readFileSync(filePath, "utf8");
10714
11248
  const workerData = JSON.parse(fileContent);
10715
11249
  workersData.push(workerData);
10716
11250
  });
@@ -10718,21 +11252,21 @@ function getDataFromWorkers() {
10718
11252
  return workersData;
10719
11253
  }
10720
11254
  function saveWorkerData(data) {
10721
- const filePath = path10.join(workersDataDirPath, "worker-data-" + process.pid + ".json");
11255
+ const filePath = path11.join(workersDataDirPath, "worker-data-" + process.pid + ".json");
10722
11256
  try {
10723
11257
  createWorkersDataDir();
10724
- fs11.writeFileSync(filePath, JSON.stringify(data));
11258
+ fs12.writeFileSync(filePath, JSON.stringify(data));
10725
11259
  } catch (e) {
10726
- BStackLogger2.debug("Exception in saving worker data: " + e);
11260
+ BStackLogger.debug("Exception in saving worker data: " + e);
10727
11261
  }
10728
11262
  }
10729
11263
  function removeWorkersDataDir() {
10730
- fs11.rmSync(workersDataDirPath, { recursive: true, force: true });
11264
+ fs12.rmSync(workersDataDirPath, { recursive: true, force: true });
10731
11265
  return true;
10732
11266
  }
10733
11267
  function createWorkersDataDir() {
10734
- if (!fs11.existsSync(workersDataDirPath)) {
10735
- fs11.mkdirSync(workersDataDirPath, { recursive: true });
11268
+ if (!fs12.existsSync(workersDataDirPath)) {
11269
+ fs12.mkdirSync(workersDataDirPath, { recursive: true });
10736
11270
  }
10737
11271
  return true;
10738
11272
  }
@@ -10746,16 +11280,16 @@ init_performance_tester();
10746
11280
  init_constants2();
10747
11281
  async function fireFunnelTestEvent(eventType, config, isCLIEnabled = false) {
10748
11282
  if (!config.userName || !config.accessKey) {
10749
- BStackLogger2.debug("username/accesskey not passed");
11283
+ BStackLogger.debug("username/accesskey not passed");
10750
11284
  return;
10751
11285
  }
10752
11286
  try {
10753
11287
  const data = buildEventData(eventType, config, isCLIEnabled);
10754
11288
  await fireFunnelRequest(data);
10755
- BStackLogger2.debug("Funnel event success");
11289
+ BStackLogger.debug("Funnel event success");
10756
11290
  config.sentFunnelData();
10757
11291
  } catch (error) {
10758
- BStackLogger2.debug(`Exception in sending funnel data: ${format2(error)}`);
11292
+ BStackLogger.debug(`Exception in sending funnel data: ${format2(error)}`);
10759
11293
  }
10760
11294
  }
10761
11295
  async function sendStart(config) {
@@ -10780,9 +11314,9 @@ async function sendFinish(config, isCLIEnabled = false) {
10780
11314
  }
10781
11315
  function saveFunnelData(eventType, config, isCLIEnabled = false) {
10782
11316
  const data = buildEventData(eventType, config, isCLIEnabled);
10783
- BStackLogger2.ensureLogsFolder();
10784
- const filePath = path11.join(BStackLogger2.logFolderPath, "funnelData.json");
10785
- fs12.writeFileSync(filePath, JSON.stringify(data));
11317
+ BStackLogger.ensureLogsFolder();
11318
+ const filePath = path12.join(BStackLogger.logFolderPath, "funnelData.json");
11319
+ fs13.writeFileSync(filePath, JSON.stringify(data));
10786
11320
  return filePath;
10787
11321
  }
10788
11322
  function redactCredentialsFromFunnelData(data) {
@@ -10799,7 +11333,7 @@ function redactCredentialsFromFunnelData(data) {
10799
11333
  async function fireFunnelRequest(data) {
10800
11334
  const { userName, accessKey } = data;
10801
11335
  redactCredentialsFromFunnelData(data);
10802
- BStackLogger2.debug("Sending SDK event with data " + util4.inspect(data, { depth: 6 }));
11336
+ BStackLogger.debug("Sending SDK event with data " + util4.inspect(data, { depth: 6 }));
10803
11337
  const encodedAuth = Buffer.from(`${userName}:${accessKey}`, "utf8").toString("base64");
10804
11338
  const response = await fetchWrap(APIUtils.FUNNEL_INSTRUMENTATION_URL, {
10805
11339
  method: "POST",
@@ -10809,7 +11343,7 @@ async function fireFunnelRequest(data) {
10809
11343
  },
10810
11344
  body: JSON.stringify(data)
10811
11345
  });
10812
- BStackLogger2.debug("Funnel Event Response: " + JSON.stringify(await response.text()));
11346
+ BStackLogger.debug("Funnel Event Response: " + JSON.stringify(await response.text()));
10813
11347
  }
10814
11348
  function getProductList(config) {
10815
11349
  const products = [];
@@ -10843,8 +11377,8 @@ function buildEventData(eventType, config, isCLIEnabled = false) {
10843
11377
  buildName: config.buildName || "undefined",
10844
11378
  buildIdentifier: String(config.buildIdentifier),
10845
11379
  // Host details
10846
- os: os4.type() || "unknown",
10847
- hostname: os4.hostname() || "unknown",
11380
+ os: os5.type() || "unknown",
11381
+ hostname: os5.hostname() || "unknown",
10848
11382
  // Product Details
10849
11383
  productMap: getProductMap(config),
10850
11384
  product: getProductList(config),
@@ -10894,30 +11428,30 @@ function isProxyError(authResult) {
10894
11428
  function handleProxyError(config, isSelfHealEnabled) {
10895
11429
  sendEvent.tcgProxyFailure(config);
10896
11430
  if (isSelfHealEnabled) {
10897
- BStackLogger2.warn("Proxy Error. Disabling Healing for this session.");
11431
+ BStackLogger.warn("Proxy Error. Disabling Healing for this session.");
10898
11432
  }
10899
11433
  }
10900
11434
  function handleUpgradeRequired(isSelfHealEnabled) {
10901
11435
  if (isSelfHealEnabled) {
10902
- BStackLogger2.warn("Please upgrade Browserstack Service to the latest version to use the self-healing feature.");
11436
+ BStackLogger.warn("Please upgrade Browserstack Service to the latest version to use the self-healing feature.");
10903
11437
  }
10904
11438
  }
10905
11439
  function handleAuthenticationFailure(status, config, isSelfHealEnabled) {
10906
11440
  if (status >= 500) {
10907
11441
  if (isSelfHealEnabled) {
10908
- BStackLogger2.warn("Something went wrong. Disabling healing for this session. Please try again later.");
11442
+ BStackLogger.warn("Something went wrong. Disabling healing for this session. Please try again later.");
10909
11443
  }
10910
11444
  sendEvent.tcgDown(config);
10911
11445
  } else {
10912
11446
  if (isSelfHealEnabled) {
10913
- BStackLogger2.warn("Authentication Failed. Disabling Healing for this session.");
11447
+ BStackLogger.warn("Authentication Failed. Disabling Healing for this session.");
10914
11448
  }
10915
11449
  sendEvent.tcgAuthFailure(config);
10916
11450
  }
10917
11451
  }
10918
11452
  function handleAuthenticationSuccess(isHealingEnabledForUser, userId, config, isSelfHealEnabled) {
10919
11453
  if (!isHealingEnabledForUser && isSelfHealEnabled) {
10920
- BStackLogger2.warn("Healing is not enabled for your group, please contact the admin");
11454
+ BStackLogger.warn("Healing is not enabled for your group, please contact the admin");
10921
11455
  } else if (userId && isHealingEnabledForUser) {
10922
11456
  sendEvent.tcgtInitSuccessful(config);
10923
11457
  }
@@ -10929,7 +11463,7 @@ function handleInitializationFailure(status, config, isSelfHealEnabled) {
10929
11463
  sendEvent.invalidTcgAuth(config);
10930
11464
  }
10931
11465
  if (isSelfHealEnabled) {
10932
- BStackLogger2.warn("Authentication Failed. Healing will be disabled for this session.");
11466
+ BStackLogger.warn("Authentication Failed. Healing will be disabled for this session.");
10933
11467
  }
10934
11468
  }
10935
11469
  function handleHealingInstrumentation(authResult, config, isSelfHealEnabled) {
@@ -10956,7 +11490,7 @@ function handleHealingInstrumentation(authResult, config, isSelfHealEnabled) {
10956
11490
  return;
10957
11491
  }
10958
11492
  } catch (err) {
10959
- BStackLogger2.debug("Error in handling healing instrumentation: " + err);
11493
+ BStackLogger.debug("Error in handling healing instrumentation: " + err);
10960
11494
  }
10961
11495
  }
10962
11496
 
@@ -10968,36 +11502,36 @@ init_bstackLogger();
10968
11502
  init_cli();
10969
11503
  import { fileURLToPath as fileURLToPath2 } from "node:url";
10970
11504
  var __filename = fileURLToPath2(import.meta.url);
10971
- var __dirname = path16.dirname(__filename);
11505
+ var __dirname = path17.dirname(__filename);
10972
11506
  function setupExitHandlers() {
10973
11507
  const handleCLICleanup = () => {
10974
- BStackLogger2.debug("Handling CLI cleanup in exit handler");
11508
+ BStackLogger.debug("Handling CLI cleanup in exit handler");
10975
11509
  try {
10976
11510
  const cliProcess = BrowserstackCLI.getInstance()?.process;
10977
11511
  if (cliProcess && cliProcess.pid && cliProcess.exitCode === null) {
10978
- BStackLogger2.debug(`Found CLI process with PID ${cliProcess.pid}, terminating`);
11512
+ BStackLogger.debug(`Found CLI process with PID ${cliProcess.pid}, terminating`);
10979
11513
  try {
10980
11514
  if (process.platform === "win32") {
10981
11515
  cliProcess.kill("SIGTERM");
10982
- BStackLogger2.debug("CLI process terminated successfully with SIGTERM (Windows)");
11516
+ BStackLogger.debug("CLI process terminated successfully with SIGTERM (Windows)");
10983
11517
  } else {
10984
11518
  cliProcess.kill("SIGINT");
10985
- BStackLogger2.debug("CLI process terminated successfully with SIGINT (Unix)");
11519
+ BStackLogger.debug("CLI process terminated successfully with SIGINT (Unix)");
10986
11520
  }
10987
11521
  } catch (processError2) {
10988
- BStackLogger2.debug(`CLI process termination error: ${processError2}`);
11522
+ BStackLogger.debug(`CLI process termination error: ${processError2}`);
10989
11523
  try {
10990
11524
  cliProcess.kill();
10991
- BStackLogger2.debug("CLI process terminated with default signal (fallback)");
11525
+ BStackLogger.debug("CLI process terminated with default signal (fallback)");
10992
11526
  } catch (fallbackError) {
10993
- BStackLogger2.debug(`CLI process fallback termination error: ${fallbackError}`);
11527
+ BStackLogger.debug(`CLI process fallback termination error: ${fallbackError}`);
10994
11528
  }
10995
11529
  }
10996
11530
  } else {
10997
- BStackLogger2.debug("No CLI process found to terminate");
11531
+ BStackLogger.debug("No CLI process found to terminate");
10998
11532
  }
10999
11533
  } catch (error) {
11000
- BStackLogger2.debug(`Error in CLI cleanup: ${error}`);
11534
+ BStackLogger.debug(`Error in CLI cleanup: ${error}`);
11001
11535
  }
11002
11536
  };
11003
11537
  process.on("exit", () => {
@@ -11005,8 +11539,8 @@ function setupExitHandlers() {
11005
11539
  handleCLICleanup();
11006
11540
  const args = shouldCallCleanup(config_default.getInstance(), isCLIEnabled);
11007
11541
  if (Array.isArray(args) && args.length) {
11008
- BStackLogger2.debug(`Spawning cleanup.js with args: ${args.join(", ")}`);
11009
- const childProcess = spawn4("node", [`${path16.join(__dirname, "cleanup.js")}`, ...args], { detached: true, stdio: "inherit", env: { ...process.env } });
11542
+ BStackLogger.debug(`Spawning cleanup.js with args: ${args.join(", ")}`);
11543
+ const childProcess = spawn4("node", [`${path17.join(__dirname, "cleanup.js")}`, ...args], { detached: true, stdio: "inherit", env: { ...process.env } });
11010
11544
  childProcess.unref();
11011
11545
  }
11012
11546
  });
@@ -11032,8 +11566,8 @@ function shouldCallCleanup(config, isCLIEnabled = false) {
11032
11566
  // src/ai-handler.ts
11033
11567
  init_bstackLogger();
11034
11568
  init_constants();
11035
- import path17 from "node:path";
11036
- import fs13 from "node:fs";
11569
+ import path18 from "node:path";
11570
+ import fs14 from "node:fs";
11037
11571
  import url2 from "node:url";
11038
11572
  import aiSDK from "@browserstack/ai-sdk-node";
11039
11573
  init_util();
@@ -11060,7 +11594,7 @@ var AiHandler = class {
11060
11594
  }
11061
11595
  } else if (options.selfHeal === true) {
11062
11596
  const healingWarnMessage = authResult.message;
11063
- BStackLogger2.warn(`Healing Auth failed. Disabling healing for this session. Reason: ${healingWarnMessage}`);
11597
+ BStackLogger.warn(`Healing Auth failed. Disabling healing for this session. Reason: ${healingWarnMessage}`);
11064
11598
  }
11065
11599
  return caps;
11066
11600
  }
@@ -11069,8 +11603,8 @@ var AiHandler = class {
11069
11603
  }
11070
11604
  async installFirefoxExtension(browser) {
11071
11605
  const __dirname2 = url2.fileURLToPath(new URL(".", import.meta.url));
11072
- const extensionPath = path17.resolve(__dirname2, aiSDK.BrowserstackHealing.getFirefoxAddonPath());
11073
- const extFile = fs13.readFileSync(extensionPath);
11606
+ const extensionPath = path18.resolve(__dirname2, aiSDK.BrowserstackHealing.getFirefoxAddonPath());
11607
+ const extFile = fs14.readFileSync(extensionPath);
11074
11608
  await browser.installAddOn(extFile.toString("base64"), true);
11075
11609
  }
11076
11610
  async handleHealing(orginalFunc, using, value, browser, options) {
@@ -11097,7 +11631,7 @@ var AiHandler = class {
11097
11631
  return result;
11098
11632
  }
11099
11633
  if (options.selfHeal === true && this.authResult.isHealingEnabled) {
11100
- BStackLogger2.info("findElement failed, trying to heal");
11634
+ BStackLogger.info("findElement failed, trying to heal");
11101
11635
  PerformanceTester.start(AI_EVENTS.SELF_HEAL_STEP);
11102
11636
  const script = await aiSDK.BrowserstackHealing.healFailure(locatorType, locatorValue, void 0, void 0, this.authResult.userId, this.authResult.groupId, sessionId, void 0, void 0, this.authResult.isGroupAIEnabled, tcgDetails);
11103
11637
  if (script) {
@@ -11107,7 +11641,7 @@ var AiHandler = class {
11107
11641
  PerformanceTester.end(AI_EVENTS.SELF_HEAL_GET_RESULT);
11108
11642
  if (tcgData && tcgData.selector && tcgData.value) {
11109
11643
  const healedResult = await orginalFunc(tcgData.selector, tcgData.value);
11110
- BStackLogger2.info("Healing worked, element found: " + tcgData.selector + ": " + tcgData.value);
11644
+ BStackLogger.info("Healing worked, element found: " + tcgData.selector + ": " + tcgData.value);
11111
11645
  PerformanceTester.end(AI_EVENTS.SELF_HEAL_STEP);
11112
11646
  return healedResult.error ? result : healedResult;
11113
11647
  }
@@ -11119,9 +11653,9 @@ var AiHandler = class {
11119
11653
  } catch (err) {
11120
11654
  PerformanceTester.end(AI_EVENTS.SELF_HEAL_STEP, false, String(err));
11121
11655
  if (options.selfHeal === true) {
11122
- BStackLogger2.warn("Something went wrong while healing. Disabling healing for this command");
11656
+ BStackLogger.warn("Something went wrong while healing. Disabling healing for this command");
11123
11657
  } else {
11124
- BStackLogger2.warn("Error in findElement: " + err + "using: " + using + "value: " + value);
11658
+ BStackLogger.warn("Error in findElement: " + err + "using: " + using + "value: " + value);
11125
11659
  }
11126
11660
  }
11127
11661
  return await orginalFunc(using, value);
@@ -11157,7 +11691,7 @@ var AiHandler = class {
11157
11691
  }
11158
11692
  } catch (err) {
11159
11693
  if (options.selfHeal === true) {
11160
- BStackLogger2.warn(`Error while initiliazing Browserstack healing Extension ${err}`);
11694
+ BStackLogger.warn(`Error while initiliazing Browserstack healing Extension ${err}`);
11161
11695
  }
11162
11696
  }
11163
11697
  return caps;
@@ -11166,7 +11700,7 @@ var AiHandler = class {
11166
11700
  if (SUPPORTED_BROWSERS_FOR_AI.includes(browser.capabilities?.browserName?.toLowerCase())) {
11167
11701
  const authInfo = this.authResult;
11168
11702
  if (Object.keys(authInfo).length === 0 && options.selfHeal === true) {
11169
- BStackLogger2.debug("TCG Auth result is empty");
11703
+ BStackLogger.debug("TCG Auth result is empty");
11170
11704
  return;
11171
11705
  }
11172
11706
  const { isAuthenticated, sessionToken, defaultLogDataEnabled } = authInfo;
@@ -11194,7 +11728,7 @@ var AiHandler = class {
11194
11728
  }
11195
11729
  } catch (err) {
11196
11730
  if (options.selfHeal === true) {
11197
- BStackLogger2.warn(`Error while setting up self-healing: ${err}. Disabling healing for this session.`);
11731
+ BStackLogger.warn(`Error while setting up self-healing: ${err}. Disabling healing for this session.`);
11198
11732
  }
11199
11733
  }
11200
11734
  }
@@ -11212,9 +11746,10 @@ var BrowserstackLauncherService = class {
11212
11746
  constructor(_options, capabilities, _config) {
11213
11747
  this._options = _options;
11214
11748
  this._config = _config;
11215
- BStackLogger2.clearLogFile();
11749
+ BStackLogger.clearLogFile();
11216
11750
  PercyLogger.clearLogFile();
11217
11751
  setupExitHandlers();
11752
+ configureCaCertificate(this._options);
11218
11753
  if (!this._config) {
11219
11754
  this._config = _options;
11220
11755
  }
@@ -11236,12 +11771,13 @@ var BrowserstackLauncherService = class {
11236
11771
  if (!isUndefined(process.env.TEST_REPORTING_BUILD_TAG)) {
11237
11772
  process.env.TEST_OBSERVABILITY_BUILD_TAG = process.env.TEST_REPORTING_BUILD_TAG;
11238
11773
  }
11239
- this.browserStackConfig = config_default.getInstance(_options, _config);
11240
- BStackLogger2.debug(`_options data: ${JSON.stringify(_options)}`);
11241
- BStackLogger2.debug(`webdriver capabilities data: ${JSON.stringify(capabilities)}`);
11774
+ const isBrowserStackInfra = isBrowserstackInfra(_config, capabilities);
11775
+ this.browserStackConfig = config_default.getInstance(_options, _config, capabilities, isBrowserStackInfra);
11776
+ BStackLogger.debug(`_options data: ${JSON.stringify(_options)}`);
11777
+ BStackLogger.debug(`webdriver capabilities data: ${JSON.stringify(capabilities)}`);
11242
11778
  const configCopy = JSON.parse(JSON.stringify(_config));
11243
11779
  CrashReporter.recursivelyRedactKeysFromObject(configCopy, ["user", "username", "key", "accesskey", "password"]);
11244
- BStackLogger2.debug(`_config data: ${JSON.stringify(configCopy)}`);
11780
+ BStackLogger.debug(`_config data: ${JSON.stringify(configCopy)}`);
11245
11781
  if (Array.isArray(capabilities)) {
11246
11782
  capabilities.flatMap((c) => {
11247
11783
  if ("alwaysMatch" in c) {
@@ -11328,7 +11864,7 @@ var BrowserstackLauncherService = class {
11328
11864
  try {
11329
11865
  CrashReporter.setConfigDetails(this._config, capabilities, this._options);
11330
11866
  } catch (error) {
11331
- BStackLogger2.error(`[Crash_Report_Upload] Config processing failed due to ${error}`);
11867
+ BStackLogger.error(`[Crash_Report_Upload] Config processing failed due to ${error}`);
11332
11868
  }
11333
11869
  }
11334
11870
  browserstackLocal;
@@ -11336,7 +11872,7 @@ var BrowserstackLauncherService = class {
11336
11872
  _projectName;
11337
11873
  _buildTag;
11338
11874
  _buildIdentifier;
11339
- _accessibilityAutomation = null;
11875
+ _accessibilityAutomation;
11340
11876
  _percy;
11341
11877
  _percyBestPlatformCaps;
11342
11878
  browserStackConfig;
@@ -11358,7 +11894,7 @@ var BrowserstackLauncherService = class {
11358
11894
  if (config.specs && Array.isArray(config.specs) && isValidEnabledValue(this._options.testOrchestrationOptions?.runSmartSelection?.enabled)) {
11359
11895
  try {
11360
11896
  const glob = (await import("glob")).sync;
11361
- const path21 = await import("node:path");
11897
+ const path22 = await import("node:path");
11362
11898
  const expandedSpecs = [];
11363
11899
  for (const specPattern of config.specs) {
11364
11900
  if (typeof specPattern === "string") {
@@ -11375,21 +11911,21 @@ var BrowserstackLauncherService = class {
11375
11911
  }) || [];
11376
11912
  filenames.forEach((filename) => {
11377
11913
  let absolutePath = filename;
11378
- if (!path21.isAbsolute(filename)) {
11379
- absolutePath = path21.resolve(rootDir, filename);
11914
+ if (!path22.isAbsolute(filename)) {
11915
+ absolutePath = path22.resolve(rootDir, filename);
11380
11916
  }
11381
- let relativePath = path21.relative(cwd, absolutePath);
11917
+ let relativePath = path22.relative(cwd, absolutePath);
11382
11918
  relativePath = relativePath.replace(/\\/g, "/");
11383
11919
  expandedSpecs.push(relativePath);
11384
11920
  });
11385
11921
  }
11386
11922
  }
11387
11923
  if (expandedSpecs.length > 0) {
11388
- BStackLogger2.info(`Expanded specs from glob patterns to ${expandedSpecs.length} files`);
11924
+ BStackLogger.info(`Expanded specs from glob patterns to ${expandedSpecs.length} files`);
11389
11925
  config.specs = expandedSpecs;
11390
11926
  }
11391
11927
  } catch (error) {
11392
- BStackLogger2.error(`Failed to expand spec patterns: ${error}`);
11928
+ BStackLogger.error(`Failed to expand spec patterns: ${error}`);
11393
11929
  }
11394
11930
  }
11395
11931
  try {
@@ -11400,11 +11936,11 @@ var BrowserstackLauncherService = class {
11400
11936
  CLIUtils.setFrameworkDetail(WDIO_NAMING_PREFIX + config.framework, "WebdriverIO");
11401
11937
  const binconfig = CLIUtils.getBinConfig(config, capabilities, this._options, this._buildTag);
11402
11938
  await BrowserstackCLI.getInstance().bootstrap(this._options, config, binconfig);
11403
- BStackLogger2.debug(`Is CLI running ${BrowserstackCLI.getInstance().isRunning()}`);
11939
+ BStackLogger.debug(`Is CLI running ${BrowserstackCLI.getInstance().isRunning()}`);
11404
11940
  PerformanceTester.end(FRAMEWORK_EVENTS.START);
11405
11941
  }
11406
11942
  } catch (err) {
11407
- BStackLogger2.error(`Error while starting CLI ${err}`);
11943
+ BStackLogger.error(`Error while starting CLI ${err}`);
11408
11944
  PerformanceTester.end(FRAMEWORK_EVENTS.START, false, format4(err));
11409
11945
  }
11410
11946
  PerformanceTester.end(FRAMEWORK_EVENTS.INIT);
@@ -11423,13 +11959,13 @@ var BrowserstackLauncherService = class {
11423
11959
  }
11424
11960
  } catch (err) {
11425
11961
  if (this._options.selfHeal === true) {
11426
- BStackLogger2.warn(`Error while setting up Browserstack healing Extension ${err}. Disabling healing for this session.`);
11962
+ BStackLogger.warn(`Error while setting up Browserstack healing Extension ${err}. Disabling healing for this session.`);
11427
11963
  }
11428
11964
  }
11429
11965
  }
11430
11966
  if (!BrowserstackCLI.getInstance().isRunning()) {
11431
11967
  if (!this._options.app) {
11432
- BStackLogger2.debug("app is not defined in browserstack-service config, skipping ...");
11968
+ BStackLogger.debug("app is not defined in browserstack-service config, skipping ...");
11433
11969
  } else {
11434
11970
  let app = {};
11435
11971
  const appConfig = this._options.app;
@@ -11438,10 +11974,10 @@ var BrowserstackLauncherService = class {
11438
11974
  } catch (error) {
11439
11975
  throw new SevereServiceError(error.message);
11440
11976
  }
11441
- if (VALID_APP_EXTENSION.includes(path20.extname(app.app))) {
11442
- if (fs14.existsSync(app.app)) {
11977
+ if (VALID_APP_EXTENSION.includes(path21.extname(app.app))) {
11978
+ if (fs15.existsSync(app.app)) {
11443
11979
  const data = await this._uploadApp(app);
11444
- BStackLogger2.info(`app upload completed: ${JSON.stringify(data)}`);
11980
+ BStackLogger.info(`app upload completed: ${JSON.stringify(data)}`);
11445
11981
  app.app = data.app_url;
11446
11982
  } else if (app.customId) {
11447
11983
  app.app = app.customId;
@@ -11449,7 +11985,7 @@ var BrowserstackLauncherService = class {
11449
11985
  throw new SevereServiceError(`[Invalid app path] app path ${app.app} is not correct, Provide correct path to app under test`);
11450
11986
  }
11451
11987
  }
11452
- BStackLogger2.info(`Using app: ${app.app}`);
11988
+ BStackLogger.info(`Using app: ${app.app}`);
11453
11989
  this._updateCaps(capabilities, "app", app.app);
11454
11990
  }
11455
11991
  }
@@ -11462,7 +11998,7 @@ var BrowserstackLauncherService = class {
11462
11998
  const shouldSetupPercy = this._options.percy || isUndefined(this._options.percy) && this._options.app;
11463
11999
  let buildStartResponse = null;
11464
12000
  if (!BrowserstackCLI.getInstance().isRunning() && (this._options.testObservability || this._accessibilityAutomation || shouldSetupPercy)) {
11465
- BStackLogger2.debug("Sending launch start event");
12001
+ BStackLogger.debug("Sending launch start event");
11466
12002
  buildStartResponse = await launchTestSession(this._options, this._config, {
11467
12003
  projectName: this._projectName,
11468
12004
  buildName: this._buildName,
@@ -11476,7 +12012,7 @@ var BrowserstackLauncherService = class {
11476
12012
  this._updateObjectTypeCaps(capabilities, "goog:chromeOptions", overrideOptions);
11477
12013
  }
11478
12014
  if (buildStartResponse?.accessibility) {
11479
- if (this._accessibilityAutomation === null) {
12015
+ if (isUndefined(this._accessibilityAutomation)) {
11480
12016
  this.browserStackConfig.accessibility = buildStartResponse.accessibility.success;
11481
12017
  this._accessibilityAutomation = buildStartResponse.accessibility.success;
11482
12018
  this._options.accessibility = buildStartResponse.accessibility.success;
@@ -11497,6 +12033,7 @@ var BrowserstackLauncherService = class {
11497
12033
  } else if (isAccessibilityAutomationSession(this._accessibilityAutomation)) {
11498
12034
  this._updateObjectTypeCaps(capabilities, "accessibilityOptions", {});
11499
12035
  }
12036
+ this._removeCliOnlyCapabilityOptions(capabilities);
11500
12037
  if (shouldSetupPercy) {
11501
12038
  try {
11502
12039
  const bestPlatformPercyCaps = getBestPlatformForPercySnapshot(capabilities);
@@ -11520,15 +12057,15 @@ var BrowserstackLauncherService = class {
11520
12057
  if (typeof spec !== "string") {
11521
12058
  return spec;
11522
12059
  }
11523
- const absolutePath = path20.isAbsolute(spec) ? spec : path20.resolve(cwd, spec);
11524
- const relativePath = path20.relative(rootDir, absolutePath);
12060
+ const absolutePath = path21.isAbsolute(spec) ? spec : path21.resolve(cwd, spec);
12061
+ const relativePath = path21.relative(rootDir, absolutePath);
11525
12062
  return relativePath.replace(/\\/g, "/");
11526
12063
  });
11527
12064
  };
11528
12065
  try {
11529
12066
  const { applyOrchestrationIfEnabled: applyOrchestrationIfEnabled2 } = await Promise.resolve().then(() => (init_apply_orchestration(), apply_orchestration_exports));
11530
12067
  if (config.specs && config.specs.length > 0 && this._options.testObservability && isValidEnabledValue(this._options.testOrchestrationOptions?.runSmartSelection?.enabled)) {
11531
- BStackLogger2.info("Applying test orchestration");
12068
+ BStackLogger.info("Applying test orchestration");
11532
12069
  const specs = config.specs.filter((spec) => typeof spec === "string");
11533
12070
  console.log(`Specs before orchestration: ${specs}`);
11534
12071
  const orderedSpecs = await applyOrchestrationIfEnabled2(specs, this._options);
@@ -11536,14 +12073,14 @@ var BrowserstackLauncherService = class {
11536
12073
  const specsToConvert = orderedSpecs && orderedSpecs.length > 0 ? orderedSpecs : specs;
11537
12074
  config.specs = convertToRootDirRelative(specsToConvert);
11538
12075
  console.log(`Specs after orchestration: ${config.specs}`);
11539
- BStackLogger2.info("Test specs updated with orchestrated order");
12076
+ BStackLogger.info("Test specs updated with orchestrated order");
11540
12077
  }
11541
12078
  } catch (error) {
11542
- BStackLogger2.error(`Error applying test orchestration: ${error}`);
12079
+ BStackLogger.error(`Error applying test orchestration: ${error}`);
11543
12080
  if (config.specs && config.specs.length > 0) {
11544
12081
  const specs = config.specs.filter((spec) => typeof spec === "string");
11545
12082
  config.specs = convertToRootDirRelative(specs);
11546
- BStackLogger2.debug(`Specs converted back to rootDir-relative after error: ${config.specs}`);
12083
+ BStackLogger.debug(`Specs converted back to rootDir-relative after error: ${config.specs}`);
11547
12084
  }
11548
12085
  }
11549
12086
  }
@@ -11551,7 +12088,7 @@ var BrowserstackLauncherService = class {
11551
12088
  return;
11552
12089
  }
11553
12090
  if (!this._options.browserstackLocal) {
11554
- return BStackLogger2.info("browserstackLocal is not enabled - skipping...");
12091
+ return BStackLogger.info("browserstackLocal is not enabled - skipping...");
11555
12092
  }
11556
12093
  const opts = {
11557
12094
  key: this._config.key,
@@ -11564,7 +12101,7 @@ var BrowserstackLauncherService = class {
11564
12101
  }
11565
12102
  const obs = new PerformanceObserver2((list) => {
11566
12103
  const entry = list.getEntries()[0];
11567
- BStackLogger2.info(`Browserstack Local successfully started after ${entry.duration}ms`);
12104
+ BStackLogger.info(`Browserstack Local successfully started after ${entry.duration}ms`);
11568
12105
  });
11569
12106
  obs.observe({ entryTypes: ["measure"] });
11570
12107
  let timer;
@@ -11597,13 +12134,13 @@ var BrowserstackLauncherService = class {
11597
12134
  PerformanceTester.start(FRAMEWORK_EVENTS.STOP);
11598
12135
  try {
11599
12136
  const isCLIEnabled = BrowserstackCLI.getInstance().isRunning();
11600
- BStackLogger2.debug("Inside OnComplete hook..");
11601
- BStackLogger2.debug("Sending stop launch event");
12137
+ BStackLogger.debug("Inside OnComplete hook..");
12138
+ BStackLogger.debug("Sending stop launch event");
11602
12139
  try {
11603
12140
  await (isCLIEnabled ? BrowserstackCLI.getInstance().stop() : stopBuildUpstream());
11604
12141
  PerformanceTester.end(FRAMEWORK_EVENTS.STOP);
11605
12142
  } catch (err) {
11606
- BStackLogger2.error(`Error while stopping CLI ${err}`);
12143
+ BStackLogger.error(`Error while stopping CLI ${err}`);
11607
12144
  PerformanceTester.end(FRAMEWORK_EVENTS.STOP, false, format4(err));
11608
12145
  }
11609
12146
  if (process.env[BROWSERSTACK_OBSERVABILITY] && process.env[BROWSERSTACK_TESTHUB_UUID]) {
@@ -11619,16 +12156,16 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
11619
12156
  return;
11620
12157
  }
11621
12158
  const duration = (/* @__PURE__ */ new Date()).getTime() - new Date(process.env.START_TIME).getTime();
11622
- BStackLogger2.info(`Total duration is ${duration / 1e3} s`);
12159
+ BStackLogger.info(`Total duration is ${duration / 1e3} s`);
11623
12160
  }
11624
- BStackLogger2.info(`BrowserStack service run ended for id: ${this.browserStackConfig?.sdkRunID} testhub id: ${testOpsConfig_default.getInstance()?.buildHashedId}`);
12161
+ BStackLogger.info(`BrowserStack service run ended for id: ${this.browserStackConfig?.sdkRunID} testhub id: ${testOpsConfig_default.getInstance()?.buildHashedId}`);
11625
12162
  await sendFinish(this.browserStackConfig, isCLIEnabled);
11626
12163
  try {
11627
12164
  PerformanceTester.start(EVENTS.SDK_SEND_LOGS);
11628
12165
  await this._uploadServiceLogs();
11629
12166
  PerformanceTester.end(EVENTS.SDK_SEND_LOGS);
11630
12167
  } catch (error) {
11631
- BStackLogger2.debug(`Failed to upload BrowserStack WDIO Service logs ${error}`);
12168
+ BStackLogger.debug(`Failed to upload BrowserStack WDIO Service logs ${error}`);
11632
12169
  PerformanceTester.end(EVENTS.SDK_SEND_LOGS, false, format4(error));
11633
12170
  }
11634
12171
  PerformanceTester.end(EVENTS.SDK_ON_STOP);
@@ -11638,9 +12175,9 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
11638
12175
  PerformanceTester.end(EVENTS.SDK_ON_STOP, false, format4(error));
11639
12176
  PerformanceTester.end(EVENTS.SDK_CLEANUP, false, format4(error));
11640
12177
  await PerformanceTester.stopAndGenerate("performance-launcher.html");
11641
- BStackLogger2.error(`Error in onComplete hook: ${error}`);
12178
+ BStackLogger.error(`Error in onComplete hook: ${error}`);
11642
12179
  }
11643
- BStackLogger2.clearLogger();
12180
+ BStackLogger.clearLogger();
11644
12181
  if (this._options.percy) {
11645
12182
  await this.stopPercy();
11646
12183
  PercyLogger.clearLogger();
@@ -11724,10 +12261,10 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
11724
12261
  }
11725
12262
  }
11726
12263
  async _uploadApp(app) {
11727
- BStackLogger2.info(`uploading app ${app.app} ${app.customId ? `and custom_id: ${app.customId}` : ""} to browserstack`);
12264
+ BStackLogger.info(`uploading app ${app.app} ${app.customId ? `and custom_id: ${app.customId}` : ""} to browserstack`);
11728
12265
  const form = new FormData();
11729
12266
  if (app.app) {
11730
- const fileName = path20.basename(app.app);
12267
+ const fileName = path21.basename(app.app);
11731
12268
  const fileBuffer = await readFile(app.app);
11732
12269
  const fileBlob = new Blob([new Uint8Array(fileBuffer)]);
11733
12270
  form.append("file", fileBlob, fileName);
@@ -11774,13 +12311,40 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
11774
12311
  }
11775
12312
  async _uploadServiceLogs() {
11776
12313
  const clientBuildUuid = this._getClientBuildUuid();
11777
- await PerformanceTester.measureWrapper(EVENTS.SDK_UPLOAD_LOGS, async () => {
11778
- const response = await uploadLogs(getBrowserStackUser(this._config), getBrowserStackKey(this._config), clientBuildUuid);
11779
- if (response) {
11780
- BStackLogger2.info(`Upload response: ${JSON.stringify(response, null, 2)}`);
11781
- BStackLogger2.logToFile(`Response - ${format4(response)}`, "debug");
12314
+ const response = await uploadLogs(getBrowserStackUser(this._config), getBrowserStackKey(this._config), clientBuildUuid);
12315
+ if (response) {
12316
+ BStackLogger.info(`Upload response: ${JSON.stringify(response, null, 2)}`);
12317
+ BStackLogger.logToFile(`Response - ${format4(response)}`, "debug");
12318
+ }
12319
+ }
12320
+ _removeCliOnlyCapabilityOptions(capabilities) {
12321
+ if (!capabilities || typeof capabilities !== "object") {
12322
+ return;
12323
+ }
12324
+ const strip = (capability) => {
12325
+ const capabilityRecord = capability;
12326
+ const bstackOptions = capabilityRecord["bstack:options"];
12327
+ if (bstackOptions && typeof bstackOptions === "object") {
12328
+ NOT_ALLOWED_KEYS_IN_CAPS.forEach((key) => delete bstackOptions[key]);
11782
12329
  }
11783
- });
12330
+ NOT_ALLOWED_KEYS_IN_CAPS.forEach((key) => delete capabilityRecord[`browserstack.${key}`]);
12331
+ const alwaysMatch = capability.alwaysMatch;
12332
+ if (alwaysMatch && typeof alwaysMatch === "object") {
12333
+ strip(alwaysMatch);
12334
+ }
12335
+ };
12336
+ if (Array.isArray(capabilities)) {
12337
+ capabilities.flatMap((c) => {
12338
+ if (Object.values(c).length > 0 && Object.values(c).every((c2) => typeof c2 === "object" && c2.capabilities)) {
12339
+ return Object.values(c).map((o) => o.capabilities);
12340
+ }
12341
+ return c;
12342
+ }).forEach(strip);
12343
+ } else {
12344
+ Object.entries(capabilities).forEach(([, caps]) => {
12345
+ strip(caps.capabilities);
12346
+ });
12347
+ }
11784
12348
  }
11785
12349
  _updateObjectTypeCaps(capabilities, capType, value) {
11786
12350
  try {
@@ -11883,7 +12447,7 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
11883
12447
  });
11884
12448
  }
11885
12449
  } catch (error) {
11886
- BStackLogger2.debug(`Exception while retrieving capability value. Error - ${error}`);
12450
+ BStackLogger.debug(`Exception while retrieving capability value. Error - ${error}`);
11887
12451
  }
11888
12452
  }
11889
12453
  _updateCaps(capabilities, capType, value) {
@@ -12019,7 +12583,7 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
12019
12583
  }
12020
12584
  if ((!this._buildName || process.env.BROWSERSTACK_BUILD_NAME) && this._buildIdentifier) {
12021
12585
  this._updateCaps(capabilities, "buildIdentifier");
12022
- BStackLogger2.warn("Skipping buildIdentifier as buildName is not passed.");
12586
+ BStackLogger.warn("Skipping buildIdentifier as buildName is not passed.");
12023
12587
  return;
12024
12588
  }
12025
12589
  if (this._buildIdentifier && this._buildIdentifier.includes("${DATE_TIME}")) {
@@ -12062,16 +12626,16 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
12062
12626
  * else returns corresponding value in json file (e.g. { "wdio-build": { "identifier" : 2 } } => 2 in this case)
12063
12627
  */
12064
12628
  _getLocalBuildNumber() {
12065
- const browserstackFolderPath = path20.join(os6.homedir(), ".browserstack");
12629
+ const browserstackFolderPath = path21.join(os7.homedir(), ".browserstack");
12066
12630
  try {
12067
- if (!fs14.existsSync(browserstackFolderPath)) {
12068
- fs14.mkdirSync(browserstackFolderPath);
12631
+ if (!fs15.existsSync(browserstackFolderPath)) {
12632
+ fs15.mkdirSync(browserstackFolderPath);
12069
12633
  }
12070
- const filePath = path20.join(browserstackFolderPath, ".build-name-cache.json");
12071
- if (!fs14.existsSync(filePath)) {
12072
- fs14.appendFileSync(filePath, JSON.stringify({}));
12634
+ const filePath = path21.join(browserstackFolderPath, ".build-name-cache.json");
12635
+ if (!fs15.existsSync(filePath)) {
12636
+ fs15.appendFileSync(filePath, JSON.stringify({}));
12073
12637
  }
12074
- const buildCacheFileData = fs14.readFileSync(filePath);
12638
+ const buildCacheFileData = fs15.readFileSync(filePath);
12075
12639
  const parsedBuildCacheFileData = JSON.parse(buildCacheFileData.toString());
12076
12640
  if (this._buildName && this._buildName in parsedBuildCacheFileData) {
12077
12641
  const prevIdentifier = parseInt(parsedBuildCacheFileData[this._buildName].identifier);
@@ -12090,16 +12654,16 @@ Visit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TEST
12090
12654
  if (!buildName || !filePath) {
12091
12655
  return;
12092
12656
  }
12093
- const jsonContent = JSON.parse(fs14.readFileSync(filePath).toString());
12657
+ const jsonContent = JSON.parse(fs15.readFileSync(filePath).toString());
12094
12658
  jsonContent[buildName] = { "identifier": buildIdentifier };
12095
- fs14.writeFileSync(filePath, JSON.stringify(jsonContent));
12659
+ fs15.writeFileSync(filePath, JSON.stringify(jsonContent));
12096
12660
  }
12097
12661
  _getClientBuildUuid() {
12098
12662
  if (process.env[BROWSERSTACK_TESTHUB_UUID]) {
12099
12663
  return process.env[BROWSERSTACK_TESTHUB_UUID];
12100
12664
  }
12101
12665
  const uuid = this.browserStackConfig?.sdkRunID;
12102
- BStackLogger2.logToFile(`If facing any issues, please contact BrowserStack support with the Build Run Id - ${uuid}`, "info");
12666
+ BStackLogger.logToFile(`If facing any issues, please contact BrowserStack support with the Build Run Id - ${uuid}`, "info");
12103
12667
  return uuid;
12104
12668
  }
12105
12669
  };
@@ -12121,6 +12685,7 @@ init_util();
12121
12685
  init_insights_handler();
12122
12686
  init_reporter();
12123
12687
  init_constants();
12688
+ init_caCert();
12124
12689
  init_crash_reporter();
12125
12690
 
12126
12691
  // src/accessibility-handler.ts
@@ -12244,7 +12809,7 @@ var _AccessibilityHandler = class {
12244
12809
  };
12245
12810
  browserWithA11y.startA11yScanning = async () => {
12246
12811
  if (this._testIdentifier === null) {
12247
- BStackLogger2.warn("Accessibility scanning cannot be started from outside the test");
12812
+ BStackLogger.warn("Accessibility scanning cannot be started from outside the test");
12248
12813
  return;
12249
12814
  }
12250
12815
  AccessibilityHandler._a11yScanSessionMap[sessionId] = true;
@@ -12256,7 +12821,7 @@ var _AccessibilityHandler = class {
12256
12821
  };
12257
12822
  browserWithA11y.stopA11yScanning = async () => {
12258
12823
  if (this._testIdentifier === null) {
12259
- BStackLogger2.warn("Accessibility scanning cannot be stopped from outside the test");
12824
+ BStackLogger.warn("Accessibility scanning cannot be stopped from outside the test");
12260
12825
  return;
12261
12826
  }
12262
12827
  AccessibilityHandler._a11yScanSessionMap[sessionId] = false;
@@ -12275,7 +12840,7 @@ var _AccessibilityHandler = class {
12275
12840
  const prevImpl = orig ? orig.bind(browser) : void 0;
12276
12841
  browser.overwriteCommand(command.name, this.commandWrapper.bind(this, command, prevImpl), command.class === "Element");
12277
12842
  } catch (error) {
12278
- BStackLogger2.debug(`Exception in overwrite command ${command.name} - ${error}`);
12843
+ BStackLogger.debug(`Exception in overwrite command ${command.name} - ${error}`);
12279
12844
  }
12280
12845
  });
12281
12846
  PerformanceTester.end(CONFIG_EVENTS.ACCESSIBILITY);
@@ -12299,14 +12864,14 @@ var _AccessibilityHandler = class {
12299
12864
  };
12300
12865
  this._testMetadata[testIdentifier].accessibilityScanStarted = shouldScanTest;
12301
12866
  if (shouldScanTest) {
12302
- BStackLogger2.info("Automate test case execution has started.");
12867
+ BStackLogger.info("Automate test case execution has started.");
12303
12868
  }
12304
12869
  } catch (error) {
12305
- BStackLogger2.error(`Exception in starting accessibility automation scan for this test case ${error}`);
12870
+ BStackLogger.error(`Exception in starting accessibility automation scan for this test case ${error}`);
12306
12871
  }
12307
12872
  }
12308
12873
  async afterTest(suiteTitle, test) {
12309
- BStackLogger2.debug("Accessibility after test hook. Before sending test stop event");
12874
+ BStackLogger.debug("Accessibility after test hook. Before sending test stop event");
12310
12875
  if (this._framework !== "mocha" || !this.shouldRunTestHooks(this._browser, this._accessibility)) {
12311
12876
  return;
12312
12877
  }
@@ -12318,17 +12883,17 @@ var _AccessibilityHandler = class {
12318
12883
  return;
12319
12884
  }
12320
12885
  if (shouldScanTestForAccessibility2) {
12321
- BStackLogger2.info("Automate test case execution has ended. Processing for accessibility testing is underway. ");
12886
+ BStackLogger.info("Automate test case execution has ended. Processing for accessibility testing is underway. ");
12322
12887
  const dataForExtension = {
12323
12888
  "thTestRunUuid": process.env.TEST_ANALYTICS_ID,
12324
12889
  "thBuildUuid": process.env.BROWSERSTACK_TESTHUB_UUID,
12325
12890
  "thJwtToken": process.env.BROWSERSTACK_TESTHUB_JWT
12326
12891
  };
12327
12892
  await this.sendTestStopEvent(this._browser, dataForExtension);
12328
- BStackLogger2.info("Accessibility testing for this test case has ended.");
12893
+ BStackLogger.info("Accessibility testing for this test case has ended.");
12329
12894
  }
12330
12895
  } catch (error) {
12331
- BStackLogger2.error(`Accessibility results could not be processed for the test case ${test.title}. Error : ${error}`);
12896
+ BStackLogger.error(`Accessibility results could not be processed for the test case ${test.title}. Error : ${error}`);
12332
12897
  }
12333
12898
  }
12334
12899
  /**
@@ -12356,14 +12921,14 @@ var _AccessibilityHandler = class {
12356
12921
  }
12357
12922
  listener_default.setTestRunAccessibilityVar(this._accessibility && shouldScanScenario);
12358
12923
  if (shouldScanScenario) {
12359
- BStackLogger2.info("Automate test case execution has started.");
12924
+ BStackLogger.info("Automate test case execution has started.");
12360
12925
  }
12361
12926
  } catch (error) {
12362
- BStackLogger2.error(`Exception in starting accessibility automation scan for this test case ${error}`);
12927
+ BStackLogger.error(`Exception in starting accessibility automation scan for this test case ${error}`);
12363
12928
  }
12364
12929
  }
12365
12930
  async afterScenario(world) {
12366
- BStackLogger2.debug("Accessibility after scenario hook. Before sending test stop event");
12931
+ BStackLogger.debug("Accessibility after scenario hook. Before sending test stop event");
12367
12932
  if (!this.shouldRunTestHooks(this._browser, this._accessibility)) {
12368
12933
  return;
12369
12934
  }
@@ -12376,17 +12941,17 @@ var _AccessibilityHandler = class {
12376
12941
  return;
12377
12942
  }
12378
12943
  if (shouldScanTestForAccessibility2) {
12379
- BStackLogger2.info("Automate test case execution has ended. Processing for accessibility testing is underway. ");
12944
+ BStackLogger.info("Automate test case execution has ended. Processing for accessibility testing is underway. ");
12380
12945
  const dataForExtension = {
12381
12946
  "thTestRunUuid": process.env.TEST_ANALYTICS_ID,
12382
12947
  "thBuildUuid": process.env.BROWSERSTACK_TESTHUB_UUID,
12383
12948
  "thJwtToken": process.env.BROWSERSTACK_TESTHUB_JWT
12384
12949
  };
12385
12950
  await this.sendTestStopEvent(this._browser, dataForExtension);
12386
- BStackLogger2.info("Accessibility testing for this test case has ended.");
12951
+ BStackLogger.info("Accessibility testing for this test case has ended.");
12387
12952
  }
12388
12953
  } catch (error) {
12389
- BStackLogger2.error(`Accessibility results could not be processed for the test case ${pickleData.name}. Error : ${error}`);
12954
+ BStackLogger.error(`Accessibility results could not be processed for the test case ${pickleData.name}. Error : ${error}`);
12390
12955
  }
12391
12956
  }
12392
12957
  /*
@@ -12394,14 +12959,14 @@ var _AccessibilityHandler = class {
12394
12959
  */
12395
12960
  async commandWrapper(command, prevImpl, origFunction, ...args) {
12396
12961
  if (this._sessionId && AccessibilityHandler._a11yScanSessionMap[this._sessionId] && (!command.name.includes("execute") || !AccessibilityHandler.shouldPatchExecuteScript(args.length ? args[0] : null))) {
12397
- BStackLogger2.debug(`Performing scan for ${command.class} ${command.name}`);
12962
+ BStackLogger.debug(`Performing scan for ${command.class} ${command.name}`);
12398
12963
  await performA11yScan(this.isAppAutomate, this._browser, true, true, command.name);
12399
12964
  }
12400
12965
  const impl = prevImpl || origFunction;
12401
12966
  return impl(...args);
12402
12967
  }
12403
12968
  async sendTestStopEvent(browser, dataForExtension) {
12404
- BStackLogger2.debug("Performing scan before saving results");
12969
+ BStackLogger.debug("Performing scan before saving results");
12405
12970
  if (AccessibilityHandler._a11yScanSessionMap[this._sessionId]) {
12406
12971
  await PerformanceTester.measureWrapper(A11Y_EVENTS.PERFORM_SCAN, async () => {
12407
12972
  await performA11yScan(this.isAppAutomate, browser, true, true);
@@ -12413,9 +12978,9 @@ var _AccessibilityHandler = class {
12413
12978
  await PerformanceTester.measureWrapper(A11Y_EVENTS.SAVE_RESULTS, async () => {
12414
12979
  if (accessibility_scripts_default.saveTestResults) {
12415
12980
  const results = await executeAccessibilityScript(browser, accessibility_scripts_default.saveTestResults, dataForExtension);
12416
- BStackLogger2.debug(util11.format(results));
12981
+ BStackLogger.debug(util11.format(results));
12417
12982
  } else {
12418
- BStackLogger2.error("saveTestResults script is null or undefined");
12983
+ BStackLogger.error("saveTestResults script is null or undefined");
12419
12984
  }
12420
12985
  })();
12421
12986
  }
@@ -12492,6 +13057,7 @@ var BrowserstackService = class {
12492
13057
  this._caps = _caps;
12493
13058
  this._config = _config;
12494
13059
  this._options = { ...DEFAULT_OPTIONS, ...options };
13060
+ configureCaCertificate(this._options);
12495
13061
  if (!this._config) {
12496
13062
  this._config = this._options;
12497
13063
  }
@@ -12571,24 +13137,33 @@ var BrowserstackService = class {
12571
13137
  PerformanceTester.end(EVENTS.SDK_FIND_NEAREST_HUB, false, "Hub URL not found");
12572
13138
  }
12573
13139
  }
12574
- if (BrowserstackCLI.getInstance().isRunning()) {
12575
- await BrowserstackCLI.getInstance().getAutomationFramework().trackEvent(AutomationFrameworkState.CREATE, HookState.PRE, { caps: capabilities });
12576
- const instance = AutomationFramework.getTrackedInstance();
12577
- const caps = AutomationFramework.getState(instance, AutomationFrameworkConstants.KEY_CAPABILITIES);
12578
- Object.assign(capabilities, caps);
13140
+ try {
13141
+ if (BrowserstackCLI.getInstance().isRunning()) {
13142
+ await BrowserstackCLI.getInstance().getAutomationFramework().trackEvent(AutomationFrameworkState.CREATE, HookState.PRE, { caps: capabilities });
13143
+ const instance = AutomationFramework.getTrackedInstance();
13144
+ const caps = AutomationFramework.getState(instance, AutomationFrameworkConstants.KEY_CAPABILITIES);
13145
+ Object.assign(capabilities, caps);
13146
+ const bstackOptions = capabilities["bstack:options"];
13147
+ if (bstackOptions && typeof bstackOptions === "object") {
13148
+ NOT_ALLOWED_KEYS_IN_CAPS.forEach((key) => delete bstackOptions[key]);
13149
+ }
13150
+ NOT_ALLOWED_KEYS_IN_CAPS.forEach((key) => delete capabilities[`browserstack.${key}`]);
13151
+ }
13152
+ } catch (err) {
13153
+ BStackLogger.error(`Error while tracking automation framework event: ${err}`);
12579
13154
  }
12580
13155
  } catch (err) {
12581
- BStackLogger2.error(`Error while connecting to Browserstack CLI: ${err}`);
13156
+ BStackLogger.error(`Error while connecting to Browserstack CLI: ${err}`);
12582
13157
  PerformanceTester.end(DRIVER_EVENT.INIT, false, util12.format(err));
12583
13158
  throw err;
12584
13159
  }
12585
13160
  PerformanceTester.end(DRIVER_EVENT.INIT);
12586
13161
  PerformanceTester.start(EVENTS.SDK_DEVICE_ALLOCATION);
12587
- BStackLogger2.debug("Device allocation tracking started - waiting for WebDriverIO to create remote session");
13162
+ BStackLogger.debug("Device allocation tracking started - waiting for WebDriverIO to create remote session");
12588
13163
  }
12589
13164
  async before(caps, specs, browser) {
12590
13165
  PerformanceTester.end(EVENTS.SDK_DEVICE_ALLOCATION, true, "Device allocated and session created");
12591
- BStackLogger2.debug("Device allocation tracking ended - remote session created successfully");
13166
+ BStackLogger.debug("Device allocation tracking ended - remote session created successfully");
12592
13167
  PerformanceTester.start(DRIVER_EVENT.PRE_INITIALIZE);
12593
13168
  this._browser = browser ? browser : globalThis.browser;
12594
13169
  PerformanceTester.browser = this._browser;
@@ -12597,7 +13172,7 @@ var BrowserstackService = class {
12597
13172
  await ai_handler_default.selfHeal(this._options, caps, this._browser);
12598
13173
  } catch (err) {
12599
13174
  if (this._options.selfHeal === true) {
12600
- BStackLogger2.warn(`Error while setting up self-healing: ${err}. Disabling healing for this session.`);
13175
+ BStackLogger.warn(`Error while setting up self-healing: ${err}. Disabling healing for this session.`);
12601
13176
  }
12602
13177
  }
12603
13178
  }
@@ -12627,13 +13202,13 @@ var BrowserstackService = class {
12627
13202
  this._options.accessibilityOptions
12628
13203
  );
12629
13204
  if (isBrowserstackSession(this._browser) && BrowserstackCLI.getInstance().isRunning()) {
12630
- BStackLogger2.info(`CLI is running, tracking accessibility event for before: ${sessionId}`);
13205
+ BStackLogger.info(`CLI is running, tracking accessibility event for before: ${sessionId}`);
12631
13206
  } else {
12632
13207
  await this._accessibilityHandler.before(sessionId);
12633
13208
  }
12634
13209
  listener_default.setAccessibilityOptions(this._options.accessibilityOptions);
12635
13210
  } catch (err) {
12636
- BStackLogger2.error(`[Accessibility Test Run] Error in service class before function: ${err}`);
13211
+ BStackLogger.error(`[Accessibility Test Run] Error in service class before function: ${err}`);
12637
13212
  }
12638
13213
  if (shouldProcessEventForTesthub("")) {
12639
13214
  patchConsoleLogs();
@@ -12644,7 +13219,7 @@ var BrowserstackService = class {
12644
13219
  this._options
12645
13220
  );
12646
13221
  if (BrowserstackCLI.getInstance().isRunning()) {
12647
- BStackLogger2.info(`CLI is running, tracking insights event for before: ${sessionId}`);
13222
+ BStackLogger.info(`CLI is running, tracking insights event for before: ${sessionId}`);
12648
13223
  await BrowserstackCLI.getInstance().getAutomationFramework().trackEvent(AutomationFrameworkState.CREATE, HookState.POST, { browser: this._browser, hubUrl: this._config.hostname });
12649
13224
  this._insightsHandler.setGitConfigPath();
12650
13225
  PerformanceTester.end(DRIVER_EVENT.PRE_INITIALIZE);
@@ -12679,7 +13254,7 @@ var BrowserstackService = class {
12679
13254
  });
12680
13255
  }
12681
13256
  } catch (err) {
12682
- BStackLogger2.error(`Error in service class before function: ${err}`);
13257
+ BStackLogger.error(`Error in service class before function: ${err}`);
12683
13258
  if (shouldProcessEventForTesthub("")) {
12684
13259
  CrashReporter.uploadCrashReport(`Error in service class before function: ${err}`, err ? err.stack : "unknown error");
12685
13260
  }
@@ -12752,8 +13327,8 @@ var BrowserstackService = class {
12752
13327
  }
12753
13328
  async afterTest(test, context, results) {
12754
13329
  this._specsRan = true;
12755
- const { error, passed } = results;
12756
- if (!passed) {
13330
+ const { error, passed, skipped } = results;
13331
+ if (!passed && !skipped) {
12757
13332
  const testError = error && error.message || "Unknown Error";
12758
13333
  this._failReasons.push(testError);
12759
13334
  this._pureTestFailReasons.push(testError);
@@ -12863,7 +13438,7 @@ var BrowserstackService = class {
12863
13438
  return;
12864
13439
  }
12865
13440
  } catch (error) {
12866
- BStackLogger2.error(`Error in after hook: ${error}`);
13441
+ BStackLogger.error(`Error in after hook: ${error}`);
12867
13442
  PerformanceTester.end(DRIVER_EVENT.QUIT, false, util12.format(error));
12868
13443
  PerformanceTester.end(HOOK_EVENTS.AFTER, false, util12.format(error));
12869
13444
  await PerformanceTester.stopAndGenerate("performance-service.html");
@@ -12934,14 +13509,14 @@ var BrowserstackService = class {
12934
13509
  failureReason = hasReasons ? this._failReasons.join("\n") : void 0;
12935
13510
  }
12936
13511
  if (!this._browser.isMultiremote) {
12937
- BStackLogger2.info(`Update (reloaded) job with sessionId ${oldSessionId}, ${sessionStatus}`);
13512
+ BStackLogger.info(`Update (reloaded) job with sessionId ${oldSessionId}, ${sessionStatus}`);
12938
13513
  } else {
12939
13514
  const browserName = this._browser.instances.filter(
12940
13515
  (browserName2) => this._browser && this._browser.getInstance(browserName2).sessionId === newSessionId
12941
13516
  )[0];
12942
- BStackLogger2.info(`Update (reloaded) multiremote job for browser "${browserName}" and sessionId ${oldSessionId}, ${sessionStatus}`);
13517
+ BStackLogger.info(`Update (reloaded) multiremote job for browser "${browserName}" and sessionId ${oldSessionId}, ${sessionStatus}`);
12943
13518
  }
12944
- BStackLogger2.warn(`Session Reloaded: Old Session Id: ${oldSessionId}, New Session Id: ${newSessionId}`);
13519
+ BStackLogger.warn(`Session Reloaded: Old Session Id: ${oldSessionId}, New Session Id: ${newSessionId}`);
12945
13520
  await this._insightsHandler?.sendCBTInfo();
12946
13521
  if (setSessionStatus) {
12947
13522
  await this._update(oldSessionId, {
@@ -12967,7 +13542,7 @@ var BrowserstackService = class {
12967
13542
  }
12968
13543
  _updateJob(requestBody) {
12969
13544
  return this._multiRemoteAction((sessionId, browserName) => {
12970
- BStackLogger2.info(
13545
+ BStackLogger.info(
12971
13546
  browserName ? `Update multiremote job for browser "${browserName}" and sessionId ${sessionId}` : `Update job with sessionId ${sessionId}`
12972
13547
  );
12973
13548
  return this._update(sessionId, requestBody);
@@ -12993,7 +13568,7 @@ var BrowserstackService = class {
12993
13568
  return Promise.resolve();
12994
13569
  }
12995
13570
  const sessionUrl = `${this._sessionBaseUrl}/${sessionId}.json`;
12996
- BStackLogger2.debug(`Updating Browserstack session at ${sessionUrl} with request body: `, requestBody);
13571
+ BStackLogger.debug(`Updating Browserstack session at ${sessionUrl} with request body: `, requestBody);
12997
13572
  const encodedAuth = Buffer.from(`${this._config.user}:${this._config.key}`, "utf8").toString("base64");
12998
13573
  const headers = {
12999
13574
  "Content-Type": "application/json; charset=utf-8",
@@ -13018,7 +13593,7 @@ var BrowserstackService = class {
13018
13593
  }
13019
13594
  await this._multiRemoteAction(async (sessionId, browserName) => {
13020
13595
  const sessionUrl = `${this._sessionBaseUrl}/${sessionId}.json`;
13021
- BStackLogger2.debug(`Requesting Browserstack session URL at ${sessionUrl}`);
13596
+ BStackLogger.debug(`Requesting Browserstack session URL at ${sessionUrl}`);
13022
13597
  let browserUrl;
13023
13598
  const encodedAuth = Buffer.from(`${this._config.user}:${this._config.key}`, "utf8").toString("base64");
13024
13599
  const headers = {
@@ -13045,7 +13620,7 @@ var BrowserstackService = class {
13045
13620
  }
13046
13621
  const capabilities = getBrowserCapabilities(this._browser, this._caps, browserName);
13047
13622
  const browserString = getBrowserDescription(capabilities);
13048
- BStackLogger2.info(`${browserString} session: ${browserUrl}`);
13623
+ BStackLogger.info(`${browserString} session: ${browserUrl}`);
13049
13624
  });
13050
13625
  }
13051
13626
  async _setSessionName(suiteTitle, test) {