@bigbinary/neeto-playwright-commons 4.8.6 → 4.8.8

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/index.js CHANGED
@@ -8,7 +8,7 @@ import path__default, { dirname } from 'path';
8
8
  import { test, expect, chromium, defineConfig, devices } from '@playwright/test';
9
9
  import { getI18nInstance, initI18n } from 'playwright-i18next-fixture';
10
10
  import { curry, isNotNil, not, isEmpty, pluck, isNil, mergeAll, mergeDeepLeft } from 'ramda';
11
- import { execSync, spawn } from 'child_process';
11
+ import { execSync, spawn, spawnSync } from 'child_process';
12
12
  import require$$2$2, { fileURLToPath } from 'url';
13
13
  import dayjs from 'dayjs';
14
14
  import require$$1$3 from 'events';
@@ -33,6 +33,7 @@ import timezone from 'dayjs/plugin/timezone.js';
33
33
  import utc from 'dayjs/plugin/utc.js';
34
34
  import https from 'https';
35
35
  import * as http from 'http';
36
+ import require$$0$c from 'constants';
36
37
 
37
38
  const BASE_URL = "/api/v1";
38
39
  const NEETO_AUTH_BASE_URL = (subdomain = "app") => `https://${subdomain}.neetoauth.net`;
@@ -307,6 +308,7 @@ const ENVIRONMENT = {
307
308
  const EXAMPLE_URL = "https://example.com";
308
309
  const IS_STAGING_ENV = process.env.TEST_ENV === ENVIRONMENT.staging;
309
310
  const IS_DEV_ENV = process.env.TEST_ENV === ENVIRONMENT.development;
311
+ const IS_REVIEW_ENV = process.env.TEST_ENV === ENVIRONMENT.review;
310
312
  const IS_CI = isPresent(process.env.NEETO_CI_JOB_ID);
311
313
  const IS_DEV_CI = IS_DEV_ENV && IS_CI;
312
314
  const IS_WEBKIT = process.env.PLAYWRIGHT_PROJECT === "webkit";
@@ -122944,6 +122946,83 @@ const initializeCredentials = (product) => {
122944
122946
  process.env.BASE_URL = baseURLGenerator(product, stagingData.subdomainName);
122945
122947
  };
122946
122948
 
122949
+ const REVIEW_APP_WAKE_TIMEOUT = 10 * 60_000;
122950
+ const REVIEW_APP_POLL_INTERVAL = 10_000;
122951
+ const REVIEW_APP_REQUEST_TIMEOUT = 20_000;
122952
+ // The host is read on each call so that a product importing the package outside
122953
+ // the review environment never trips the guard.
122954
+ const reviewAppHost = () => {
122955
+ const host = process.env.REVIEW_APP_HOST;
122956
+ if (!host) {
122957
+ throw new Error("REVIEW_APP_HOST must be set when TEST_ENV is review");
122958
+ }
122959
+ return host;
122960
+ };
122961
+ const isReviewAppServing = async () => {
122962
+ try {
122963
+ const response = await fetch(`https://${reviewAppHost()}/?_hs=${Date.now()}`, {
122964
+ headers: { Accept: "text/html", "X-Downtime-Poll": "1" },
122965
+ redirect: "manual",
122966
+ signal: AbortSignal.timeout(REVIEW_APP_REQUEST_TIMEOUT),
122967
+ });
122968
+ return response.status < 400 && !response.headers.has("x-neeto-downtime");
122969
+ }
122970
+ catch {
122971
+ return false;
122972
+ }
122973
+ };
122974
+ const wakeReviewApp = async () => {
122975
+ try {
122976
+ await fetch(`https://${reviewAppHost()}/`, {
122977
+ headers: { Accept: "text/html" },
122978
+ signal: AbortSignal.timeout(REVIEW_APP_REQUEST_TIMEOUT),
122979
+ });
122980
+ }
122981
+ catch {
122982
+ // The wake request is fire-and-forget; readiness is polled separately.
122983
+ }
122984
+ };
122985
+ const reviewAppBaseURL = (subdomain = CREDENTIALS.subdomainName) => `https://${subdomain}.${reviewAppHost()}`;
122986
+ const waitForReviewApp = () => {
122987
+ const host = reviewAppHost();
122988
+ return expect(async () => {
122989
+ const isServing = await isReviewAppServing();
122990
+ !isServing && (await wakeReviewApp());
122991
+ expect(isServing, `Review app ${host} is not up yet`).toBe(true);
122992
+ }).toPass({
122993
+ timeout: REVIEW_APP_WAKE_TIMEOUT,
122994
+ intervals: [REVIEW_APP_POLL_INTERVAL],
122995
+ });
122996
+ };
122997
+ const initializeReviewAppCredentials = () => {
122998
+ if (shouldSkipSetupAndTeardown())
122999
+ return;
123000
+ const { firstName, lastName, name, email, subdomainName } = CREDENTIALS;
123001
+ writeDataToFile(JSON.stringify({
123002
+ user: {
123003
+ firstName,
123004
+ lastName,
123005
+ email,
123006
+ subdomainName,
123007
+ businessName: subdomainName,
123008
+ currentUserName: name,
123009
+ otp: 111111,
123010
+ domain: reviewAppHost(),
123011
+ },
123012
+ }, null, 2));
123013
+ };
123014
+ const loginToReviewApp = async ({ page, loginPath = "/login", }) => {
123015
+ if (shouldSkipSetupAndTeardown())
123016
+ return;
123017
+ await waitForReviewApp();
123018
+ await authenticateUser({ page, loginPath });
123019
+ const userCredentials = readFileSyncIfExists();
123020
+ await page.context().storageState({ path: STORAGE_STATE });
123021
+ const mergedCredentials = mergeAll([readFileSyncIfExists(), userCredentials]);
123022
+ writeDataToFile(JSON.stringify(mergedCredentials, null, 2));
123023
+ updateCredentials({ key: "isLoggedIn", value: "true" });
123024
+ };
123025
+
122947
123026
  /**
122948
123027
  * Atoms hardcodes these labels instead of `neetoui.table.*`. `hasText` matches
122949
123028
  * substrings, and "Unfreeze column" contains "Freeze column", so the label has
@@ -126175,12 +126254,2134 @@ async function warmup({ urls = DEFAULT_WARMUP_URLS, timeout = 60_000, } = {}) {
126175
126254
  }
126176
126255
  }
126177
126256
 
126257
+ var properLockfile = {exports: {}};
126258
+
126259
+ var lockfile = {};
126260
+
126261
+ var polyfills;
126262
+ var hasRequiredPolyfills;
126263
+
126264
+ function requirePolyfills () {
126265
+ if (hasRequiredPolyfills) return polyfills;
126266
+ hasRequiredPolyfills = 1;
126267
+ var constants = require$$0$c;
126268
+
126269
+ var origCwd = process.cwd;
126270
+ var cwd = null;
126271
+
126272
+ var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform;
126273
+
126274
+ process.cwd = function() {
126275
+ if (!cwd)
126276
+ cwd = origCwd.call(process);
126277
+ return cwd
126278
+ };
126279
+ try {
126280
+ process.cwd();
126281
+ } catch (er) {}
126282
+
126283
+ // This check is needed until node.js 12 is required
126284
+ if (typeof process.chdir === 'function') {
126285
+ var chdir = process.chdir;
126286
+ process.chdir = function (d) {
126287
+ cwd = null;
126288
+ chdir.call(process, d);
126289
+ };
126290
+ if (Object.setPrototypeOf) Object.setPrototypeOf(process.chdir, chdir);
126291
+ }
126292
+
126293
+ polyfills = patch;
126294
+
126295
+ function patch (fs) {
126296
+ // (re-)implement some things that are known busted or missing.
126297
+
126298
+ // lchmod, broken prior to 0.6.2
126299
+ // back-port the fix here.
126300
+ if (constants.hasOwnProperty('O_SYMLINK') &&
126301
+ process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
126302
+ patchLchmod(fs);
126303
+ }
126304
+
126305
+ // lutimes implementation, or no-op
126306
+ if (!fs.lutimes) {
126307
+ patchLutimes(fs);
126308
+ }
126309
+
126310
+ // https://github.com/isaacs/node-graceful-fs/issues/4
126311
+ // Chown should not fail on einval or eperm if non-root.
126312
+ // It should not fail on enosys ever, as this just indicates
126313
+ // that a fs doesn't support the intended operation.
126314
+
126315
+ fs.chown = chownFix(fs.chown);
126316
+ fs.fchown = chownFix(fs.fchown);
126317
+ fs.lchown = chownFix(fs.lchown);
126318
+
126319
+ fs.chmod = chmodFix(fs.chmod);
126320
+ fs.fchmod = chmodFix(fs.fchmod);
126321
+ fs.lchmod = chmodFix(fs.lchmod);
126322
+
126323
+ fs.chownSync = chownFixSync(fs.chownSync);
126324
+ fs.fchownSync = chownFixSync(fs.fchownSync);
126325
+ fs.lchownSync = chownFixSync(fs.lchownSync);
126326
+
126327
+ fs.chmodSync = chmodFixSync(fs.chmodSync);
126328
+ fs.fchmodSync = chmodFixSync(fs.fchmodSync);
126329
+ fs.lchmodSync = chmodFixSync(fs.lchmodSync);
126330
+
126331
+ fs.stat = statFix(fs.stat);
126332
+ fs.fstat = statFix(fs.fstat);
126333
+ fs.lstat = statFix(fs.lstat);
126334
+
126335
+ fs.statSync = statFixSync(fs.statSync);
126336
+ fs.fstatSync = statFixSync(fs.fstatSync);
126337
+ fs.lstatSync = statFixSync(fs.lstatSync);
126338
+
126339
+ // if lchmod/lchown do not exist, then make them no-ops
126340
+ if (fs.chmod && !fs.lchmod) {
126341
+ fs.lchmod = function (path, mode, cb) {
126342
+ if (cb) process.nextTick(cb);
126343
+ };
126344
+ fs.lchmodSync = function () {};
126345
+ }
126346
+ if (fs.chown && !fs.lchown) {
126347
+ fs.lchown = function (path, uid, gid, cb) {
126348
+ if (cb) process.nextTick(cb);
126349
+ };
126350
+ fs.lchownSync = function () {};
126351
+ }
126352
+
126353
+ // on Windows, A/V software can lock the directory, causing this
126354
+ // to fail with an EACCES or EPERM if the directory contains newly
126355
+ // created files. Try again on failure, for up to 60 seconds.
126356
+
126357
+ // Set the timeout this long because some Windows Anti-Virus, such as Parity
126358
+ // bit9, may lock files for up to a minute, causing npm package install
126359
+ // failures. Also, take care to yield the scheduler. Windows scheduling gives
126360
+ // CPU to a busy looping process, which can cause the program causing the lock
126361
+ // contention to be starved of CPU by node, so the contention doesn't resolve.
126362
+ if (platform === "win32") {
126363
+ fs.rename = typeof fs.rename !== 'function' ? fs.rename
126364
+ : (function (fs$rename) {
126365
+ function rename (from, to, cb) {
126366
+ var start = Date.now();
126367
+ var backoff = 0;
126368
+ fs$rename(from, to, function CB (er) {
126369
+ if (er
126370
+ && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY")
126371
+ && Date.now() - start < 60000) {
126372
+ setTimeout(function() {
126373
+ fs.stat(to, function (stater, st) {
126374
+ if (stater && stater.code === "ENOENT")
126375
+ fs$rename(from, to, CB);
126376
+ else
126377
+ cb(er);
126378
+ });
126379
+ }, backoff);
126380
+ if (backoff < 100)
126381
+ backoff += 10;
126382
+ return;
126383
+ }
126384
+ if (cb) cb(er);
126385
+ });
126386
+ }
126387
+ if (Object.setPrototypeOf) Object.setPrototypeOf(rename, fs$rename);
126388
+ return rename
126389
+ })(fs.rename);
126390
+ }
126391
+
126392
+ // if read() returns EAGAIN, then just try it again.
126393
+ fs.read = typeof fs.read !== 'function' ? fs.read
126394
+ : (function (fs$read) {
126395
+ function read (fd, buffer, offset, length, position, callback_) {
126396
+ var callback;
126397
+ if (callback_ && typeof callback_ === 'function') {
126398
+ var eagCounter = 0;
126399
+ callback = function (er, _, __) {
126400
+ if (er && er.code === 'EAGAIN' && eagCounter < 10) {
126401
+ eagCounter ++;
126402
+ return fs$read.call(fs, fd, buffer, offset, length, position, callback)
126403
+ }
126404
+ callback_.apply(this, arguments);
126405
+ };
126406
+ }
126407
+ return fs$read.call(fs, fd, buffer, offset, length, position, callback)
126408
+ }
126409
+
126410
+ // This ensures `util.promisify` works as it does for native `fs.read`.
126411
+ if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read);
126412
+ return read
126413
+ })(fs.read);
126414
+
126415
+ fs.readSync = typeof fs.readSync !== 'function' ? fs.readSync
126416
+ : (function (fs$readSync) { return function (fd, buffer, offset, length, position) {
126417
+ var eagCounter = 0;
126418
+ while (true) {
126419
+ try {
126420
+ return fs$readSync.call(fs, fd, buffer, offset, length, position)
126421
+ } catch (er) {
126422
+ if (er.code === 'EAGAIN' && eagCounter < 10) {
126423
+ eagCounter ++;
126424
+ continue
126425
+ }
126426
+ throw er
126427
+ }
126428
+ }
126429
+ }})(fs.readSync);
126430
+
126431
+ function patchLchmod (fs) {
126432
+ fs.lchmod = function (path, mode, callback) {
126433
+ fs.open( path
126434
+ , constants.O_WRONLY | constants.O_SYMLINK
126435
+ , mode
126436
+ , function (err, fd) {
126437
+ if (err) {
126438
+ if (callback) callback(err);
126439
+ return
126440
+ }
126441
+ // prefer to return the chmod error, if one occurs,
126442
+ // but still try to close, and report closing errors if they occur.
126443
+ fs.fchmod(fd, mode, function (err) {
126444
+ fs.close(fd, function(err2) {
126445
+ if (callback) callback(err || err2);
126446
+ });
126447
+ });
126448
+ });
126449
+ };
126450
+
126451
+ fs.lchmodSync = function (path, mode) {
126452
+ var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode);
126453
+
126454
+ // prefer to return the chmod error, if one occurs,
126455
+ // but still try to close, and report closing errors if they occur.
126456
+ var threw = true;
126457
+ var ret;
126458
+ try {
126459
+ ret = fs.fchmodSync(fd, mode);
126460
+ threw = false;
126461
+ } finally {
126462
+ if (threw) {
126463
+ try {
126464
+ fs.closeSync(fd);
126465
+ } catch (er) {}
126466
+ } else {
126467
+ fs.closeSync(fd);
126468
+ }
126469
+ }
126470
+ return ret
126471
+ };
126472
+ }
126473
+
126474
+ function patchLutimes (fs) {
126475
+ if (constants.hasOwnProperty("O_SYMLINK") && fs.futimes) {
126476
+ fs.lutimes = function (path, at, mt, cb) {
126477
+ fs.open(path, constants.O_SYMLINK, function (er, fd) {
126478
+ if (er) {
126479
+ if (cb) cb(er);
126480
+ return
126481
+ }
126482
+ fs.futimes(fd, at, mt, function (er) {
126483
+ fs.close(fd, function (er2) {
126484
+ if (cb) cb(er || er2);
126485
+ });
126486
+ });
126487
+ });
126488
+ };
126489
+
126490
+ fs.lutimesSync = function (path, at, mt) {
126491
+ var fd = fs.openSync(path, constants.O_SYMLINK);
126492
+ var ret;
126493
+ var threw = true;
126494
+ try {
126495
+ ret = fs.futimesSync(fd, at, mt);
126496
+ threw = false;
126497
+ } finally {
126498
+ if (threw) {
126499
+ try {
126500
+ fs.closeSync(fd);
126501
+ } catch (er) {}
126502
+ } else {
126503
+ fs.closeSync(fd);
126504
+ }
126505
+ }
126506
+ return ret
126507
+ };
126508
+
126509
+ } else if (fs.futimes) {
126510
+ fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb); };
126511
+ fs.lutimesSync = function () {};
126512
+ }
126513
+ }
126514
+
126515
+ function chmodFix (orig) {
126516
+ if (!orig) return orig
126517
+ return function (target, mode, cb) {
126518
+ return orig.call(fs, target, mode, function (er) {
126519
+ if (chownErOk(er)) er = null;
126520
+ if (cb) cb.apply(this, arguments);
126521
+ })
126522
+ }
126523
+ }
126524
+
126525
+ function chmodFixSync (orig) {
126526
+ if (!orig) return orig
126527
+ return function (target, mode) {
126528
+ try {
126529
+ return orig.call(fs, target, mode)
126530
+ } catch (er) {
126531
+ if (!chownErOk(er)) throw er
126532
+ }
126533
+ }
126534
+ }
126535
+
126536
+
126537
+ function chownFix (orig) {
126538
+ if (!orig) return orig
126539
+ return function (target, uid, gid, cb) {
126540
+ return orig.call(fs, target, uid, gid, function (er) {
126541
+ if (chownErOk(er)) er = null;
126542
+ if (cb) cb.apply(this, arguments);
126543
+ })
126544
+ }
126545
+ }
126546
+
126547
+ function chownFixSync (orig) {
126548
+ if (!orig) return orig
126549
+ return function (target, uid, gid) {
126550
+ try {
126551
+ return orig.call(fs, target, uid, gid)
126552
+ } catch (er) {
126553
+ if (!chownErOk(er)) throw er
126554
+ }
126555
+ }
126556
+ }
126557
+
126558
+ function statFix (orig) {
126559
+ if (!orig) return orig
126560
+ // Older versions of Node erroneously returned signed integers for
126561
+ // uid + gid.
126562
+ return function (target, options, cb) {
126563
+ if (typeof options === 'function') {
126564
+ cb = options;
126565
+ options = null;
126566
+ }
126567
+ function callback (er, stats) {
126568
+ if (stats) {
126569
+ if (stats.uid < 0) stats.uid += 0x100000000;
126570
+ if (stats.gid < 0) stats.gid += 0x100000000;
126571
+ }
126572
+ if (cb) cb.apply(this, arguments);
126573
+ }
126574
+ return options ? orig.call(fs, target, options, callback)
126575
+ : orig.call(fs, target, callback)
126576
+ }
126577
+ }
126578
+
126579
+ function statFixSync (orig) {
126580
+ if (!orig) return orig
126581
+ // Older versions of Node erroneously returned signed integers for
126582
+ // uid + gid.
126583
+ return function (target, options) {
126584
+ var stats = options ? orig.call(fs, target, options)
126585
+ : orig.call(fs, target);
126586
+ if (stats) {
126587
+ if (stats.uid < 0) stats.uid += 0x100000000;
126588
+ if (stats.gid < 0) stats.gid += 0x100000000;
126589
+ }
126590
+ return stats;
126591
+ }
126592
+ }
126593
+
126594
+ // ENOSYS means that the fs doesn't support the op. Just ignore
126595
+ // that, because it doesn't matter.
126596
+ //
126597
+ // if there's no getuid, or if getuid() is something other
126598
+ // than 0, and the error is EINVAL or EPERM, then just ignore
126599
+ // it.
126600
+ //
126601
+ // This specific case is a silent failure in cp, install, tar,
126602
+ // and most other unix tools that manage permissions.
126603
+ //
126604
+ // When running as root, or if other types of errors are
126605
+ // encountered, then it's strict.
126606
+ function chownErOk (er) {
126607
+ if (!er)
126608
+ return true
126609
+
126610
+ if (er.code === "ENOSYS")
126611
+ return true
126612
+
126613
+ var nonroot = !process.getuid || process.getuid() !== 0;
126614
+ if (nonroot) {
126615
+ if (er.code === "EINVAL" || er.code === "EPERM")
126616
+ return true
126617
+ }
126618
+
126619
+ return false
126620
+ }
126621
+ }
126622
+ return polyfills;
126623
+ }
126624
+
126625
+ var legacyStreams;
126626
+ var hasRequiredLegacyStreams;
126627
+
126628
+ function requireLegacyStreams () {
126629
+ if (hasRequiredLegacyStreams) return legacyStreams;
126630
+ hasRequiredLegacyStreams = 1;
126631
+ var Stream = require$$0$6.Stream;
126632
+
126633
+ legacyStreams = legacy;
126634
+
126635
+ function legacy (fs) {
126636
+ return {
126637
+ ReadStream: ReadStream,
126638
+ WriteStream: WriteStream
126639
+ }
126640
+
126641
+ function ReadStream (path, options) {
126642
+ if (!(this instanceof ReadStream)) return new ReadStream(path, options);
126643
+
126644
+ Stream.call(this);
126645
+
126646
+ var self = this;
126647
+
126648
+ this.path = path;
126649
+ this.fd = null;
126650
+ this.readable = true;
126651
+ this.paused = false;
126652
+
126653
+ this.flags = 'r';
126654
+ this.mode = 438; /*=0666*/
126655
+ this.bufferSize = 64 * 1024;
126656
+
126657
+ options = options || {};
126658
+
126659
+ // Mixin options into this
126660
+ var keys = Object.keys(options);
126661
+ for (var index = 0, length = keys.length; index < length; index++) {
126662
+ var key = keys[index];
126663
+ this[key] = options[key];
126664
+ }
126665
+
126666
+ if (this.encoding) this.setEncoding(this.encoding);
126667
+
126668
+ if (this.start !== undefined) {
126669
+ if ('number' !== typeof this.start) {
126670
+ throw TypeError('start must be a Number');
126671
+ }
126672
+ if (this.end === undefined) {
126673
+ this.end = Infinity;
126674
+ } else if ('number' !== typeof this.end) {
126675
+ throw TypeError('end must be a Number');
126676
+ }
126677
+
126678
+ if (this.start > this.end) {
126679
+ throw new Error('start must be <= end');
126680
+ }
126681
+
126682
+ this.pos = this.start;
126683
+ }
126684
+
126685
+ if (this.fd !== null) {
126686
+ process.nextTick(function() {
126687
+ self._read();
126688
+ });
126689
+ return;
126690
+ }
126691
+
126692
+ fs.open(this.path, this.flags, this.mode, function (err, fd) {
126693
+ if (err) {
126694
+ self.emit('error', err);
126695
+ self.readable = false;
126696
+ return;
126697
+ }
126698
+
126699
+ self.fd = fd;
126700
+ self.emit('open', fd);
126701
+ self._read();
126702
+ });
126703
+ }
126704
+
126705
+ function WriteStream (path, options) {
126706
+ if (!(this instanceof WriteStream)) return new WriteStream(path, options);
126707
+
126708
+ Stream.call(this);
126709
+
126710
+ this.path = path;
126711
+ this.fd = null;
126712
+ this.writable = true;
126713
+
126714
+ this.flags = 'w';
126715
+ this.encoding = 'binary';
126716
+ this.mode = 438; /*=0666*/
126717
+ this.bytesWritten = 0;
126718
+
126719
+ options = options || {};
126720
+
126721
+ // Mixin options into this
126722
+ var keys = Object.keys(options);
126723
+ for (var index = 0, length = keys.length; index < length; index++) {
126724
+ var key = keys[index];
126725
+ this[key] = options[key];
126726
+ }
126727
+
126728
+ if (this.start !== undefined) {
126729
+ if ('number' !== typeof this.start) {
126730
+ throw TypeError('start must be a Number');
126731
+ }
126732
+ if (this.start < 0) {
126733
+ throw new Error('start must be >= zero');
126734
+ }
126735
+
126736
+ this.pos = this.start;
126737
+ }
126738
+
126739
+ this.busy = false;
126740
+ this._queue = [];
126741
+
126742
+ if (this.fd === null) {
126743
+ this._open = fs.open;
126744
+ this._queue.push([this._open, this.path, this.flags, this.mode, undefined]);
126745
+ this.flush();
126746
+ }
126747
+ }
126748
+ }
126749
+ return legacyStreams;
126750
+ }
126751
+
126752
+ var clone_1;
126753
+ var hasRequiredClone;
126754
+
126755
+ function requireClone () {
126756
+ if (hasRequiredClone) return clone_1;
126757
+ hasRequiredClone = 1;
126758
+
126759
+ clone_1 = clone;
126760
+
126761
+ var getPrototypeOf = Object.getPrototypeOf || function (obj) {
126762
+ return obj.__proto__
126763
+ };
126764
+
126765
+ function clone (obj) {
126766
+ if (obj === null || typeof obj !== 'object')
126767
+ return obj
126768
+
126769
+ if (obj instanceof Object)
126770
+ var copy = { __proto__: getPrototypeOf(obj) };
126771
+ else
126772
+ var copy = Object.create(null);
126773
+
126774
+ Object.getOwnPropertyNames(obj).forEach(function (key) {
126775
+ Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key));
126776
+ });
126777
+
126778
+ return copy
126779
+ }
126780
+ return clone_1;
126781
+ }
126782
+
126783
+ var gracefulFs;
126784
+ var hasRequiredGracefulFs;
126785
+
126786
+ function requireGracefulFs () {
126787
+ if (hasRequiredGracefulFs) return gracefulFs;
126788
+ hasRequiredGracefulFs = 1;
126789
+ var fs = fs__default;
126790
+ var polyfills = requirePolyfills();
126791
+ var legacy = requireLegacyStreams();
126792
+ var clone = requireClone();
126793
+
126794
+ var util = require$$0$4;
126795
+
126796
+ /* istanbul ignore next - node 0.x polyfill */
126797
+ var gracefulQueue;
126798
+ var previousSymbol;
126799
+
126800
+ /* istanbul ignore else - node 0.x polyfill */
126801
+ if (typeof Symbol === 'function' && typeof Symbol.for === 'function') {
126802
+ gracefulQueue = Symbol.for('graceful-fs.queue');
126803
+ // This is used in testing by future versions
126804
+ previousSymbol = Symbol.for('graceful-fs.previous');
126805
+ } else {
126806
+ gracefulQueue = '___graceful-fs.queue';
126807
+ previousSymbol = '___graceful-fs.previous';
126808
+ }
126809
+
126810
+ function noop () {}
126811
+
126812
+ function publishQueue(context, queue) {
126813
+ Object.defineProperty(context, gracefulQueue, {
126814
+ get: function() {
126815
+ return queue
126816
+ }
126817
+ });
126818
+ }
126819
+
126820
+ var debug = noop;
126821
+ if (util.debuglog)
126822
+ debug = util.debuglog('gfs4');
126823
+ else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ''))
126824
+ debug = function() {
126825
+ var m = util.format.apply(util, arguments);
126826
+ m = 'GFS4: ' + m.split(/\n/).join('\nGFS4: ');
126827
+ console.error(m);
126828
+ };
126829
+
126830
+ // Once time initialization
126831
+ if (!fs[gracefulQueue]) {
126832
+ // This queue can be shared by multiple loaded instances
126833
+ var queue = commonjsGlobal[gracefulQueue] || [];
126834
+ publishQueue(fs, queue);
126835
+
126836
+ // Patch fs.close/closeSync to shared queue version, because we need
126837
+ // to retry() whenever a close happens *anywhere* in the program.
126838
+ // This is essential when multiple graceful-fs instances are
126839
+ // in play at the same time.
126840
+ fs.close = (function (fs$close) {
126841
+ function close (fd, cb) {
126842
+ return fs$close.call(fs, fd, function (err) {
126843
+ // This function uses the graceful-fs shared queue
126844
+ if (!err) {
126845
+ resetQueue();
126846
+ }
126847
+
126848
+ if (typeof cb === 'function')
126849
+ cb.apply(this, arguments);
126850
+ })
126851
+ }
126852
+
126853
+ Object.defineProperty(close, previousSymbol, {
126854
+ value: fs$close
126855
+ });
126856
+ return close
126857
+ })(fs.close);
126858
+
126859
+ fs.closeSync = (function (fs$closeSync) {
126860
+ function closeSync (fd) {
126861
+ // This function uses the graceful-fs shared queue
126862
+ fs$closeSync.apply(fs, arguments);
126863
+ resetQueue();
126864
+ }
126865
+
126866
+ Object.defineProperty(closeSync, previousSymbol, {
126867
+ value: fs$closeSync
126868
+ });
126869
+ return closeSync
126870
+ })(fs.closeSync);
126871
+
126872
+ if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) {
126873
+ process.on('exit', function() {
126874
+ debug(fs[gracefulQueue]);
126875
+ require$$0$5.equal(fs[gracefulQueue].length, 0);
126876
+ });
126877
+ }
126878
+ }
126879
+
126880
+ if (!commonjsGlobal[gracefulQueue]) {
126881
+ publishQueue(commonjsGlobal, fs[gracefulQueue]);
126882
+ }
126883
+
126884
+ gracefulFs = patch(clone(fs));
126885
+ if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
126886
+ gracefulFs = patch(fs);
126887
+ fs.__patched = true;
126888
+ }
126889
+
126890
+ function patch (fs) {
126891
+ // Everything that references the open() function needs to be in here
126892
+ polyfills(fs);
126893
+ fs.gracefulify = patch;
126894
+
126895
+ fs.createReadStream = createReadStream;
126896
+ fs.createWriteStream = createWriteStream;
126897
+ var fs$readFile = fs.readFile;
126898
+ fs.readFile = readFile;
126899
+ function readFile (path, options, cb) {
126900
+ if (typeof options === 'function')
126901
+ cb = options, options = null;
126902
+
126903
+ return go$readFile(path, options, cb)
126904
+
126905
+ function go$readFile (path, options, cb, startTime) {
126906
+ return fs$readFile(path, options, function (err) {
126907
+ if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
126908
+ enqueue([go$readFile, [path, options, cb], err, startTime || Date.now(), Date.now()]);
126909
+ else {
126910
+ if (typeof cb === 'function')
126911
+ cb.apply(this, arguments);
126912
+ }
126913
+ })
126914
+ }
126915
+ }
126916
+
126917
+ var fs$writeFile = fs.writeFile;
126918
+ fs.writeFile = writeFile;
126919
+ function writeFile (path, data, options, cb) {
126920
+ if (typeof options === 'function')
126921
+ cb = options, options = null;
126922
+
126923
+ return go$writeFile(path, data, options, cb)
126924
+
126925
+ function go$writeFile (path, data, options, cb, startTime) {
126926
+ return fs$writeFile(path, data, options, function (err) {
126927
+ if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
126928
+ enqueue([go$writeFile, [path, data, options, cb], err, startTime || Date.now(), Date.now()]);
126929
+ else {
126930
+ if (typeof cb === 'function')
126931
+ cb.apply(this, arguments);
126932
+ }
126933
+ })
126934
+ }
126935
+ }
126936
+
126937
+ var fs$appendFile = fs.appendFile;
126938
+ if (fs$appendFile)
126939
+ fs.appendFile = appendFile;
126940
+ function appendFile (path, data, options, cb) {
126941
+ if (typeof options === 'function')
126942
+ cb = options, options = null;
126943
+
126944
+ return go$appendFile(path, data, options, cb)
126945
+
126946
+ function go$appendFile (path, data, options, cb, startTime) {
126947
+ return fs$appendFile(path, data, options, function (err) {
126948
+ if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
126949
+ enqueue([go$appendFile, [path, data, options, cb], err, startTime || Date.now(), Date.now()]);
126950
+ else {
126951
+ if (typeof cb === 'function')
126952
+ cb.apply(this, arguments);
126953
+ }
126954
+ })
126955
+ }
126956
+ }
126957
+
126958
+ var fs$copyFile = fs.copyFile;
126959
+ if (fs$copyFile)
126960
+ fs.copyFile = copyFile;
126961
+ function copyFile (src, dest, flags, cb) {
126962
+ if (typeof flags === 'function') {
126963
+ cb = flags;
126964
+ flags = 0;
126965
+ }
126966
+ return go$copyFile(src, dest, flags, cb)
126967
+
126968
+ function go$copyFile (src, dest, flags, cb, startTime) {
126969
+ return fs$copyFile(src, dest, flags, function (err) {
126970
+ if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
126971
+ enqueue([go$copyFile, [src, dest, flags, cb], err, startTime || Date.now(), Date.now()]);
126972
+ else {
126973
+ if (typeof cb === 'function')
126974
+ cb.apply(this, arguments);
126975
+ }
126976
+ })
126977
+ }
126978
+ }
126979
+
126980
+ var fs$readdir = fs.readdir;
126981
+ fs.readdir = readdir;
126982
+ var noReaddirOptionVersions = /^v[0-5]\./;
126983
+ function readdir (path, options, cb) {
126984
+ if (typeof options === 'function')
126985
+ cb = options, options = null;
126986
+
126987
+ var go$readdir = noReaddirOptionVersions.test(process.version)
126988
+ ? function go$readdir (path, options, cb, startTime) {
126989
+ return fs$readdir(path, fs$readdirCallback(
126990
+ path, options, cb, startTime
126991
+ ))
126992
+ }
126993
+ : function go$readdir (path, options, cb, startTime) {
126994
+ return fs$readdir(path, options, fs$readdirCallback(
126995
+ path, options, cb, startTime
126996
+ ))
126997
+ };
126998
+
126999
+ return go$readdir(path, options, cb)
127000
+
127001
+ function fs$readdirCallback (path, options, cb, startTime) {
127002
+ return function (err, files) {
127003
+ if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
127004
+ enqueue([
127005
+ go$readdir,
127006
+ [path, options, cb],
127007
+ err,
127008
+ startTime || Date.now(),
127009
+ Date.now()
127010
+ ]);
127011
+ else {
127012
+ if (files && files.sort)
127013
+ files.sort();
127014
+
127015
+ if (typeof cb === 'function')
127016
+ cb.call(this, err, files);
127017
+ }
127018
+ }
127019
+ }
127020
+ }
127021
+
127022
+ if (process.version.substr(0, 4) === 'v0.8') {
127023
+ var legStreams = legacy(fs);
127024
+ ReadStream = legStreams.ReadStream;
127025
+ WriteStream = legStreams.WriteStream;
127026
+ }
127027
+
127028
+ var fs$ReadStream = fs.ReadStream;
127029
+ if (fs$ReadStream) {
127030
+ ReadStream.prototype = Object.create(fs$ReadStream.prototype);
127031
+ ReadStream.prototype.open = ReadStream$open;
127032
+ }
127033
+
127034
+ var fs$WriteStream = fs.WriteStream;
127035
+ if (fs$WriteStream) {
127036
+ WriteStream.prototype = Object.create(fs$WriteStream.prototype);
127037
+ WriteStream.prototype.open = WriteStream$open;
127038
+ }
127039
+
127040
+ Object.defineProperty(fs, 'ReadStream', {
127041
+ get: function () {
127042
+ return ReadStream
127043
+ },
127044
+ set: function (val) {
127045
+ ReadStream = val;
127046
+ },
127047
+ enumerable: true,
127048
+ configurable: true
127049
+ });
127050
+ Object.defineProperty(fs, 'WriteStream', {
127051
+ get: function () {
127052
+ return WriteStream
127053
+ },
127054
+ set: function (val) {
127055
+ WriteStream = val;
127056
+ },
127057
+ enumerable: true,
127058
+ configurable: true
127059
+ });
127060
+
127061
+ // legacy names
127062
+ var FileReadStream = ReadStream;
127063
+ Object.defineProperty(fs, 'FileReadStream', {
127064
+ get: function () {
127065
+ return FileReadStream
127066
+ },
127067
+ set: function (val) {
127068
+ FileReadStream = val;
127069
+ },
127070
+ enumerable: true,
127071
+ configurable: true
127072
+ });
127073
+ var FileWriteStream = WriteStream;
127074
+ Object.defineProperty(fs, 'FileWriteStream', {
127075
+ get: function () {
127076
+ return FileWriteStream
127077
+ },
127078
+ set: function (val) {
127079
+ FileWriteStream = val;
127080
+ },
127081
+ enumerable: true,
127082
+ configurable: true
127083
+ });
127084
+
127085
+ function ReadStream (path, options) {
127086
+ if (this instanceof ReadStream)
127087
+ return fs$ReadStream.apply(this, arguments), this
127088
+ else
127089
+ return ReadStream.apply(Object.create(ReadStream.prototype), arguments)
127090
+ }
127091
+
127092
+ function ReadStream$open () {
127093
+ var that = this;
127094
+ open(that.path, that.flags, that.mode, function (err, fd) {
127095
+ if (err) {
127096
+ if (that.autoClose)
127097
+ that.destroy();
127098
+
127099
+ that.emit('error', err);
127100
+ } else {
127101
+ that.fd = fd;
127102
+ that.emit('open', fd);
127103
+ that.read();
127104
+ }
127105
+ });
127106
+ }
127107
+
127108
+ function WriteStream (path, options) {
127109
+ if (this instanceof WriteStream)
127110
+ return fs$WriteStream.apply(this, arguments), this
127111
+ else
127112
+ return WriteStream.apply(Object.create(WriteStream.prototype), arguments)
127113
+ }
127114
+
127115
+ function WriteStream$open () {
127116
+ var that = this;
127117
+ open(that.path, that.flags, that.mode, function (err, fd) {
127118
+ if (err) {
127119
+ that.destroy();
127120
+ that.emit('error', err);
127121
+ } else {
127122
+ that.fd = fd;
127123
+ that.emit('open', fd);
127124
+ }
127125
+ });
127126
+ }
127127
+
127128
+ function createReadStream (path, options) {
127129
+ return new fs.ReadStream(path, options)
127130
+ }
127131
+
127132
+ function createWriteStream (path, options) {
127133
+ return new fs.WriteStream(path, options)
127134
+ }
127135
+
127136
+ var fs$open = fs.open;
127137
+ fs.open = open;
127138
+ function open (path, flags, mode, cb) {
127139
+ if (typeof mode === 'function')
127140
+ cb = mode, mode = null;
127141
+
127142
+ return go$open(path, flags, mode, cb)
127143
+
127144
+ function go$open (path, flags, mode, cb, startTime) {
127145
+ return fs$open(path, flags, mode, function (err, fd) {
127146
+ if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
127147
+ enqueue([go$open, [path, flags, mode, cb], err, startTime || Date.now(), Date.now()]);
127148
+ else {
127149
+ if (typeof cb === 'function')
127150
+ cb.apply(this, arguments);
127151
+ }
127152
+ })
127153
+ }
127154
+ }
127155
+
127156
+ return fs
127157
+ }
127158
+
127159
+ function enqueue (elem) {
127160
+ debug('ENQUEUE', elem[0].name, elem[1]);
127161
+ fs[gracefulQueue].push(elem);
127162
+ retry();
127163
+ }
127164
+
127165
+ // keep track of the timeout between retry() calls
127166
+ var retryTimer;
127167
+
127168
+ // reset the startTime and lastTime to now
127169
+ // this resets the start of the 60 second overall timeout as well as the
127170
+ // delay between attempts so that we'll retry these jobs sooner
127171
+ function resetQueue () {
127172
+ var now = Date.now();
127173
+ for (var i = 0; i < fs[gracefulQueue].length; ++i) {
127174
+ // entries that are only a length of 2 are from an older version, don't
127175
+ // bother modifying those since they'll be retried anyway.
127176
+ if (fs[gracefulQueue][i].length > 2) {
127177
+ fs[gracefulQueue][i][3] = now; // startTime
127178
+ fs[gracefulQueue][i][4] = now; // lastTime
127179
+ }
127180
+ }
127181
+ // call retry to make sure we're actively processing the queue
127182
+ retry();
127183
+ }
127184
+
127185
+ function retry () {
127186
+ // clear the timer and remove it to help prevent unintended concurrency
127187
+ clearTimeout(retryTimer);
127188
+ retryTimer = undefined;
127189
+
127190
+ if (fs[gracefulQueue].length === 0)
127191
+ return
127192
+
127193
+ var elem = fs[gracefulQueue].shift();
127194
+ var fn = elem[0];
127195
+ var args = elem[1];
127196
+ // these items may be unset if they were added by an older graceful-fs
127197
+ var err = elem[2];
127198
+ var startTime = elem[3];
127199
+ var lastTime = elem[4];
127200
+
127201
+ // if we don't have a startTime we have no way of knowing if we've waited
127202
+ // long enough, so go ahead and retry this item now
127203
+ if (startTime === undefined) {
127204
+ debug('RETRY', fn.name, args);
127205
+ fn.apply(null, args);
127206
+ } else if (Date.now() - startTime >= 60000) {
127207
+ // it's been more than 60 seconds total, bail now
127208
+ debug('TIMEOUT', fn.name, args);
127209
+ var cb = args.pop();
127210
+ if (typeof cb === 'function')
127211
+ cb.call(null, err);
127212
+ } else {
127213
+ // the amount of time between the last attempt and right now
127214
+ var sinceAttempt = Date.now() - lastTime;
127215
+ // the amount of time between when we first tried, and when we last tried
127216
+ // rounded up to at least 1
127217
+ var sinceStart = Math.max(lastTime - startTime, 1);
127218
+ // backoff. wait longer than the total time we've been retrying, but only
127219
+ // up to a maximum of 100ms
127220
+ var desiredDelay = Math.min(sinceStart * 1.2, 100);
127221
+ // it's been long enough since the last retry, do it again
127222
+ if (sinceAttempt >= desiredDelay) {
127223
+ debug('RETRY', fn.name, args);
127224
+ fn.apply(null, args.concat([startTime]));
127225
+ } else {
127226
+ // if we can't do this job yet, push it to the end of the queue
127227
+ // and let the next iteration check again
127228
+ fs[gracefulQueue].push(elem);
127229
+ }
127230
+ }
127231
+
127232
+ // schedule our next run if one isn't already scheduled
127233
+ if (retryTimer === undefined) {
127234
+ retryTimer = setTimeout(retry, 0);
127235
+ }
127236
+ }
127237
+ return gracefulFs;
127238
+ }
127239
+
127240
+ var retry$1 = {};
127241
+
127242
+ var retry_operation;
127243
+ var hasRequiredRetry_operation;
127244
+
127245
+ function requireRetry_operation () {
127246
+ if (hasRequiredRetry_operation) return retry_operation;
127247
+ hasRequiredRetry_operation = 1;
127248
+ function RetryOperation(timeouts, options) {
127249
+ // Compatibility for the old (timeouts, retryForever) signature
127250
+ if (typeof options === 'boolean') {
127251
+ options = { forever: options };
127252
+ }
127253
+
127254
+ this._originalTimeouts = JSON.parse(JSON.stringify(timeouts));
127255
+ this._timeouts = timeouts;
127256
+ this._options = options || {};
127257
+ this._maxRetryTime = options && options.maxRetryTime || Infinity;
127258
+ this._fn = null;
127259
+ this._errors = [];
127260
+ this._attempts = 1;
127261
+ this._operationTimeout = null;
127262
+ this._operationTimeoutCb = null;
127263
+ this._timeout = null;
127264
+ this._operationStart = null;
127265
+
127266
+ if (this._options.forever) {
127267
+ this._cachedTimeouts = this._timeouts.slice(0);
127268
+ }
127269
+ }
127270
+ retry_operation = RetryOperation;
127271
+
127272
+ RetryOperation.prototype.reset = function() {
127273
+ this._attempts = 1;
127274
+ this._timeouts = this._originalTimeouts;
127275
+ };
127276
+
127277
+ RetryOperation.prototype.stop = function() {
127278
+ if (this._timeout) {
127279
+ clearTimeout(this._timeout);
127280
+ }
127281
+
127282
+ this._timeouts = [];
127283
+ this._cachedTimeouts = null;
127284
+ };
127285
+
127286
+ RetryOperation.prototype.retry = function(err) {
127287
+ if (this._timeout) {
127288
+ clearTimeout(this._timeout);
127289
+ }
127290
+
127291
+ if (!err) {
127292
+ return false;
127293
+ }
127294
+ var currentTime = new Date().getTime();
127295
+ if (err && currentTime - this._operationStart >= this._maxRetryTime) {
127296
+ this._errors.unshift(new Error('RetryOperation timeout occurred'));
127297
+ return false;
127298
+ }
127299
+
127300
+ this._errors.push(err);
127301
+
127302
+ var timeout = this._timeouts.shift();
127303
+ if (timeout === undefined) {
127304
+ if (this._cachedTimeouts) {
127305
+ // retry forever, only keep last error
127306
+ this._errors.splice(this._errors.length - 1, this._errors.length);
127307
+ this._timeouts = this._cachedTimeouts.slice(0);
127308
+ timeout = this._timeouts.shift();
127309
+ } else {
127310
+ return false;
127311
+ }
127312
+ }
127313
+
127314
+ var self = this;
127315
+ var timer = setTimeout(function() {
127316
+ self._attempts++;
127317
+
127318
+ if (self._operationTimeoutCb) {
127319
+ self._timeout = setTimeout(function() {
127320
+ self._operationTimeoutCb(self._attempts);
127321
+ }, self._operationTimeout);
127322
+
127323
+ if (self._options.unref) {
127324
+ self._timeout.unref();
127325
+ }
127326
+ }
127327
+
127328
+ self._fn(self._attempts);
127329
+ }, timeout);
127330
+
127331
+ if (this._options.unref) {
127332
+ timer.unref();
127333
+ }
127334
+
127335
+ return true;
127336
+ };
127337
+
127338
+ RetryOperation.prototype.attempt = function(fn, timeoutOps) {
127339
+ this._fn = fn;
127340
+
127341
+ if (timeoutOps) {
127342
+ if (timeoutOps.timeout) {
127343
+ this._operationTimeout = timeoutOps.timeout;
127344
+ }
127345
+ if (timeoutOps.cb) {
127346
+ this._operationTimeoutCb = timeoutOps.cb;
127347
+ }
127348
+ }
127349
+
127350
+ var self = this;
127351
+ if (this._operationTimeoutCb) {
127352
+ this._timeout = setTimeout(function() {
127353
+ self._operationTimeoutCb();
127354
+ }, self._operationTimeout);
127355
+ }
127356
+
127357
+ this._operationStart = new Date().getTime();
127358
+
127359
+ this._fn(this._attempts);
127360
+ };
127361
+
127362
+ RetryOperation.prototype.try = function(fn) {
127363
+ console.log('Using RetryOperation.try() is deprecated');
127364
+ this.attempt(fn);
127365
+ };
127366
+
127367
+ RetryOperation.prototype.start = function(fn) {
127368
+ console.log('Using RetryOperation.start() is deprecated');
127369
+ this.attempt(fn);
127370
+ };
127371
+
127372
+ RetryOperation.prototype.start = RetryOperation.prototype.try;
127373
+
127374
+ RetryOperation.prototype.errors = function() {
127375
+ return this._errors;
127376
+ };
127377
+
127378
+ RetryOperation.prototype.attempts = function() {
127379
+ return this._attempts;
127380
+ };
127381
+
127382
+ RetryOperation.prototype.mainError = function() {
127383
+ if (this._errors.length === 0) {
127384
+ return null;
127385
+ }
127386
+
127387
+ var counts = {};
127388
+ var mainError = null;
127389
+ var mainErrorCount = 0;
127390
+
127391
+ for (var i = 0; i < this._errors.length; i++) {
127392
+ var error = this._errors[i];
127393
+ var message = error.message;
127394
+ var count = (counts[message] || 0) + 1;
127395
+
127396
+ counts[message] = count;
127397
+
127398
+ if (count >= mainErrorCount) {
127399
+ mainError = error;
127400
+ mainErrorCount = count;
127401
+ }
127402
+ }
127403
+
127404
+ return mainError;
127405
+ };
127406
+ return retry_operation;
127407
+ }
127408
+
127409
+ var hasRequiredRetry$1;
127410
+
127411
+ function requireRetry$1 () {
127412
+ if (hasRequiredRetry$1) return retry$1;
127413
+ hasRequiredRetry$1 = 1;
127414
+ (function (exports$1) {
127415
+ var RetryOperation = requireRetry_operation();
127416
+
127417
+ exports$1.operation = function(options) {
127418
+ var timeouts = exports$1.timeouts(options);
127419
+ return new RetryOperation(timeouts, {
127420
+ forever: options && options.forever,
127421
+ unref: options && options.unref,
127422
+ maxRetryTime: options && options.maxRetryTime
127423
+ });
127424
+ };
127425
+
127426
+ exports$1.timeouts = function(options) {
127427
+ if (options instanceof Array) {
127428
+ return [].concat(options);
127429
+ }
127430
+
127431
+ var opts = {
127432
+ retries: 10,
127433
+ factor: 2,
127434
+ minTimeout: 1 * 1000,
127435
+ maxTimeout: Infinity,
127436
+ randomize: false
127437
+ };
127438
+ for (var key in options) {
127439
+ opts[key] = options[key];
127440
+ }
127441
+
127442
+ if (opts.minTimeout > opts.maxTimeout) {
127443
+ throw new Error('minTimeout is greater than maxTimeout');
127444
+ }
127445
+
127446
+ var timeouts = [];
127447
+ for (var i = 0; i < opts.retries; i++) {
127448
+ timeouts.push(this.createTimeout(i, opts));
127449
+ }
127450
+
127451
+ if (options && options.forever && !timeouts.length) {
127452
+ timeouts.push(this.createTimeout(i, opts));
127453
+ }
127454
+
127455
+ // sort the array numerically ascending
127456
+ timeouts.sort(function(a,b) {
127457
+ return a - b;
127458
+ });
127459
+
127460
+ return timeouts;
127461
+ };
127462
+
127463
+ exports$1.createTimeout = function(attempt, opts) {
127464
+ var random = (opts.randomize)
127465
+ ? (Math.random() + 1)
127466
+ : 1;
127467
+
127468
+ var timeout = Math.round(random * opts.minTimeout * Math.pow(opts.factor, attempt));
127469
+ timeout = Math.min(timeout, opts.maxTimeout);
127470
+
127471
+ return timeout;
127472
+ };
127473
+
127474
+ exports$1.wrap = function(obj, options, methods) {
127475
+ if (options instanceof Array) {
127476
+ methods = options;
127477
+ options = null;
127478
+ }
127479
+
127480
+ if (!methods) {
127481
+ methods = [];
127482
+ for (var key in obj) {
127483
+ if (typeof obj[key] === 'function') {
127484
+ methods.push(key);
127485
+ }
127486
+ }
127487
+ }
127488
+
127489
+ for (var i = 0; i < methods.length; i++) {
127490
+ var method = methods[i];
127491
+ var original = obj[method];
127492
+
127493
+ obj[method] = function retryWrapper(original) {
127494
+ var op = exports$1.operation(options);
127495
+ var args = Array.prototype.slice.call(arguments, 1);
127496
+ var callback = args.pop();
127497
+
127498
+ args.push(function(err) {
127499
+ if (op.retry(err)) {
127500
+ return;
127501
+ }
127502
+ if (err) {
127503
+ arguments[0] = op.mainError();
127504
+ }
127505
+ callback.apply(this, arguments);
127506
+ });
127507
+
127508
+ op.attempt(function() {
127509
+ original.apply(obj, args);
127510
+ });
127511
+ }.bind(obj, original);
127512
+ obj[method].options = options;
127513
+ }
127514
+ };
127515
+ } (retry$1));
127516
+ return retry$1;
127517
+ }
127518
+
127519
+ var retry;
127520
+ var hasRequiredRetry;
127521
+
127522
+ function requireRetry () {
127523
+ if (hasRequiredRetry) return retry;
127524
+ hasRequiredRetry = 1;
127525
+ retry = requireRetry$1();
127526
+ return retry;
127527
+ }
127528
+
127529
+ var signalExit = {exports: {}};
127530
+
127531
+ var signals = {exports: {}};
127532
+
127533
+ var hasRequiredSignals;
127534
+
127535
+ function requireSignals () {
127536
+ if (hasRequiredSignals) return signals.exports;
127537
+ hasRequiredSignals = 1;
127538
+ (function (module) {
127539
+ // This is not the set of all possible signals.
127540
+ //
127541
+ // It IS, however, the set of all signals that trigger
127542
+ // an exit on either Linux or BSD systems. Linux is a
127543
+ // superset of the signal names supported on BSD, and
127544
+ // the unknown signals just fail to register, so we can
127545
+ // catch that easily enough.
127546
+ //
127547
+ // Don't bother with SIGKILL. It's uncatchable, which
127548
+ // means that we can't fire any callbacks anyway.
127549
+ //
127550
+ // If a user does happen to register a handler on a non-
127551
+ // fatal signal like SIGWINCH or something, and then
127552
+ // exit, it'll end up firing `process.emit('exit')`, so
127553
+ // the handler will be fired anyway.
127554
+ //
127555
+ // SIGBUS, SIGFPE, SIGSEGV and SIGILL, when not raised
127556
+ // artificially, inherently leave the process in a
127557
+ // state from which it is not safe to try and enter JS
127558
+ // listeners.
127559
+ module.exports = [
127560
+ 'SIGABRT',
127561
+ 'SIGALRM',
127562
+ 'SIGHUP',
127563
+ 'SIGINT',
127564
+ 'SIGTERM'
127565
+ ];
127566
+
127567
+ if (process.platform !== 'win32') {
127568
+ module.exports.push(
127569
+ 'SIGVTALRM',
127570
+ 'SIGXCPU',
127571
+ 'SIGXFSZ',
127572
+ 'SIGUSR2',
127573
+ 'SIGTRAP',
127574
+ 'SIGSYS',
127575
+ 'SIGQUIT',
127576
+ 'SIGIOT'
127577
+ // should detect profiler and enable/disable accordingly.
127578
+ // see #21
127579
+ // 'SIGPROF'
127580
+ );
127581
+ }
127582
+
127583
+ if (process.platform === 'linux') {
127584
+ module.exports.push(
127585
+ 'SIGIO',
127586
+ 'SIGPOLL',
127587
+ 'SIGPWR',
127588
+ 'SIGSTKFLT',
127589
+ 'SIGUNUSED'
127590
+ );
127591
+ }
127592
+ } (signals));
127593
+ return signals.exports;
127594
+ }
127595
+
127596
+ var hasRequiredSignalExit;
127597
+
127598
+ function requireSignalExit () {
127599
+ if (hasRequiredSignalExit) return signalExit.exports;
127600
+ hasRequiredSignalExit = 1;
127601
+ // Note: since nyc uses this module to output coverage, any lines
127602
+ // that are in the direct sync flow of nyc's outputCoverage are
127603
+ // ignored, since we can never get coverage for them.
127604
+ // grab a reference to node's real process object right away
127605
+ var process = commonjsGlobal.process;
127606
+
127607
+ const processOk = function (process) {
127608
+ return process &&
127609
+ typeof process === 'object' &&
127610
+ typeof process.removeListener === 'function' &&
127611
+ typeof process.emit === 'function' &&
127612
+ typeof process.reallyExit === 'function' &&
127613
+ typeof process.listeners === 'function' &&
127614
+ typeof process.kill === 'function' &&
127615
+ typeof process.pid === 'number' &&
127616
+ typeof process.on === 'function'
127617
+ };
127618
+
127619
+ // some kind of non-node environment, just no-op
127620
+ /* istanbul ignore if */
127621
+ if (!processOk(process)) {
127622
+ signalExit.exports = function () {
127623
+ return function () {}
127624
+ };
127625
+ } else {
127626
+ var assert = require$$0$5;
127627
+ var signals = requireSignals();
127628
+ var isWin = /^win/i.test(process.platform);
127629
+
127630
+ var EE = require$$1$3;
127631
+ /* istanbul ignore if */
127632
+ if (typeof EE !== 'function') {
127633
+ EE = EE.EventEmitter;
127634
+ }
127635
+
127636
+ var emitter;
127637
+ if (process.__signal_exit_emitter__) {
127638
+ emitter = process.__signal_exit_emitter__;
127639
+ } else {
127640
+ emitter = process.__signal_exit_emitter__ = new EE();
127641
+ emitter.count = 0;
127642
+ emitter.emitted = {};
127643
+ }
127644
+
127645
+ // Because this emitter is a global, we have to check to see if a
127646
+ // previous version of this library failed to enable infinite listeners.
127647
+ // I know what you're about to say. But literally everything about
127648
+ // signal-exit is a compromise with evil. Get used to it.
127649
+ if (!emitter.infinite) {
127650
+ emitter.setMaxListeners(Infinity);
127651
+ emitter.infinite = true;
127652
+ }
127653
+
127654
+ signalExit.exports = function (cb, opts) {
127655
+ /* istanbul ignore if */
127656
+ if (!processOk(commonjsGlobal.process)) {
127657
+ return function () {}
127658
+ }
127659
+ assert.equal(typeof cb, 'function', 'a callback must be provided for exit handler');
127660
+
127661
+ if (loaded === false) {
127662
+ load();
127663
+ }
127664
+
127665
+ var ev = 'exit';
127666
+ if (opts && opts.alwaysLast) {
127667
+ ev = 'afterexit';
127668
+ }
127669
+
127670
+ var remove = function () {
127671
+ emitter.removeListener(ev, cb);
127672
+ if (emitter.listeners('exit').length === 0 &&
127673
+ emitter.listeners('afterexit').length === 0) {
127674
+ unload();
127675
+ }
127676
+ };
127677
+ emitter.on(ev, cb);
127678
+
127679
+ return remove
127680
+ };
127681
+
127682
+ var unload = function unload () {
127683
+ if (!loaded || !processOk(commonjsGlobal.process)) {
127684
+ return
127685
+ }
127686
+ loaded = false;
127687
+
127688
+ signals.forEach(function (sig) {
127689
+ try {
127690
+ process.removeListener(sig, sigListeners[sig]);
127691
+ } catch (er) {}
127692
+ });
127693
+ process.emit = originalProcessEmit;
127694
+ process.reallyExit = originalProcessReallyExit;
127695
+ emitter.count -= 1;
127696
+ };
127697
+ signalExit.exports.unload = unload;
127698
+
127699
+ var emit = function emit (event, code, signal) {
127700
+ /* istanbul ignore if */
127701
+ if (emitter.emitted[event]) {
127702
+ return
127703
+ }
127704
+ emitter.emitted[event] = true;
127705
+ emitter.emit(event, code, signal);
127706
+ };
127707
+
127708
+ // { <signal>: <listener fn>, ... }
127709
+ var sigListeners = {};
127710
+ signals.forEach(function (sig) {
127711
+ sigListeners[sig] = function listener () {
127712
+ /* istanbul ignore if */
127713
+ if (!processOk(commonjsGlobal.process)) {
127714
+ return
127715
+ }
127716
+ // If there are no other listeners, an exit is coming!
127717
+ // Simplest way: remove us and then re-send the signal.
127718
+ // We know that this will kill the process, so we can
127719
+ // safely emit now.
127720
+ var listeners = process.listeners(sig);
127721
+ if (listeners.length === emitter.count) {
127722
+ unload();
127723
+ emit('exit', null, sig);
127724
+ /* istanbul ignore next */
127725
+ emit('afterexit', null, sig);
127726
+ /* istanbul ignore next */
127727
+ if (isWin && sig === 'SIGHUP') {
127728
+ // "SIGHUP" throws an `ENOSYS` error on Windows,
127729
+ // so use a supported signal instead
127730
+ sig = 'SIGINT';
127731
+ }
127732
+ /* istanbul ignore next */
127733
+ process.kill(process.pid, sig);
127734
+ }
127735
+ };
127736
+ });
127737
+
127738
+ signalExit.exports.signals = function () {
127739
+ return signals
127740
+ };
127741
+
127742
+ var loaded = false;
127743
+
127744
+ var load = function load () {
127745
+ if (loaded || !processOk(commonjsGlobal.process)) {
127746
+ return
127747
+ }
127748
+ loaded = true;
127749
+
127750
+ // This is the number of onSignalExit's that are in play.
127751
+ // It's important so that we can count the correct number of
127752
+ // listeners on signals, and don't wait for the other one to
127753
+ // handle it instead of us.
127754
+ emitter.count += 1;
127755
+
127756
+ signals = signals.filter(function (sig) {
127757
+ try {
127758
+ process.on(sig, sigListeners[sig]);
127759
+ return true
127760
+ } catch (er) {
127761
+ return false
127762
+ }
127763
+ });
127764
+
127765
+ process.emit = processEmit;
127766
+ process.reallyExit = processReallyExit;
127767
+ };
127768
+ signalExit.exports.load = load;
127769
+
127770
+ var originalProcessReallyExit = process.reallyExit;
127771
+ var processReallyExit = function processReallyExit (code) {
127772
+ /* istanbul ignore if */
127773
+ if (!processOk(commonjsGlobal.process)) {
127774
+ return
127775
+ }
127776
+ process.exitCode = code || /* istanbul ignore next */ 0;
127777
+ emit('exit', process.exitCode, null);
127778
+ /* istanbul ignore next */
127779
+ emit('afterexit', process.exitCode, null);
127780
+ /* istanbul ignore next */
127781
+ originalProcessReallyExit.call(process, process.exitCode);
127782
+ };
127783
+
127784
+ var originalProcessEmit = process.emit;
127785
+ var processEmit = function processEmit (ev, arg) {
127786
+ if (ev === 'exit' && processOk(commonjsGlobal.process)) {
127787
+ /* istanbul ignore else */
127788
+ if (arg !== undefined) {
127789
+ process.exitCode = arg;
127790
+ }
127791
+ var ret = originalProcessEmit.apply(this, arguments);
127792
+ /* istanbul ignore next */
127793
+ emit('exit', process.exitCode, null);
127794
+ /* istanbul ignore next */
127795
+ emit('afterexit', process.exitCode, null);
127796
+ /* istanbul ignore next */
127797
+ return ret
127798
+ } else {
127799
+ return originalProcessEmit.apply(this, arguments)
127800
+ }
127801
+ };
127802
+ }
127803
+ return signalExit.exports;
127804
+ }
127805
+
127806
+ var mtimePrecision = {};
127807
+
127808
+ var hasRequiredMtimePrecision;
127809
+
127810
+ function requireMtimePrecision () {
127811
+ if (hasRequiredMtimePrecision) return mtimePrecision;
127812
+ hasRequiredMtimePrecision = 1;
127813
+
127814
+ const cacheSymbol = Symbol();
127815
+
127816
+ function probe(file, fs, callback) {
127817
+ const cachedPrecision = fs[cacheSymbol];
127818
+
127819
+ if (cachedPrecision) {
127820
+ return fs.stat(file, (err, stat) => {
127821
+ /* istanbul ignore if */
127822
+ if (err) {
127823
+ return callback(err);
127824
+ }
127825
+
127826
+ callback(null, stat.mtime, cachedPrecision);
127827
+ });
127828
+ }
127829
+
127830
+ // Set mtime by ceiling Date.now() to seconds + 5ms so that it's "not on the second"
127831
+ const mtime = new Date((Math.ceil(Date.now() / 1000) * 1000) + 5);
127832
+
127833
+ fs.utimes(file, mtime, mtime, (err) => {
127834
+ /* istanbul ignore if */
127835
+ if (err) {
127836
+ return callback(err);
127837
+ }
127838
+
127839
+ fs.stat(file, (err, stat) => {
127840
+ /* istanbul ignore if */
127841
+ if (err) {
127842
+ return callback(err);
127843
+ }
127844
+
127845
+ const precision = stat.mtime.getTime() % 1000 === 0 ? 's' : 'ms';
127846
+
127847
+ // Cache the precision in a non-enumerable way
127848
+ Object.defineProperty(fs, cacheSymbol, { value: precision });
127849
+
127850
+ callback(null, stat.mtime, precision);
127851
+ });
127852
+ });
127853
+ }
127854
+
127855
+ function getMtime(precision) {
127856
+ let now = Date.now();
127857
+
127858
+ if (precision === 's') {
127859
+ now = Math.ceil(now / 1000) * 1000;
127860
+ }
127861
+
127862
+ return new Date(now);
127863
+ }
127864
+
127865
+ mtimePrecision.probe = probe;
127866
+ mtimePrecision.getMtime = getMtime;
127867
+ return mtimePrecision;
127868
+ }
127869
+
127870
+ var hasRequiredLockfile;
127871
+
127872
+ function requireLockfile () {
127873
+ if (hasRequiredLockfile) return lockfile;
127874
+ hasRequiredLockfile = 1;
127875
+
127876
+ const path = path__default;
127877
+ const fs = requireGracefulFs();
127878
+ const retry = requireRetry();
127879
+ const onExit = requireSignalExit();
127880
+ const mtimePrecision = requireMtimePrecision();
127881
+
127882
+ const locks = {};
127883
+
127884
+ function getLockFile(file, options) {
127885
+ return options.lockfilePath || `${file}.lock`;
127886
+ }
127887
+
127888
+ function resolveCanonicalPath(file, options, callback) {
127889
+ if (!options.realpath) {
127890
+ return callback(null, path.resolve(file));
127891
+ }
127892
+
127893
+ // Use realpath to resolve symlinks
127894
+ // It also resolves relative paths
127895
+ options.fs.realpath(file, callback);
127896
+ }
127897
+
127898
+ function acquireLock(file, options, callback) {
127899
+ const lockfilePath = getLockFile(file, options);
127900
+
127901
+ // Use mkdir to create the lockfile (atomic operation)
127902
+ options.fs.mkdir(lockfilePath, (err) => {
127903
+ if (!err) {
127904
+ // At this point, we acquired the lock!
127905
+ // Probe the mtime precision
127906
+ return mtimePrecision.probe(lockfilePath, options.fs, (err, mtime, mtimePrecision) => {
127907
+ // If it failed, try to remove the lock..
127908
+ /* istanbul ignore if */
127909
+ if (err) {
127910
+ options.fs.rmdir(lockfilePath, () => {});
127911
+
127912
+ return callback(err);
127913
+ }
127914
+
127915
+ callback(null, mtime, mtimePrecision);
127916
+ });
127917
+ }
127918
+
127919
+ // If error is not EEXIST then some other error occurred while locking
127920
+ if (err.code !== 'EEXIST') {
127921
+ return callback(err);
127922
+ }
127923
+
127924
+ // Otherwise, check if lock is stale by analyzing the file mtime
127925
+ if (options.stale <= 0) {
127926
+ return callback(Object.assign(new Error('Lock file is already being held'), { code: 'ELOCKED', file }));
127927
+ }
127928
+
127929
+ options.fs.stat(lockfilePath, (err, stat) => {
127930
+ if (err) {
127931
+ // Retry if the lockfile has been removed (meanwhile)
127932
+ // Skip stale check to avoid recursiveness
127933
+ if (err.code === 'ENOENT') {
127934
+ return acquireLock(file, { ...options, stale: 0 }, callback);
127935
+ }
127936
+
127937
+ return callback(err);
127938
+ }
127939
+
127940
+ if (!isLockStale(stat, options)) {
127941
+ return callback(Object.assign(new Error('Lock file is already being held'), { code: 'ELOCKED', file }));
127942
+ }
127943
+
127944
+ // If it's stale, remove it and try again!
127945
+ // Skip stale check to avoid recursiveness
127946
+ removeLock(file, options, (err) => {
127947
+ if (err) {
127948
+ return callback(err);
127949
+ }
127950
+
127951
+ acquireLock(file, { ...options, stale: 0 }, callback);
127952
+ });
127953
+ });
127954
+ });
127955
+ }
127956
+
127957
+ function isLockStale(stat, options) {
127958
+ return stat.mtime.getTime() < Date.now() - options.stale;
127959
+ }
127960
+
127961
+ function removeLock(file, options, callback) {
127962
+ // Remove lockfile, ignoring ENOENT errors
127963
+ options.fs.rmdir(getLockFile(file, options), (err) => {
127964
+ if (err && err.code !== 'ENOENT') {
127965
+ return callback(err);
127966
+ }
127967
+
127968
+ callback();
127969
+ });
127970
+ }
127971
+
127972
+ function updateLock(file, options) {
127973
+ const lock = locks[file];
127974
+
127975
+ // Just for safety, should never happen
127976
+ /* istanbul ignore if */
127977
+ if (lock.updateTimeout) {
127978
+ return;
127979
+ }
127980
+
127981
+ lock.updateDelay = lock.updateDelay || options.update;
127982
+ lock.updateTimeout = setTimeout(() => {
127983
+ lock.updateTimeout = null;
127984
+
127985
+ // Stat the file to check if mtime is still ours
127986
+ // If it is, we can still recover from a system sleep or a busy event loop
127987
+ options.fs.stat(lock.lockfilePath, (err, stat) => {
127988
+ const isOverThreshold = lock.lastUpdate + options.stale < Date.now();
127989
+
127990
+ // If it failed to update the lockfile, keep trying unless
127991
+ // the lockfile was deleted or we are over the threshold
127992
+ if (err) {
127993
+ if (err.code === 'ENOENT' || isOverThreshold) {
127994
+ return setLockAsCompromised(file, lock, Object.assign(err, { code: 'ECOMPROMISED' }));
127995
+ }
127996
+
127997
+ lock.updateDelay = 1000;
127998
+
127999
+ return updateLock(file, options);
128000
+ }
128001
+
128002
+ const isMtimeOurs = lock.mtime.getTime() === stat.mtime.getTime();
128003
+
128004
+ if (!isMtimeOurs) {
128005
+ return setLockAsCompromised(
128006
+ file,
128007
+ lock,
128008
+ Object.assign(
128009
+ new Error('Unable to update lock within the stale threshold'),
128010
+ { code: 'ECOMPROMISED' }
128011
+ ));
128012
+ }
128013
+
128014
+ const mtime = mtimePrecision.getMtime(lock.mtimePrecision);
128015
+
128016
+ options.fs.utimes(lock.lockfilePath, mtime, mtime, (err) => {
128017
+ const isOverThreshold = lock.lastUpdate + options.stale < Date.now();
128018
+
128019
+ // Ignore if the lock was released
128020
+ if (lock.released) {
128021
+ return;
128022
+ }
128023
+
128024
+ // If it failed to update the lockfile, keep trying unless
128025
+ // the lockfile was deleted or we are over the threshold
128026
+ if (err) {
128027
+ if (err.code === 'ENOENT' || isOverThreshold) {
128028
+ return setLockAsCompromised(file, lock, Object.assign(err, { code: 'ECOMPROMISED' }));
128029
+ }
128030
+
128031
+ lock.updateDelay = 1000;
128032
+
128033
+ return updateLock(file, options);
128034
+ }
128035
+
128036
+ // All ok, keep updating..
128037
+ lock.mtime = mtime;
128038
+ lock.lastUpdate = Date.now();
128039
+ lock.updateDelay = null;
128040
+ updateLock(file, options);
128041
+ });
128042
+ });
128043
+ }, lock.updateDelay);
128044
+
128045
+ // Unref the timer so that the nodejs process can exit freely
128046
+ // This is safe because all acquired locks will be automatically released
128047
+ // on process exit
128048
+
128049
+ // We first check that `lock.updateTimeout.unref` exists because some users
128050
+ // may be using this module outside of NodeJS (e.g., in an electron app),
128051
+ // and in those cases `setTimeout` return an integer.
128052
+ /* istanbul ignore else */
128053
+ if (lock.updateTimeout.unref) {
128054
+ lock.updateTimeout.unref();
128055
+ }
128056
+ }
128057
+
128058
+ function setLockAsCompromised(file, lock, err) {
128059
+ // Signal the lock has been released
128060
+ lock.released = true;
128061
+
128062
+ // Cancel lock mtime update
128063
+ // Just for safety, at this point updateTimeout should be null
128064
+ /* istanbul ignore if */
128065
+ if (lock.updateTimeout) {
128066
+ clearTimeout(lock.updateTimeout);
128067
+ }
128068
+
128069
+ if (locks[file] === lock) {
128070
+ delete locks[file];
128071
+ }
128072
+
128073
+ lock.options.onCompromised(err);
128074
+ }
128075
+
128076
+ // ----------------------------------------------------------
128077
+
128078
+ function lock(file, options, callback) {
128079
+ /* istanbul ignore next */
128080
+ options = {
128081
+ stale: 10000,
128082
+ update: null,
128083
+ realpath: true,
128084
+ retries: 0,
128085
+ fs,
128086
+ onCompromised: (err) => { throw err; },
128087
+ ...options,
128088
+ };
128089
+
128090
+ options.retries = options.retries || 0;
128091
+ options.retries = typeof options.retries === 'number' ? { retries: options.retries } : options.retries;
128092
+ options.stale = Math.max(options.stale || 0, 2000);
128093
+ options.update = options.update == null ? options.stale / 2 : options.update || 0;
128094
+ options.update = Math.max(Math.min(options.update, options.stale / 2), 1000);
128095
+
128096
+ // Resolve to a canonical file path
128097
+ resolveCanonicalPath(file, options, (err, file) => {
128098
+ if (err) {
128099
+ return callback(err);
128100
+ }
128101
+
128102
+ // Attempt to acquire the lock
128103
+ const operation = retry.operation(options.retries);
128104
+
128105
+ operation.attempt(() => {
128106
+ acquireLock(file, options, (err, mtime, mtimePrecision) => {
128107
+ if (operation.retry(err)) {
128108
+ return;
128109
+ }
128110
+
128111
+ if (err) {
128112
+ return callback(operation.mainError());
128113
+ }
128114
+
128115
+ // We now own the lock
128116
+ const lock = locks[file] = {
128117
+ lockfilePath: getLockFile(file, options),
128118
+ mtime,
128119
+ mtimePrecision,
128120
+ options,
128121
+ lastUpdate: Date.now(),
128122
+ };
128123
+
128124
+ // We must keep the lock fresh to avoid staleness
128125
+ updateLock(file, options);
128126
+
128127
+ callback(null, (releasedCallback) => {
128128
+ if (lock.released) {
128129
+ return releasedCallback &&
128130
+ releasedCallback(Object.assign(new Error('Lock is already released'), { code: 'ERELEASED' }));
128131
+ }
128132
+
128133
+ // Not necessary to use realpath twice when unlocking
128134
+ unlock(file, { ...options, realpath: false }, releasedCallback);
128135
+ });
128136
+ });
128137
+ });
128138
+ });
128139
+ }
128140
+
128141
+ function unlock(file, options, callback) {
128142
+ options = {
128143
+ fs,
128144
+ realpath: true,
128145
+ ...options,
128146
+ };
128147
+
128148
+ // Resolve to a canonical file path
128149
+ resolveCanonicalPath(file, options, (err, file) => {
128150
+ if (err) {
128151
+ return callback(err);
128152
+ }
128153
+
128154
+ // Skip if the lock is not acquired
128155
+ const lock = locks[file];
128156
+
128157
+ if (!lock) {
128158
+ return callback(Object.assign(new Error('Lock is not acquired/owned by you'), { code: 'ENOTACQUIRED' }));
128159
+ }
128160
+
128161
+ lock.updateTimeout && clearTimeout(lock.updateTimeout); // Cancel lock mtime update
128162
+ lock.released = true; // Signal the lock has been released
128163
+ delete locks[file]; // Delete from locks
128164
+
128165
+ removeLock(file, options, callback);
128166
+ });
128167
+ }
128168
+
128169
+ function check(file, options, callback) {
128170
+ options = {
128171
+ stale: 10000,
128172
+ realpath: true,
128173
+ fs,
128174
+ ...options,
128175
+ };
128176
+
128177
+ options.stale = Math.max(options.stale || 0, 2000);
128178
+
128179
+ // Resolve to a canonical file path
128180
+ resolveCanonicalPath(file, options, (err, file) => {
128181
+ if (err) {
128182
+ return callback(err);
128183
+ }
128184
+
128185
+ // Check if lockfile exists
128186
+ options.fs.stat(getLockFile(file, options), (err, stat) => {
128187
+ if (err) {
128188
+ // If does not exist, file is not locked. Otherwise, callback with error
128189
+ return err.code === 'ENOENT' ? callback(null, false) : callback(err);
128190
+ }
128191
+
128192
+ // Otherwise, check if lock is stale by analyzing the file mtime
128193
+ return callback(null, !isLockStale(stat, options));
128194
+ });
128195
+ });
128196
+ }
128197
+
128198
+ function getLocks() {
128199
+ return locks;
128200
+ }
128201
+
128202
+ // Remove acquired locks on exit
128203
+ /* istanbul ignore next */
128204
+ onExit(() => {
128205
+ for (const file in locks) {
128206
+ const options = locks[file].options;
128207
+
128208
+ try { options.fs.rmdirSync(getLockFile(file, options)); } catch (e) { /* Empty */ }
128209
+ }
128210
+ });
128211
+
128212
+ lockfile.lock = lock;
128213
+ lockfile.unlock = unlock;
128214
+ lockfile.check = check;
128215
+ lockfile.getLocks = getLocks;
128216
+ return lockfile;
128217
+ }
128218
+
128219
+ var adapter;
128220
+ var hasRequiredAdapter;
128221
+
128222
+ function requireAdapter () {
128223
+ if (hasRequiredAdapter) return adapter;
128224
+ hasRequiredAdapter = 1;
128225
+
128226
+ const fs = requireGracefulFs();
128227
+
128228
+ function createSyncFs(fs) {
128229
+ const methods = ['mkdir', 'realpath', 'stat', 'rmdir', 'utimes'];
128230
+ const newFs = { ...fs };
128231
+
128232
+ methods.forEach((method) => {
128233
+ newFs[method] = (...args) => {
128234
+ const callback = args.pop();
128235
+ let ret;
128236
+
128237
+ try {
128238
+ ret = fs[`${method}Sync`](...args);
128239
+ } catch (err) {
128240
+ return callback(err);
128241
+ }
128242
+
128243
+ callback(null, ret);
128244
+ };
128245
+ });
128246
+
128247
+ return newFs;
128248
+ }
128249
+
128250
+ // ----------------------------------------------------------
128251
+
128252
+ function toPromise(method) {
128253
+ return (...args) => new Promise((resolve, reject) => {
128254
+ args.push((err, result) => {
128255
+ if (err) {
128256
+ reject(err);
128257
+ } else {
128258
+ resolve(result);
128259
+ }
128260
+ });
128261
+
128262
+ method(...args);
128263
+ });
128264
+ }
128265
+
128266
+ function toSync(method) {
128267
+ return (...args) => {
128268
+ let err;
128269
+ let result;
128270
+
128271
+ args.push((_err, _result) => {
128272
+ err = _err;
128273
+ result = _result;
128274
+ });
128275
+
128276
+ method(...args);
128277
+
128278
+ if (err) {
128279
+ throw err;
128280
+ }
128281
+
128282
+ return result;
128283
+ };
128284
+ }
128285
+
128286
+ function toSyncOptions(options) {
128287
+ // Shallow clone options because we are oging to mutate them
128288
+ options = { ...options };
128289
+
128290
+ // Transform fs to use the sync methods instead
128291
+ options.fs = createSyncFs(options.fs || fs);
128292
+
128293
+ // Retries are not allowed because it requires the flow to be sync
128294
+ if (
128295
+ (typeof options.retries === 'number' && options.retries > 0) ||
128296
+ (options.retries && typeof options.retries.retries === 'number' && options.retries.retries > 0)
128297
+ ) {
128298
+ throw Object.assign(new Error('Cannot use retries with the sync api'), { code: 'ESYNC' });
128299
+ }
128300
+
128301
+ return options;
128302
+ }
128303
+
128304
+ adapter = {
128305
+ toPromise,
128306
+ toSync,
128307
+ toSyncOptions,
128308
+ };
128309
+ return adapter;
128310
+ }
128311
+
128312
+ var hasRequiredProperLockfile;
128313
+
128314
+ function requireProperLockfile () {
128315
+ if (hasRequiredProperLockfile) return properLockfile.exports;
128316
+ hasRequiredProperLockfile = 1;
128317
+
128318
+ const lockfile = requireLockfile();
128319
+ const { toPromise, toSync, toSyncOptions } = requireAdapter();
128320
+
128321
+ async function lock(file, options) {
128322
+ const release = await toPromise(lockfile.lock)(file, options);
128323
+
128324
+ return toPromise(release);
128325
+ }
128326
+
128327
+ function lockSync(file, options) {
128328
+ const release = toSync(lockfile.lock)(file, toSyncOptions(options));
128329
+
128330
+ return toSync(release);
128331
+ }
128332
+
128333
+ function unlock(file, options) {
128334
+ return toPromise(lockfile.unlock)(file, options);
128335
+ }
128336
+
128337
+ function unlockSync(file, options) {
128338
+ return toSync(lockfile.unlock)(file, toSyncOptions(options));
128339
+ }
128340
+
128341
+ function check(file, options) {
128342
+ return toPromise(lockfile.check)(file, options);
128343
+ }
128344
+
128345
+ function checkSync(file, options) {
128346
+ return toSync(lockfile.check)(file, toSyncOptions(options));
128347
+ }
128348
+
128349
+ properLockfile.exports = lock;
128350
+ properLockfile.exports.lock = lock;
128351
+ properLockfile.exports.unlock = unlock;
128352
+ properLockfile.exports.lockSync = lockSync;
128353
+ properLockfile.exports.unlockSync = unlockSync;
128354
+ properLockfile.exports.check = check;
128355
+ properLockfile.exports.checkSync = checkSync;
128356
+ return properLockfile.exports;
128357
+ }
128358
+
128359
+ var properLockfileExports = requireProperLockfile();
128360
+
128361
+ const DIR = "/tmp/neeto-auth-web";
126178
128362
  const CONFIG$1 = {
126179
- DIR: "/tmp/neeto-auth-web",
128363
+ DIR,
126180
128364
  LOG: "/tmp/neeto-auth-server.log",
126181
128365
  PORT: 9000,
126182
128366
  MAX_WAIT_MS: 120_000,
126183
- EMAIL_INIT: "/tmp/neeto-auth-web/config/initializers/playwright_email_capture.rb",
128367
+ WAIT_FOR_SERVER_POLL_MS: 3000,
128368
+ EMAIL_INIT: path.join(DIR, "config", "initializers", "playwright_email_capture.rb"),
128369
+ SETUP_COMPLETE_MARKER: path.join(DIR, ".playwright_setup_complete"),
128370
+ SETUP_LOCK: "/tmp/neeto-auth-web-setup.lock",
128371
+ SETUP_LOCK_STALE_MS: 30_000,
128372
+ SETUP_LOCK_UPDATE_MS: 10_000,
128373
+ SETUP_LOCK_RETRIES: 480,
128374
+ SETUP_LOCK_RETRY_INTERVAL_MS: 1000,
128375
+ SERVER_PID_FILE: path.join(DIR, "tmp", "pids", "server.pid"),
128376
+ DIR_RELEASE_TIMEOUT_MS: 5000,
128377
+ DIR_RELEASE_POLL_MS: 200,
128378
+ PROCESS_EXIT_TIMEOUT_MS: 10_000,
128379
+ PROCESS_EXIT_POLL_MS: 500,
128380
+ USERS_DIR: "/tmp/neeto-auth-web-users",
128381
+ USERS_LOCK: "/tmp/neeto-auth-web-users.lock",
128382
+ USERS_LOCK_STALE_MS: 30_000,
128383
+ USERS_LOCK_RETRIES: 400,
128384
+ USERS_LOCK_RETRY_INTERVAL_MS: 100,
126184
128385
  };
126185
128386
  const __dirname$2 = getDirname(import.meta.url);
126186
128387
  const SCRIPTS_DIR$1 = path.join(__dirname$2, "scripts", "neeto-auth");
@@ -126199,6 +128400,33 @@ const httpCheck$1 = (port, timeout = 3000) => new Promise(resolve => {
126199
128400
  resolve(false);
126200
128401
  });
126201
128402
  });
128403
+ const pollUntil = async (check, timeoutMs, intervalMs) => {
128404
+ const deadline = Date.now() + timeoutMs;
128405
+ while (Date.now() < deadline) {
128406
+ if (await check())
128407
+ return true;
128408
+ await sleep$1(intervalMs);
128409
+ }
128410
+ return false;
128411
+ };
128412
+ const isProcessAlive = (pid) => {
128413
+ try {
128414
+ process.kill(pid, 0);
128415
+ return true;
128416
+ }
128417
+ catch {
128418
+ return false;
128419
+ }
128420
+ };
128421
+ const listPids = (lsofArgs) => (spawnSync("lsof", ["-t", ...lsofArgs], { encoding: "utf-8" }).stdout ?? "")
128422
+ .split("\n")
128423
+ .map(Number)
128424
+ .filter(pid => Number.isInteger(pid) && pid > 0);
128425
+ // "-i" reads the argument as a port, "-sTCP:LISTEN" drops httpCheck's client sockets.
128426
+ const listServerPids = (port) => listPids(["-i", `tcp:${port}`, "-sTCP:LISTEN"]).filter(pid => pid !== process.pid);
128427
+ const readServerLog = () => fs.existsSync(CONFIG$1.LOG)
128428
+ ? fs.readFileSync(CONFIG$1.LOG, "utf-8")
128429
+ : "<no log file>";
126202
128430
  class NeetoAuthServer {
126203
128431
  process = null;
126204
128432
  targetApp;
@@ -126213,90 +128441,144 @@ class NeetoAuthServer {
126213
128441
  POSTGRES_USER: process.env.POSTGRES_USER ?? process.env.USER ?? "postgres",
126214
128442
  };
126215
128443
  }
126216
- waitForProcessExit = async (pid) => {
126217
- const deadline = Date.now() + 10_000;
126218
- while (Date.now() < deadline) {
126219
- try {
126220
- process.kill(pid, 0);
126221
- await sleep$1(500);
126222
- }
126223
- catch {
126224
- return;
126225
- }
126226
- }
128444
+ get userMarkerPath() {
128445
+ return path.join(CONFIG$1.USERS_DIR, String(process.pid));
128446
+ }
128447
+ registerAsUser = () => {
128448
+ fs.mkdirSync(CONFIG$1.USERS_DIR, { recursive: true });
128449
+ fs.writeFileSync(this.userMarkerPath, "");
128450
+ };
128451
+ // Deletes dead markers instead of skipping them: a reused pid would read as alive.
128452
+ listLiveUsers = () => {
128453
+ if (!fs.existsSync(CONFIG$1.USERS_DIR))
128454
+ return [];
128455
+ return fs.readdirSync(CONFIG$1.USERS_DIR).filter(pid => {
128456
+ if (isProcessAlive(Number(pid)))
128457
+ return true;
128458
+ fs.rmSync(path.join(CONFIG$1.USERS_DIR, pid), { force: true });
128459
+ return false;
128460
+ });
126227
128461
  };
128462
+ killPids = (pids, signal) => pids.forEach(pid => {
128463
+ try {
128464
+ process.kill(pid, signal);
128465
+ }
128466
+ catch {
128467
+ // Already gone.
128468
+ }
128469
+ });
128470
+ waitUntilDirIsFree = () => pollUntil(() => listPids(["+D", CONFIG$1.DIR]).length === 0, CONFIG$1.DIR_RELEASE_TIMEOUT_MS, CONFIG$1.DIR_RELEASE_POLL_MS);
126228
128471
  killServerOnPort = async () => {
128472
+ this.killPids(listServerPids(CONFIG$1.PORT), "SIGKILL");
128473
+ await sleep$1(1000);
128474
+ };
128475
+ acquireSetupLock = async () => {
126229
128476
  try {
126230
- execSync(`lsof -ti tcp:${CONFIG$1.PORT} | xargs kill -9`, {
126231
- stdio: "ignore",
128477
+ return await properLockfileExports.lock(CONFIG$1.DIR, {
128478
+ lockfilePath: CONFIG$1.SETUP_LOCK,
128479
+ realpath: false,
128480
+ stale: CONFIG$1.SETUP_LOCK_STALE_MS,
128481
+ update: CONFIG$1.SETUP_LOCK_UPDATE_MS,
128482
+ retries: {
128483
+ retries: CONFIG$1.SETUP_LOCK_RETRIES,
128484
+ minTimeout: CONFIG$1.SETUP_LOCK_RETRY_INTERVAL_MS,
128485
+ maxTimeout: CONFIG$1.SETUP_LOCK_RETRY_INTERVAL_MS,
128486
+ },
128487
+ onCompromised: error => log$1(`Setup lock was compromised: ${error.message}`),
126232
128488
  });
126233
- await sleep$1(1000);
126234
128489
  }
126235
- catch {
126236
- // No process on that port — nothing to kill.
128490
+ catch (error) {
128491
+ if (error.code !== "ELOCKED")
128492
+ throw error;
128493
+ throw new Error(`[NeetoAuth] Waited ${(CONFIG$1.SETUP_LOCK_RETRIES * CONFIG$1.SETUP_LOCK_RETRY_INTERVAL_MS) /
128494
+ 60_000} minutes for another worker to finish the neeto-auth-web setup, and it ` +
128495
+ `still holds ${CONFIG$1.SETUP_LOCK}. Delete that file if no setup is running.`);
126237
128496
  }
126238
128497
  };
126239
- ensureSetup = () => {
126240
- if (fs.existsSync(`${CONFIG$1.DIR}/Gemfile`)) {
128498
+ withSetupLock = async (fn) => {
128499
+ const release = await this.acquireSetupLock();
128500
+ try {
128501
+ await fn();
128502
+ }
128503
+ finally {
128504
+ // A compromised lock is already released; rethrowing here would mask fn()'s error.
128505
+ await release().catch(() => { });
128506
+ }
128507
+ };
128508
+ // Separate from the setup lock: the fast path must not queue behind a setup.
128509
+ withUsersLock = async (fn) => {
128510
+ const release = await properLockfileExports.lock(CONFIG$1.USERS_DIR, {
128511
+ lockfilePath: CONFIG$1.USERS_LOCK,
128512
+ realpath: false,
128513
+ stale: CONFIG$1.USERS_LOCK_STALE_MS,
128514
+ retries: {
128515
+ retries: CONFIG$1.USERS_LOCK_RETRIES,
128516
+ minTimeout: CONFIG$1.USERS_LOCK_RETRY_INTERVAL_MS,
128517
+ maxTimeout: CONFIG$1.USERS_LOCK_RETRY_INTERVAL_MS,
128518
+ },
128519
+ onCompromised: error => log$1(`Users lock was compromised: ${error.message}`),
128520
+ });
128521
+ try {
128522
+ return await fn();
128523
+ }
128524
+ finally {
128525
+ await release().catch(() => { });
128526
+ }
128527
+ };
128528
+ ensureSetup = async () => {
128529
+ if (fs.existsSync(CONFIG$1.SETUP_COMPLETE_MARKER)) {
126241
128530
  log$1("Already set up, skipping.");
126242
128531
  return;
126243
128532
  }
126244
128533
  if (!process.env.GITHUB_TOKEN) {
126245
128534
  throw new Error("[NeetoAuth] GITHUB_TOKEN is not set. Cannot clone neeto-auth-web.");
126246
128535
  }
128536
+ if (fs.existsSync(CONFIG$1.DIR)) {
128537
+ // We hold the setup lock and the port is free, so anything using this directory is an orphan.
128538
+ log$1("Found an incomplete previous setup — killing any lingering " +
128539
+ "process using it and cleaning up before retrying.");
128540
+ this.killPids(listPids(["+D", CONFIG$1.DIR]), "SIGKILL");
128541
+ await this.waitUntilDirIsFree();
128542
+ fs.rmSync(CONFIG$1.DIR, { recursive: true, force: true });
128543
+ }
126247
128544
  log$1("Running first-time setup...");
126248
- const setupScript = path.join(SCRIPTS_DIR$1, "setup.sh");
126249
128545
  try {
126250
- execSync(`bash "${setupScript}" "${CONFIG$1.DIR}"`, {
126251
- stdio: "inherit",
126252
- env: this.serverEnv,
126253
- });
128546
+ await this.runSetupScript();
128547
+ fs.writeFileSync(CONFIG$1.SETUP_COMPLETE_MARKER, "");
126254
128548
  }
126255
128549
  catch {
126256
128550
  throw new Error("[NeetoAuth] First-time setup failed. Check the output above for details.");
126257
128551
  }
126258
128552
  log$1("Setup complete.");
126259
128553
  };
128554
+ // Async, not execSync: a blocked event loop stops proper-lockfile refreshing the lock.
128555
+ runSetupScript = () => new Promise((resolve, reject) => {
128556
+ const setupScript = path.join(SCRIPTS_DIR$1, "setup.sh");
128557
+ const child = spawn("bash", [setupScript, CONFIG$1.DIR], {
128558
+ stdio: "inherit",
128559
+ env: this.serverEnv,
128560
+ });
128561
+ child.on("error", reject);
128562
+ child.on("exit", code => code === 0
128563
+ ? resolve()
128564
+ : reject(new Error(`setup.sh exited with code ${code}`)));
128565
+ });
126260
128566
  waitForServer = async (timeoutMs = CONFIG$1.MAX_WAIT_MS) => {
126261
- const startTime = Date.now();
126262
- while (Date.now() - startTime < timeoutMs) {
128567
+ const started = await pollUntil(() => {
126263
128568
  if (this.process !== null && this.process.exitCode !== null) {
126264
- const logContent = fs.existsSync(CONFIG$1.LOG)
126265
- ? fs.readFileSync(CONFIG$1.LOG, "utf-8")
126266
- : "<no log file>";
126267
- throw new Error(`[NeetoAuth] Server process exited unexpectedly with code ${this.process.exitCode}.\nLog:\n${logContent}`);
128569
+ throw new Error(`[NeetoAuth] Server process exited unexpectedly with code ${this.process.exitCode}.\nLog:\n${readServerLog()}`);
126268
128570
  }
126269
- if (await httpCheck$1(CONFIG$1.PORT))
126270
- return;
126271
- await sleep$1(3000);
126272
- }
126273
- const logContent = fs.existsSync(CONFIG$1.LOG)
126274
- ? fs.readFileSync(CONFIG$1.LOG, "utf-8")
126275
- : "<no log file>";
126276
- throw new Error(`[NeetoAuth] Server did not start within ${timeoutMs / 1000}s.\nLog:\n${logContent}`);
126277
- };
126278
- injectEmailCaptureInitializer = () => {
126279
- fs.writeFileSync(CONFIG$1.EMAIL_INIT, buildEmailCaptureInitializer(this.targetApp));
126280
- };
126281
- isRunningForCurrentApp = () => {
126282
- if (!fs.existsSync(CONFIG$1.EMAIL_INIT))
126283
- return false;
126284
- const currentContent = fs.readFileSync(CONFIG$1.EMAIL_INIT, "utf-8");
126285
- return currentContent === buildEmailCaptureInitializer(this.targetApp);
126286
- };
126287
- start = async () => {
126288
- if (IS_STAGING_ENV)
128571
+ return httpCheck$1(CONFIG$1.PORT);
128572
+ }, timeoutMs, CONFIG$1.WAIT_FOR_SERVER_POLL_MS);
128573
+ if (started)
126289
128574
  return;
126290
- if (await httpCheck$1(CONFIG$1.PORT)) {
126291
- if (this.isRunningForCurrentApp()) {
126292
- log$1("Server already running for this app.");
126293
- return;
126294
- }
126295
- log$1("Server running for a different app restarting...");
126296
- await this.killServerOnPort();
126297
- }
126298
- this.ensureSetup();
126299
- this.injectEmailCaptureInitializer();
128575
+ throw new Error(`[NeetoAuth] Server did not start within ${timeoutMs / 1000}s.\nLog:\n${readServerLog()}`);
128576
+ };
128577
+ spawnServer = async () => {
128578
+ // Nothing can be using a server that does not exist yet, so these are from a previous run.
128579
+ fs.rmSync(CONFIG$1.USERS_DIR, { recursive: true, force: true });
128580
+ // Puma refuses to start over a pidfile it thinks is alive; the port is already confirmed free, so this one is stale.
128581
+ fs.rmSync(CONFIG$1.SERVER_PID_FILE, { force: true });
126300
128582
  log$1("Starting server...");
126301
128583
  const logStream = fs.createWriteStream(CONFIG$1.LOG);
126302
128584
  this.process = spawn("bundle", [
@@ -126317,16 +128599,70 @@ class NeetoAuthServer {
126317
128599
  await this.waitForServer();
126318
128600
  log$1("Server ready.");
126319
128601
  };
126320
- stop = async () => {
126321
- if (IS_STAGING_ENV || !this.process)
128602
+ injectEmailCaptureInitializer = () => {
128603
+ fs.writeFileSync(CONFIG$1.EMAIL_INIT, buildEmailCaptureInitializer(this.targetApp));
128604
+ };
128605
+ isRunningForCurrentApp = () => {
128606
+ if (!fs.existsSync(CONFIG$1.EMAIL_INIT))
128607
+ return false;
128608
+ const currentContent = fs.readFileSync(CONFIG$1.EMAIL_INIT, "utf-8");
128609
+ return currentContent === buildEmailCaptureInitializer(this.targetApp);
128610
+ };
128611
+ isServingCurrentApp = async () => (await httpCheck$1(CONFIG$1.PORT)) && this.isRunningForCurrentApp();
128612
+ start = async () => {
128613
+ if (IS_STAGING_ENV)
128614
+ return;
128615
+ // Checking and registering under one lock stops us adopting a doomed server.
128616
+ const adopted = await this.withUsersLock(async () => {
128617
+ if (!(await this.isServingCurrentApp()))
128618
+ return false;
128619
+ this.registerAsUser();
128620
+ return true;
128621
+ });
128622
+ if (adopted) {
128623
+ log$1("Server already running for this app.");
126322
128624
  return;
126323
- const pid = this.process.pid;
126324
- log$1("Stopping server...");
126325
- this.process.kill("SIGTERM");
126326
- this.process = null;
126327
- if (pid) {
126328
- await this.waitForProcessExit(pid);
126329
128625
  }
128626
+ await this.withSetupLock(async () => {
128627
+ // Re-check: another worker may have finished setup while we waited for the lock.
128628
+ if (await this.isServingCurrentApp()) {
128629
+ log$1("Server already running for this app.");
128630
+ return;
128631
+ }
128632
+ if (await httpCheck$1(CONFIG$1.PORT)) {
128633
+ log$1("Server running for a different app — restarting...");
128634
+ await this.killServerOnPort();
128635
+ }
128636
+ await this.ensureSetup();
128637
+ this.injectEmailCaptureInitializer();
128638
+ await this.spawnServer();
128639
+ });
128640
+ await this.withUsersLock(async () => this.registerAsUser());
128641
+ };
128642
+ stop = async () => {
128643
+ if (IS_STAGING_ENV)
128644
+ return;
128645
+ // The kill stays inside the lock, or a worker could adopt the server in between.
128646
+ await this.withUsersLock(async () => {
128647
+ fs.rmSync(this.userMarkerPath, { force: true });
128648
+ if (this.listLiveUsers().length > 0) {
128649
+ log$1("Other workers still using the server — leaving it running.");
128650
+ return;
128651
+ }
128652
+ if (!this.isRunningForCurrentApp()) {
128653
+ log$1("Server on the port is serving another app — leaving it running.");
128654
+ this.process = null;
128655
+ return;
128656
+ }
128657
+ log$1("Stopping server...");
128658
+ const pids = listServerPids(CONFIG$1.PORT);
128659
+ this.killPids(pids, "SIGTERM");
128660
+ await Promise.all(pids.map(pid => pollUntil(() => !isProcessAlive(pid), CONFIG$1.PROCESS_EXIT_TIMEOUT_MS, CONFIG$1.PROCESS_EXIT_POLL_MS)));
128661
+ this.killPids(listServerPids(CONFIG$1.PORT), "SIGKILL"); // Any stragglers.
128662
+ // A start() that failed before binding leaves a child the sweep cannot see.
128663
+ this.process?.kill("SIGKILL");
128664
+ this.process = null;
128665
+ });
126330
128666
  };
126331
128667
  }
126332
128668
 
@@ -127451,4 +129787,4 @@ class InboundEmailApis {
127451
129787
  };
127452
129788
  }
127453
129789
 
127454
- export { ACTIONS, ADMIN_PANEL_SELECTORS, ALL_RESOURCES, ANALYTICS_RESOURCES, API_KEYS_SELECTORS, API_ROUTES, APP_RESOURCES, AUDIT_LOGS_SELECTORS, ApiKeysApi, ApiKeysPage, ApiKeysPageV2, AuditLogsPage, BASE_URL, CALENDAR_LABELS, CERTIFICATE_LIMIT_EXCEEDED_MESSAGE, CERTIFICATE_LIMIT_EXCEEDED_REGEXP, CERTIFICATE_PROVISION_FAILED_MESSAGE, CERTIFICATE_PROVISION_FAILED_REGEXP, CHANGELOG_WIDGET_SELECTORS, CHAT_WIDGET_SELECTORS, CHAT_WIDGET_TEXTS, COLOR, COMMON_SELECTORS, COMMON_TEXTS, COMMUNITY_TEXTS, CREDENTIALS, CURRENT_TIME_RANGES, CUSTOM_DOMAIN_SELECTORS, CUSTOM_DOMAIN_SUFFIX, ColorPickerUtils, CustomCommands, CustomCommandsV2, CustomDomainApi, CustomDomainPage, DATE_FORMATS, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DEFAULT_TIMEZONE_ID, DEFAULT_WEBHOOKS_RESPONSE_TEXT, DESCRIPTION_EDITOR_TEXTS, EDITOR_VERIFY_TEXT_COLOR, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXAMPLE_URL, EXPANDED_FONT_SIZE, EXPORT_FILE_TYPES, EditorPage, EmailDeliveryUtils, EmbedBase, FILE_FORMATS, FONTS_RESOURCES, FONT_SIZE_SELECTORS, FROM_EMAIL_ENV_KEYS, GLOBAL_TRANSLATIONS_PATTERN, GOOGLE_ANALYTICS_SELECTORS, GOOGLE_CALENDAR_DATE_FORMAT, GOOGLE_LOGIN_SELECTORS, GOOGLE_LOGIN_TEXTS, GOOGLE_SHEETS_SELECTORS, GooglePage, HELP_CENTER_ROUTES, HELP_CENTER_SELECTORS, HelpAndProfilePage, HelpAndProfilePageV2, INTEGRATIONS_TEXTS, INTEGRATION_SELECTORS, IPRestrictionsPage, IP_RESTRICTIONS_SELECTORS, IS_CI, IS_DEV_CI, IS_DEV_ENV, IS_MAILPIT_ENABLED, IS_PLAYWRIGHT_RUN, IS_SHADCN_UI, IS_STAGING_ENV, IS_WEBKIT, ImageUploader, InboundEmailApis, IntegrationBase, IpRestrictionsApi, KEYBOARD_SHORTCUTS_SELECTORS, KEYBOARD_SHORTCUT_TEST_CASES, LIST_MODIFIER_SELECTORS, LIST_MODIFIER_TAGS, LOGIN_SELECTORS, MAILPIT_BASE_URL, MAILPIT_DOMAIN_NAME, MEMBER_FORM_SELECTORS, MEMBER_SELECTORS, MEMBER_TEXTS, MERGE_TAGS_SELECTORS, MICROSOFT_LOGIN_SELECTORS, MICROSOFT_LOGIN_TEXTS, MailerUtils, MailpitApi, Member, MemberApis, MicrosoftPage, NEETO_AUTH_BASE_URL, NEETO_EDITOR_SELECTORS, NEETO_FILTERS_SELECTORS, NEETO_IMAGE_UPLOADER_SELECTORS, NEETO_ROUTES, NEETO_SEO_SELECTORS, NEETO_TEXT_MODIFIER_SELECTORS, NeetoAuthServer, NeetoChatWidget, NeetoEmailDeliveryApi, NeetoTowerApi, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PRODUCT_ROLES_ROUTE_MAP, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_NAMES, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RailsEmailApiClient, RailsEmailUtils, RoleApis, RolesPage, RolesPageV2, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SecurityApi, SidebarSection, SlackApi, SlackPage, SmsApi, SmsUtils, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEAM_MEMBER_TEXTS, TEXT_MODIFIER_ROLES, TEXT_MODIFIER_SELECTORS, TEXT_MODIFIER_TAGS, THANK_YOU_SELECTORS, THEMES_SELECTORS, THEMES_TEXTS, THIRD_PARTY_RESOURCES, THIRD_PARTY_ROUTES, TIME_RANGES, TOASTR_MESSAGES, TWILIO_SELECTORS, TagsApi, TagsPage, TeamMembers, TeamMembersV2, ThankYouApi, ThankYouPage, TwilioApi, USER_AGENTS, WEBHOOK_SELECTORS, WebhookSiteApi, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_TEST_EMAIL_V2, ZAPIER_WEB_TEXTS, ZapierPage, authenticateUser, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, createOrganizationViaApi, createOrganizationViaRake, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, exampleEmail, executeWithThrottledResources, extractSubdomainFromError, filterUtils, fixedMenuSelector, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getDirname, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getIsoCodeFromPhoneCode, getListCount, globalShortcuts, grantClipboardPermissions, hexToRGB, hexToRGBA, i18nFixture, imageRegex, initializeCredentials, initializeTestData, initializeTotp, isGithubIssueOpen, isStagingOrganizationExpired, joinHyphenCase, joinString, login, mailpitDomainName, minutesAgo, networkConditions, networkThrottlingUsingCDP, optionSelector, readFileAsBrowserFile, readFileSyncIfExists, removeCredentialFile, serializeFileForBrowser, shouldSkipCustomDomainSetup, shouldSkipSetupAndTeardown, simulateClickWithDelay, simulateTypingWithDelay, skipTest, squish, stealth as stealthTest, tableUtils, toCamelCase, updateCredentials, warmup, withCookieCache, writeDataToFile };
129790
+ export { ACTIONS, ADMIN_PANEL_SELECTORS, ALL_RESOURCES, ANALYTICS_RESOURCES, API_KEYS_SELECTORS, API_ROUTES, APP_RESOURCES, AUDIT_LOGS_SELECTORS, ApiKeysApi, ApiKeysPage, ApiKeysPageV2, AuditLogsPage, BASE_URL, CALENDAR_LABELS, CERTIFICATE_LIMIT_EXCEEDED_MESSAGE, CERTIFICATE_LIMIT_EXCEEDED_REGEXP, CERTIFICATE_PROVISION_FAILED_MESSAGE, CERTIFICATE_PROVISION_FAILED_REGEXP, CHANGELOG_WIDGET_SELECTORS, CHAT_WIDGET_SELECTORS, CHAT_WIDGET_TEXTS, COLOR, COMMON_SELECTORS, COMMON_TEXTS, COMMUNITY_TEXTS, CREDENTIALS, CURRENT_TIME_RANGES, CUSTOM_DOMAIN_SELECTORS, CUSTOM_DOMAIN_SUFFIX, ColorPickerUtils, CustomCommands, CustomCommandsV2, CustomDomainApi, CustomDomainPage, DATE_FORMATS, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DEFAULT_TIMEZONE_ID, DEFAULT_WEBHOOKS_RESPONSE_TEXT, DESCRIPTION_EDITOR_TEXTS, EDITOR_VERIFY_TEXT_COLOR, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXAMPLE_URL, EXPANDED_FONT_SIZE, EXPORT_FILE_TYPES, EditorPage, EmailDeliveryUtils, EmbedBase, FILE_FORMATS, FONTS_RESOURCES, FONT_SIZE_SELECTORS, FROM_EMAIL_ENV_KEYS, GLOBAL_TRANSLATIONS_PATTERN, GOOGLE_ANALYTICS_SELECTORS, GOOGLE_CALENDAR_DATE_FORMAT, GOOGLE_LOGIN_SELECTORS, GOOGLE_LOGIN_TEXTS, GOOGLE_SHEETS_SELECTORS, GooglePage, HELP_CENTER_ROUTES, HELP_CENTER_SELECTORS, HelpAndProfilePage, HelpAndProfilePageV2, INTEGRATIONS_TEXTS, INTEGRATION_SELECTORS, IPRestrictionsPage, IP_RESTRICTIONS_SELECTORS, IS_CI, IS_DEV_CI, IS_DEV_ENV, IS_MAILPIT_ENABLED, IS_PLAYWRIGHT_RUN, IS_REVIEW_ENV, IS_SHADCN_UI, IS_STAGING_ENV, IS_WEBKIT, ImageUploader, InboundEmailApis, IntegrationBase, IpRestrictionsApi, KEYBOARD_SHORTCUTS_SELECTORS, KEYBOARD_SHORTCUT_TEST_CASES, LIST_MODIFIER_SELECTORS, LIST_MODIFIER_TAGS, LOGIN_SELECTORS, MAILPIT_BASE_URL, MAILPIT_DOMAIN_NAME, MEMBER_FORM_SELECTORS, MEMBER_SELECTORS, MEMBER_TEXTS, MERGE_TAGS_SELECTORS, MICROSOFT_LOGIN_SELECTORS, MICROSOFT_LOGIN_TEXTS, MailerUtils, MailpitApi, Member, MemberApis, MicrosoftPage, NEETO_AUTH_BASE_URL, NEETO_EDITOR_SELECTORS, NEETO_FILTERS_SELECTORS, NEETO_IMAGE_UPLOADER_SELECTORS, NEETO_ROUTES, NEETO_SEO_SELECTORS, NEETO_TEXT_MODIFIER_SELECTORS, NeetoAuthServer, NeetoChatWidget, NeetoEmailDeliveryApi, NeetoTowerApi, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PRODUCT_ROLES_ROUTE_MAP, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_NAMES, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RailsEmailApiClient, RailsEmailUtils, RoleApis, RolesPage, RolesPageV2, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SecurityApi, SidebarSection, SlackApi, SlackPage, SmsApi, SmsUtils, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEAM_MEMBER_TEXTS, TEXT_MODIFIER_ROLES, TEXT_MODIFIER_SELECTORS, TEXT_MODIFIER_TAGS, THANK_YOU_SELECTORS, THEMES_SELECTORS, THEMES_TEXTS, THIRD_PARTY_RESOURCES, THIRD_PARTY_ROUTES, TIME_RANGES, TOASTR_MESSAGES, TWILIO_SELECTORS, TagsApi, TagsPage, TeamMembers, TeamMembersV2, ThankYouApi, ThankYouPage, TwilioApi, USER_AGENTS, WEBHOOK_SELECTORS, WebhookSiteApi, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_TEST_EMAIL_V2, ZAPIER_WEB_TEXTS, ZapierPage, authenticateUser, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, createOrganizationViaApi, createOrganizationViaRake, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, exampleEmail, executeWithThrottledResources, extractSubdomainFromError, filterUtils, fixedMenuSelector, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getDirname, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getIsoCodeFromPhoneCode, getListCount, globalShortcuts, grantClipboardPermissions, hexToRGB, hexToRGBA, i18nFixture, imageRegex, initializeCredentials, initializeReviewAppCredentials, initializeTestData, initializeTotp, isGithubIssueOpen, isStagingOrganizationExpired, joinHyphenCase, joinString, login, loginToReviewApp, mailpitDomainName, minutesAgo, networkConditions, networkThrottlingUsingCDP, optionSelector, readFileAsBrowserFile, readFileSyncIfExists, removeCredentialFile, reviewAppBaseURL, serializeFileForBrowser, shouldSkipCustomDomainSetup, shouldSkipSetupAndTeardown, simulateClickWithDelay, simulateTypingWithDelay, skipTest, squish, stealth as stealthTest, tableUtils, toCamelCase, updateCredentials, waitForReviewApp, warmup, withCookieCache, writeDataToFile };