fyn 2.0.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/fyn.js +1218 -268
  2. package/package.json +1 -1
package/dist/fyn.js CHANGED
@@ -132,6 +132,7 @@ const PromiseQueue = __webpack_require__("./lib/util/promise-queue.ts");
132
132
  const sortObjKeys = __webpack_require__("./lib/util/sort-obj-keys.ts");
133
133
  const fyntil = __webpack_require__("./lib/util/fyntil.ts");
134
134
  const showStat = __webpack_require__("./cli/show-stat.ts");
135
+ const showAudit = __webpack_require__("./cli/show-audit.ts");
135
136
  const { runNpmScript, addNpmLifecycle } = __webpack_require__("./lib/util/run-npm-script.ts");
136
137
  const { initEnv, makeNpmEnv } = __webpack_require__("./lib/util/make-npm-env.ts");
137
138
  const runScript = __webpack_require__("./node_modules/.f/_/@npmcli/run-script/10.0.2/@npmcli/run-script/lib/run-script.js");
@@ -437,10 +438,11 @@ class FynCli {
437
438
  * 3. postinstall
438
439
  * 4. prepare
439
440
  */
440
- install() {
441
+ install(argv = {}) {
441
442
  let failure;
442
443
  let installLocked;
443
444
  const start = Date.now();
445
+ const runAudit = argv.opts?.audit !== false;
444
446
  return Promise.try(() => this.fyn._initializePkg()).then(async () => {
445
447
  checkNewVersion(this.fyn._options);
446
448
  if (!this.fyn._changeProdMode && !this.fyn._options.forceInstall && this.fyn._installConfig.time) {
@@ -528,6 +530,17 @@ class FynCli {
528
530
  chalk.green("complete in total"),
529
531
  chalk.magenta(`${(end - start) / 1e3}`) + "secs"
530
532
  );
533
+ if (runAudit) {
534
+ try {
535
+ await showAudit(this.fyn, {
536
+ colors: this.fyn._options.colors !== false,
537
+ summary: true
538
+ // Show brief summary, not full report
539
+ });
540
+ } catch (err) {
541
+ logger.warn("Security audit failed:", err.message);
542
+ }
543
+ }
531
544
  }).catch((err) => {
532
545
  if (err.message === "No Change") {
533
546
  logger.info(`No changes detected since last fyn install - nothing to be done.
@@ -555,6 +568,17 @@ class FynCli {
555
568
  return this._opts.saveLogs && this.saveLogs(this._opts.saveLogs);
556
569
  });
557
570
  }
571
+ audit(argv) {
572
+ const opts = {
573
+ json: argv.opts?.json || false,
574
+ omit: argv.opts?.omit || [],
575
+ auditLevel: argv.opts?.auditLevel || "info",
576
+ noCache: argv.opts?.noCache || false
577
+ };
578
+ return showAudit(this.fyn, opts).finally(() => {
579
+ return this._opts.saveLogs && this.saveLogs(this._opts.saveLogs);
580
+ });
581
+ }
558
582
  async runScript(pkg, script, env, scriptArgs = []) {
559
583
  const config = (x) => this.fyn.allrc[x];
560
584
  const options = {
@@ -1005,7 +1029,7 @@ const commands = {
1005
1029
  desc: "Install modules",
1006
1030
  async exec(cmd) {
1007
1031
  const cli = new FynCli(await pickOptions(cmd));
1008
- return cli.install();
1032
+ return cli.install(cmd.jsonMeta);
1009
1033
  },
1010
1034
  options: {
1011
1035
  "run-npm": {
@@ -1016,6 +1040,11 @@ const commands = {
1016
1040
  alias: "fi",
1017
1041
  desc: "force install even if no files changed since last install",
1018
1042
  args: "<flag boolean>"
1043
+ },
1044
+ audit: {
1045
+ desc: "run security audit after install (use --no-audit to skip)",
1046
+ args: "<flag boolean>",
1047
+ default: true
1019
1048
  }
1020
1049
  }
1021
1050
  },
@@ -1040,7 +1069,7 @@ const commands = {
1040
1069
  config.noStartupInfo = true;
1041
1070
  logger.info("installing...");
1042
1071
  fynTil.resetFynpo();
1043
- return new FynCli(config).install();
1072
+ return new FynCli(config).install({ opts: { audit: meta.opts.audit } });
1044
1073
  });
1045
1074
  },
1046
1075
  options: {
@@ -1110,6 +1139,32 @@ const commands = {
1110
1139
  return new FynCli(await pickOptions(cmd)).stat(cmd.jsonMeta);
1111
1140
  }
1112
1141
  },
1142
+ audit: {
1143
+ desc: "Check for known security vulnerabilities",
1144
+ exec: async (cmd) => {
1145
+ return new FynCli(await pickOptions(cmd)).audit(cmd.jsonMeta);
1146
+ },
1147
+ options: {
1148
+ json: {
1149
+ alias: "j",
1150
+ args: "<flag boolean>",
1151
+ desc: "Output audit report as JSON"
1152
+ },
1153
+ omit: {
1154
+ args: "[types string..]",
1155
+ desc: "Dependency types to omit (dev, optional, peer)"
1156
+ },
1157
+ "audit-level": {
1158
+ args: "<level string>",
1159
+ desc: "Minimum severity level to report (info, low, moderate, high, critical)",
1160
+ default: "info"
1161
+ },
1162
+ "no-cache": {
1163
+ args: "<flag boolean>",
1164
+ desc: "Bypass the audit cache and fetch fresh data"
1165
+ }
1166
+ }
1167
+ },
1113
1168
  run: {
1114
1169
  desc: "Run a npm script",
1115
1170
  args: "[script string] [args...]",
@@ -1437,6 +1492,95 @@ const myPkg = JSON.parse(Fs.readFileSync(Path.join(__dirname, "../package.json")
1437
1492
  module.exports = myPkg;
1438
1493
 
1439
1494
 
1495
+ /***/ }),
1496
+
1497
+ /***/ "./cli/show-audit.ts":
1498
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1499
+
1500
+ "use strict";
1501
+
1502
+ const Promise = __webpack_require__("./node_modules/.f/_/aveazul/1.1.0/aveazul/cjs-entry.cjs");
1503
+ const CliLogger = __webpack_require__("./lib/cli-logger.ts");
1504
+ const logger = __webpack_require__("./lib/logger.ts");
1505
+ const AuditReport = __webpack_require__("./lib/audit/audit-report.ts");
1506
+ const AuditFormatter = __webpack_require__("./lib/audit/audit-formatter.ts");
1507
+ const PkgStatProvider = __webpack_require__("./lib/pkg-stat-provider.ts");
1508
+ const { FETCH_META } = __webpack_require__("./lib/log-items.ts");
1509
+ class ShowAudit {
1510
+ /**
1511
+ * @param {Object} options
1512
+ * @param {Object} options.fyn - Fyn instance
1513
+ * @param {Object} options.opts - CLI options
1514
+ */
1515
+ constructor({ fyn, opts }) {
1516
+ this._fyn = fyn;
1517
+ this._opts = opts || {};
1518
+ this._fyn._options.buildLocal = false;
1519
+ }
1520
+ /**
1521
+ * Run the audit workflow.
1522
+ *
1523
+ * @returns {Promise<void>}
1524
+ */
1525
+ async runAudit() {
1526
+ const spinner = CliLogger.spinners[1];
1527
+ try {
1528
+ let depData = this._fyn._data;
1529
+ if (!depData || Object.keys(depData.pkgs || {}).length === 0) {
1530
+ logger.addItem({ name: FETCH_META, color: "green", spinner });
1531
+ logger.updateItem(FETCH_META, "resolving dependencies...");
1532
+ await this._fyn.resolveDependencies();
1533
+ logger.removeItem(FETCH_META);
1534
+ depData = this._fyn._data;
1535
+ }
1536
+ const pkgCount = Object.keys(depData.pkgs).length;
1537
+ if (pkgCount === 0) {
1538
+ logger.info("No dependencies to audit");
1539
+ return;
1540
+ }
1541
+ logger.addItem({ name: FETCH_META, color: "green", spinner });
1542
+ logger.updateItem(FETCH_META, "fetching security advisories...");
1543
+ const auditReport = new AuditReport({
1544
+ fyn: this._fyn,
1545
+ depData,
1546
+ noCache: this._opts.noCache || false,
1547
+ omit: this._opts.omit || []
1548
+ });
1549
+ const auditResult = await auditReport.fetchAdvisories();
1550
+ logger.removeItem(FETCH_META);
1551
+ const vulnerabilities = auditReport.matchVulnerabilities(auditResult);
1552
+ let statProvider = null;
1553
+ if (!this._opts.summary && !this._opts.json) {
1554
+ statProvider = new PkgStatProvider({ fyn: this._fyn });
1555
+ }
1556
+ const formatter = new AuditFormatter({
1557
+ json: this._opts.json || false,
1558
+ colors: this._fyn._options.colors !== false,
1559
+ auditLevel: this._opts.auditLevel || "info",
1560
+ summary: this._opts.summary || false,
1561
+ statProvider
1562
+ });
1563
+ if (statProvider) {
1564
+ await formatter.precomputeStats(vulnerabilities);
1565
+ }
1566
+ const { output } = formatter.format(auditResult, vulnerabilities);
1567
+ if (output) {
1568
+ console.log(output);
1569
+ }
1570
+ } catch (err) {
1571
+ logger.removeItem(FETCH_META);
1572
+ logger.error("Audit failed:", err.message);
1573
+ if (process.env.FYN_DEBUG) {
1574
+ logger.error(err.stack);
1575
+ }
1576
+ }
1577
+ }
1578
+ }
1579
+ module.exports = (fyn, opts) => {
1580
+ return new ShowAudit({ fyn, opts }).runAudit();
1581
+ };
1582
+
1583
+
1440
1584
  /***/ }),
1441
1585
 
1442
1586
  /***/ "./cli/show-stat.ts":
@@ -1447,13 +1591,10 @@ module.exports = myPkg;
1447
1591
  const chalk = __webpack_require__("./node_modules/.f/_/chalk/4.1.2/chalk/source/index.js");
1448
1592
  const CliLogger = __webpack_require__("./lib/cli-logger.ts");
1449
1593
  const logger = __webpack_require__("./lib/logger.ts");
1450
- const _ = __webpack_require__("./node_modules/.f/_/lodash/4.17.21/lodash/lodash.min.js");
1451
- const semverUtil = __webpack_require__("./lib/util/semver.ts");
1452
1594
  const Promise = __webpack_require__("./node_modules/.f/_/aveazul/1.1.0/aveazul/cjs-entry.cjs");
1453
1595
  const logFormat = __webpack_require__("./lib/util/log-format.ts");
1454
- const PkgDepLinker = __webpack_require__("./lib/pkg-dep-linker.ts");
1596
+ const PkgStatProvider = __webpack_require__("./lib/pkg-stat-provider.ts");
1455
1597
  const { FETCH_META } = __webpack_require__("./lib/log-items.ts");
1456
- const { SEMVER } = __webpack_require__("./lib/symbols.ts");
1457
1598
  const PACKAGE_JSON = "~package.json";
1458
1599
  const formatPkgId = (pkg) => {
1459
1600
  if (pkg.name === PACKAGE_JSON) {
@@ -1462,220 +1603,52 @@ const formatPkgId = (pkg) => {
1462
1603
  const top = pkg.promoted ? "" : "\u2B07";
1463
1604
  return `${logFormat.pkgId(pkg)}${top}`;
1464
1605
  };
1465
- const getPkgId = (pkg) => {
1466
- if (pkg.name === PACKAGE_JSON) {
1467
- return pkg.name;
1468
- }
1469
- return `${pkg.name}@${pkg.version}`;
1470
- };
1471
1606
  class ShowStat {
1472
1607
  constructor({ fyn }) {
1473
1608
  this._fyn = fyn;
1474
1609
  this._fyn._options.buildLocal = false;
1475
- }
1476
- // returns array of packages match id
1477
- findPkgsById(pkgs, id) {
1478
- const ix = id.indexOf("@", 1);
1479
- const sx = ix > 0 ? ix : id.length;
1480
- const name = id.substr(0, sx);
1481
- const semver = id.substr(sx + 1);
1482
- return _(pkgs[name]).map((vpkg, version) => {
1483
- if (!semver || semverUtil.satisfies(version, semver)) {
1484
- return vpkg;
1485
- }
1486
- }).filter((x) => x).value();
1487
- }
1488
- findDependents(pkgs, ask) {
1489
- const dependents = [];
1490
- if (!this._fynRes) {
1491
- const depLinker = new PkgDepLinker({ fyn: this._fyn });
1492
- this._fynRes = depLinker.makeAppFynRes(this._fyn._data.res, {});
1493
- }
1494
- const check = (res, vpkg) => {
1495
- const semv = ask.local ? semverUtil.unlocalify(ask.version) : ask.version;
1496
- if (res && semverUtil.satisfies(res.resolved, semv)) {
1497
- dependents.push(vpkg);
1498
- }
1499
- };
1500
- for (const name in pkgs) {
1501
- const pkg = pkgs[name];
1502
- for (const version in pkg) {
1503
- const vpkg = pkg[version];
1504
- ["dep", "opt", "per"].forEach((s) => {
1505
- const x = vpkg.res[s];
1506
- check(x && x[ask.name], vpkg);
1507
- });
1508
- }
1509
- }
1510
- check(this._fynRes[ask.name], { name: PACKAGE_JSON, promoted: true });
1511
- return dependents;
1512
- }
1513
- showPkgDependents(pkgs, ask) {
1514
- const dependents = this.findDependents(pkgs, ask).sort((a, b) => {
1515
- if (a.name === b.name) {
1516
- return semverUtil.simpleCompare(a.version, b.version);
1517
- }
1518
- return a.name > b.name ? 1 : -1;
1519
- });
1520
- if (dependents.length > 0) {
1521
- logger.prefix("").info(
1522
- "=>",
1523
- logFormat.pkgId(ask),
1524
- `has ${dependents.length} dependents:`,
1525
- dependents.map(formatPkgId).join(" ")
1526
- );
1527
- }
1528
- return dependents;
1610
+ this._statProvider = new PkgStatProvider({ fyn });
1529
1611
  }
1530
1612
  _show(pkgIds) {
1531
- const data = this._fyn._data;
1532
- this._dependentsCache = {};
1533
- let groups = {};
1534
- return Promise.each(pkgIds, (pkgId) => {
1535
- const askPkgs = this.findPkgsById(data.pkgs, pkgId).sort(
1536
- (a, b) => semverUtil.simpleCompare(a.version, b.version)
1537
- );
1538
- if (askPkgs.length === 0) {
1613
+ return Promise.each(pkgIds, async (pkgId) => {
1614
+ const matches = this._statProvider.findMatchingVersions(pkgId);
1615
+ if (matches.versions.length === 0) {
1539
1616
  logger.prefix("").info(chalk.yellow(pkgId), "is not installed");
1540
1617
  } else {
1541
1618
  logger.prefix("").info(
1542
1619
  chalk.green.bgRed(pkgId),
1543
1620
  "matched these installed versions",
1544
- askPkgs.map(formatPkgId).join(" ")
1621
+ matches.versions.map(formatPkgId).join(" ")
1545
1622
  );
1546
- return Promise.each(askPkgs, (ask) => {
1547
- const specificId = getPkgId(ask);
1548
- const deps = this.showPkgDependents(data.pkgs, ask);
1549
- this._allPaths = [];
1550
- return this._findDepPaths(deps.map(getPkgId), [specificId], ask.name).then(() => {
1551
- const newGroups = _.groupBy(this._allPaths, (x) => x[x.length - 1]);
1552
- groups = { ...groups, ...newGroups };
1553
- const paths = groups[specificId];
1554
- if (paths && paths.length > 0) {
1555
- this._displayPaths(specificId, paths);
1556
- }
1557
- });
1558
- });
1559
- }
1560
- }).then(() => {
1561
- logger.info(chalk.green(`stat completed for ${pkgIds.join(" ")}`));
1562
- });
1563
- }
1564
- _findDepPaths(pkgIds, output = [], askName = "") {
1565
- const data = this._fyn._data;
1566
- return Promise.each(pkgIds, (pkgId) => {
1567
- const askPkgs = this.findPkgsById(data.pkgs, pkgId).sort(
1568
- (a, b) => semverUtil.simpleCompare(a.version, b.version)
1569
- );
1570
- if (askPkgs.length < 1) {
1571
- if (pkgId === PACKAGE_JSON) {
1572
- const newOutput = [].concat(output);
1573
- ["dependencies", "optionalDependencies", "peerDependencies", "devDependencies"].find(
1574
- (s) => {
1575
- const semver = _.get(this._fyn, ["_pkg", s, askName]);
1576
- if (semver) {
1577
- newOutput[SEMVER] = semver;
1578
- }
1579
- return semver;
1580
- }
1581
- );
1582
- this._allPaths.push(newOutput);
1583
- } else {
1584
- this._allPaths.push([pkgId]);
1585
- }
1586
- return void 0;
1587
- }
1588
- return Promise.map(
1589
- askPkgs,
1590
- (pkg) => {
1591
- const pkgId2 = getPkgId(pkg);
1592
- if (output.indexOf(pkgId2) >= 0) {
1593
- logger.debug("stat detected circular dependency:", pkgId2, output.join(" "));
1594
- return;
1595
- }
1596
- let dependents = this._dependentsCache[pkgId2];
1597
- if (!dependents) {
1598
- this._dependentsCache[pkgId2] = dependents = this.findDependents(data.pkgs, pkg).sort(
1599
- (a, b) => {
1600
- if (a.name === b.name) {
1601
- return semverUtil.simpleCompare(a.version, b.version);
1602
- }
1603
- return a.name > b.name ? 1 : -1;
1604
- }
1623
+ for (const match of matches.versions) {
1624
+ const stat = await this._statProvider.getPackageStat(match.name, match.version);
1625
+ if (!stat) continue;
1626
+ if (stat.dependents.length > 0) {
1627
+ logger.prefix("").info(
1628
+ "=>",
1629
+ logFormat.pkgId({ name: stat.name, version: stat.version }),
1630
+ `has ${stat.dependents.length} dependents:`,
1631
+ stat.dependents.map(formatPkgId).join(" ")
1605
1632
  );
1606
1633
  }
1607
- const followIds = dependents.filter((x) => x.name !== PACKAGE_JSON).map((x) => `${x.name}@${x.version.replace("-fynlocal_h", "")}`);
1608
- if (dependents.length > 0) {
1609
- const newOutput = [pkgId2].concat(output);
1610
- if (output.length === 1) {
1611
- ["dep", "opt", "per", "dev"].find((s) => {
1612
- const sv = _.get(pkg, ["res", s, askName]);
1613
- if (sv) {
1614
- newOutput[SEMVER] = sv.semver;
1615
- }
1616
- return sv;
1617
- });
1618
- } else {
1619
- newOutput[SEMVER] = output[SEMVER];
1620
- }
1621
- if (followIds.length > 0) {
1622
- return this._findDepPaths(followIds, newOutput, askName);
1623
- } else if (output) {
1624
- this._allPaths.push(newOutput);
1634
+ if (stat.circularDeps && stat.circularDeps.length > 0) {
1635
+ for (const circular of stat.circularDeps) {
1636
+ logger.prefix("").info("stat detected circular dependency:", circular.join(" "));
1625
1637
  }
1626
- } else {
1627
- logger.prefix("").info("no dependents for", pkgId2);
1628
1638
  }
1629
- },
1630
- { concurrency: 1 }
1631
- );
1632
- });
1633
- }
1634
- _displayPaths(pkgId, paths) {
1635
- const cmpDepPath = (a, b) => {
1636
- for (let ixA = 0; ixA < a.length; ixA++) {
1637
- if (b.length <= ixA) {
1638
- return 1;
1639
- }
1640
- const aId = a[ixA];
1641
- const bId = b[ixA];
1642
- if (aId !== bId) {
1643
- return aId > bId ? 1 : -1;
1644
- }
1645
- }
1646
- return 0;
1647
- };
1648
- paths = paths.sort((a, b) => a.length - b.length);
1649
- let minDetails = 5;
1650
- let briefPaths = paths;
1651
- while (briefPaths.length > 10 && minDetails > 0) {
1652
- const occurLevels = {};
1653
- briefPaths = paths.filter((dp) => {
1654
- const last = dp.length - 1;
1655
- for (let ix = 0; ix < last; ix++) {
1656
- const pkgId2 = dp[ix];
1657
- const occur = occurLevels[pkgId2];
1658
- if (occur && occur.level < ix && occur.leaf === dp[last] && dp.length - ix > minDetails) {
1659
- return false;
1639
+ const paths = stat.allPaths;
1640
+ const briefPaths = stat.significantPaths;
1641
+ if (paths.length > 0) {
1642
+ const formattedPaths = this._statProvider.formatPaths(briefPaths);
1643
+ const msg = paths.length === briefPaths.length ? `these dependency paths:` : `${paths.length} dependency paths, showing the ${briefPaths.length} most significant ones below:`;
1644
+ logger.prefix("").info(`=> ${stat.name}@${stat.version} has ${msg}`);
1645
+ logger.prefix("").info(formattedPaths.map((p) => ` > ${p}`).join("\n"));
1660
1646
  }
1661
- occurLevels[pkgId2] = {
1662
- level: ix,
1663
- leaf: dp[last]
1664
- };
1665
1647
  }
1666
- return true;
1667
- });
1668
- minDetails--;
1669
- }
1670
- briefPaths = briefPaths.sort(cmpDepPath);
1671
- const msg = paths.length === briefPaths.length ? `these dependency paths:` : `${paths.length} dependency paths, showing the ${briefPaths.length} most significant ones below:`;
1672
- logger.prefix("").info(`=> ${pkgId} has ${msg}`);
1673
- logger.prefix("").info(
1674
- briefPaths.map((x) => {
1675
- const semver = x[SEMVER];
1676
- return ` > ` + x.join(" > ") + (semver ? ` (${semver})` : "");
1677
- }).join("\n")
1678
- );
1648
+ }
1649
+ }).then(() => {
1650
+ logger.info(chalk.green(`stat completed for ${pkgIds.join(" ")}`));
1651
+ });
1679
1652
  }
1680
1653
  showStat(pkgIds) {
1681
1654
  const spinner = CliLogger.spinners[1];
@@ -1972,6 +1945,474 @@ module.exports.__TEST__ = {
1972
1945
  };
1973
1946
 
1974
1947
 
1948
+ /***/ }),
1949
+
1950
+ /***/ "./lib/audit/audit-cache.ts":
1951
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1952
+
1953
+ "use strict";
1954
+
1955
+ const cacache = __webpack_require__("./node_modules/.f/_/cacache/20.0.1/cacache/lib/index.js");
1956
+ const crypto = __webpack_require__("crypto");
1957
+ const Path = __webpack_require__("path");
1958
+ const AUDIT_CACHE_PREFIX = "fyn-audit-";
1959
+ function generateCacheKey(payload) {
1960
+ const sorted = Object.keys(payload).sort().reduce((acc, name) => {
1961
+ acc[name] = [...payload[name]].sort();
1962
+ return acc;
1963
+ }, {});
1964
+ const hash = crypto.createHash("sha256").update(JSON.stringify(sorted)).digest("hex");
1965
+ return `${AUDIT_CACHE_PREFIX}${hash}`;
1966
+ }
1967
+ async function cacheAuditResult(cacheDir, key, result) {
1968
+ const auditCacheDir = Path.join(cacheDir, "audit");
1969
+ const data = JSON.stringify(result);
1970
+ await cacache.put(auditCacheDir, key, data);
1971
+ }
1972
+ async function getCachedAuditResult(cacheDir, key) {
1973
+ const auditCacheDir = Path.join(cacheDir, "audit");
1974
+ try {
1975
+ const { data } = await cacache.get(auditCacheDir, key);
1976
+ return JSON.parse(data.toString());
1977
+ } catch (err) {
1978
+ if (err.code === "ENOENT" || err.code === "ENOTCACHED") {
1979
+ return null;
1980
+ }
1981
+ throw err;
1982
+ }
1983
+ }
1984
+ async function hasAuditCache(cacheDir, key) {
1985
+ const auditCacheDir = Path.join(cacheDir, "audit");
1986
+ try {
1987
+ const info = await cacache.get.info(auditCacheDir, key);
1988
+ return info !== null;
1989
+ } catch (err) {
1990
+ return false;
1991
+ }
1992
+ }
1993
+ module.exports = {
1994
+ AUDIT_CACHE_PREFIX,
1995
+ generateCacheKey,
1996
+ cacheAuditResult,
1997
+ getCachedAuditResult,
1998
+ hasAuditCache
1999
+ };
2000
+
2001
+
2002
+ /***/ }),
2003
+
2004
+ /***/ "./lib/audit/audit-formatter.ts":
2005
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2006
+
2007
+ "use strict";
2008
+
2009
+ const chalk = __webpack_require__("./node_modules/.f/_/chalk/4.1.2/chalk/source/index.js");
2010
+ const { SEMVER } = __webpack_require__("./lib/symbols.ts");
2011
+ const SEVERITY_COLORS = {
2012
+ critical: chalk.red.bold,
2013
+ high: chalk.red,
2014
+ moderate: chalk.yellow,
2015
+ low: chalk.cyan,
2016
+ info: chalk.blue
2017
+ };
2018
+ const SEVERITY_ORDER = ["critical", "high", "moderate", "low", "info"];
2019
+ class AuditFormatter {
2020
+ /**
2021
+ * @param {Object} options
2022
+ * @param {boolean} options.json - Output as JSON
2023
+ * @param {boolean} options.colors - Use colors in output
2024
+ * @param {string} options.auditLevel - Minimum severity to report
2025
+ * @param {boolean} options.summary - Output brief summary only (like npm after install)
2026
+ * @param {Object} options.statProvider - PkgStatProvider instance for dependency path info
2027
+ * @param {Object} options.statCache - Pre-computed stat results keyed by "name@version"
2028
+ */
2029
+ constructor(options = {}) {
2030
+ this._json = options.json || false;
2031
+ this._colors = options.colors !== false;
2032
+ this._auditLevel = options.auditLevel || "info";
2033
+ this._summary = options.summary || false;
2034
+ this._statProvider = options.statProvider || null;
2035
+ this._statCache = options.statCache || {};
2036
+ }
2037
+ /**
2038
+ * Get severity level as number for comparison.
2039
+ */
2040
+ getSeverityLevel(severity) {
2041
+ const levels = { critical: 5, high: 4, moderate: 3, low: 2, info: 1 };
2042
+ return levels[severity] || 0;
2043
+ }
2044
+ /**
2045
+ * Check if severity meets minimum audit level.
2046
+ */
2047
+ meetsAuditLevel(severity) {
2048
+ return this.getSeverityLevel(severity) >= this.getSeverityLevel(this._auditLevel);
2049
+ }
2050
+ /**
2051
+ * Colorize text based on severity.
2052
+ */
2053
+ colorize(text, severity) {
2054
+ if (!this._colors) return text;
2055
+ const colorFn = SEVERITY_COLORS[severity] || ((t) => t);
2056
+ return colorFn(text);
2057
+ }
2058
+ /**
2059
+ * Format audit result for output.
2060
+ *
2061
+ * @param {Object} auditResult - Result from AuditReport.fetchAdvisories()
2062
+ * @param {Array} vulnerabilities - Matched vulnerabilities from matchVulnerabilities()
2063
+ * @returns {Object} { output: string, exitCode: number }
2064
+ */
2065
+ format(auditResult, vulnerabilities) {
2066
+ if (this._json) {
2067
+ return this.formatJson(auditResult, vulnerabilities);
2068
+ }
2069
+ if (this._summary) {
2070
+ return this.formatSummary(auditResult, vulnerabilities);
2071
+ }
2072
+ return this.formatHuman(auditResult, vulnerabilities);
2073
+ }
2074
+ /**
2075
+ * Format as brief summary (like npm shows after install).
2076
+ * Example: "audited 745 packages\n3 vulnerabilities (1 moderate, 1 high, 1 critical)"
2077
+ */
2078
+ formatSummary(auditResult, vulnerabilities) {
2079
+ const filtered = vulnerabilities.filter((v) => this.meetsAuditLevel(v.advisory.severity));
2080
+ const pkgCount = auditResult.metadata?.totalDependencies || 0;
2081
+ if (filtered.length === 0) {
2082
+ return { output: `audited ${pkgCount} packages`, exitCode: 0 };
2083
+ }
2084
+ const counts = {};
2085
+ filtered.forEach((v) => {
2086
+ const sev = v.advisory.severity;
2087
+ counts[sev] = (counts[sev] || 0) + 1;
2088
+ });
2089
+ const parts = SEVERITY_ORDER.filter((sev) => counts[sev]).map((sev) => {
2090
+ const count = counts[sev];
2091
+ return this.colorize(`${count} ${sev}`, sev);
2092
+ });
2093
+ const total = filtered.length;
2094
+ const output = `audited ${pkgCount} packages
2095
+
2096
+ ${total} ${total === 1 ? "vulnerability" : "vulnerabilities"} (${parts.join(", ")})
2097
+
2098
+ Run \`fyn audit\` for details.`;
2099
+ return { output, exitCode: 0 };
2100
+ }
2101
+ /**
2102
+ * Format as JSON.
2103
+ */
2104
+ formatJson(auditResult, vulnerabilities) {
2105
+ const filtered = vulnerabilities.filter((v) => this.meetsAuditLevel(v.advisory.severity));
2106
+ const output = JSON.stringify(
2107
+ {
2108
+ vulnerabilities: filtered,
2109
+ metadata: auditResult.metadata,
2110
+ advisories: auditResult.advisories
2111
+ },
2112
+ null,
2113
+ 2
2114
+ );
2115
+ return { output, exitCode: 0 };
2116
+ }
2117
+ /**
2118
+ * Format as human-readable table.
2119
+ */
2120
+ formatHuman(auditResult, vulnerabilities) {
2121
+ const lines = [];
2122
+ const { metadata } = auditResult;
2123
+ const filtered = vulnerabilities.filter((v) => this.meetsAuditLevel(v.advisory.severity));
2124
+ const bySeverity = {};
2125
+ SEVERITY_ORDER.forEach((s) => bySeverity[s] = []);
2126
+ filtered.forEach((vuln) => {
2127
+ const sev = vuln.advisory.severity;
2128
+ if (bySeverity[sev]) {
2129
+ bySeverity[sev].push(vuln);
2130
+ }
2131
+ });
2132
+ lines.push("");
2133
+ if (filtered.length === 0) {
2134
+ lines.push(this._colors ? chalk.green("No vulnerabilities found!") : "No vulnerabilities found!");
2135
+ lines.push("");
2136
+ lines.push(`Scanned ${metadata.totalDependencies} packages`);
2137
+ } else {
2138
+ const counts = SEVERITY_ORDER.map((sev) => {
2139
+ const count = bySeverity[sev].length;
2140
+ if (count === 0) return null;
2141
+ return this.colorize(`${count} ${sev}`, sev);
2142
+ }).filter(Boolean);
2143
+ lines.push(`Found ${filtered.length} vulnerabilities (${counts.join(", ")})`);
2144
+ lines.push("");
2145
+ SEVERITY_ORDER.forEach((severity) => {
2146
+ const vulns = bySeverity[severity];
2147
+ if (vulns.length === 0) return;
2148
+ vulns.forEach((vuln) => {
2149
+ const { advisory } = vuln;
2150
+ lines.push(this.formatVulnerability(vuln));
2151
+ lines.push("");
2152
+ });
2153
+ });
2154
+ lines.push(`Scanned ${metadata.totalDependencies} packages`);
2155
+ }
2156
+ lines.push("");
2157
+ return { output: lines.join("\n"), exitCode: 0 };
2158
+ }
2159
+ /**
2160
+ * Format a single vulnerability entry.
2161
+ */
2162
+ formatVulnerability(vuln) {
2163
+ const { advisory, name, version } = vuln;
2164
+ const lines = [];
2165
+ const sevLabel = this.colorize(advisory.severity.toUpperCase().padEnd(10), advisory.severity);
2166
+ lines.push(`${sevLabel} ${advisory.title}`);
2167
+ const pkgId = this._colors ? chalk.yellow(`${name}@${version}`) : `${name}@${version}`;
2168
+ const vulnRange = this._colors ? chalk.red(`Vulnerable: ${advisory.vulnerable_versions}`) : `Vulnerable: ${advisory.vulnerable_versions}`;
2169
+ const infoUrl = advisory.url ? this._colors ? chalk.cyan(`info: ${advisory.url}`) : `info: ${advisory.url}` : "";
2170
+ let details = ` ${pkgId} - ${vulnRange}`;
2171
+ if (infoUrl) {
2172
+ details += ` - ${infoUrl}`;
2173
+ }
2174
+ lines.push(details);
2175
+ const cacheKey = `${name}@${version}`;
2176
+ const stat = this._statCache[cacheKey];
2177
+ if (stat && stat.significantPaths && stat.significantPaths.length > 0) {
2178
+ const seenFirstLegs = /* @__PURE__ */ new Set();
2179
+ const uniquePaths = [];
2180
+ for (const path of stat.significantPaths) {
2181
+ const firstLeg = path[0];
2182
+ if (!seenFirstLegs.has(firstLeg)) {
2183
+ seenFirstLegs.add(firstLeg);
2184
+ uniquePaths.push(path);
2185
+ if (uniquePaths.length >= 5) break;
2186
+ }
2187
+ }
2188
+ for (const path of uniquePaths) {
2189
+ const semver = path[SEMVER];
2190
+ const pathStr = path.join(" > ");
2191
+ const fullPath = semver ? `${pathStr} (${semver})` : pathStr;
2192
+ lines.push(` > ${fullPath}`);
2193
+ }
2194
+ }
2195
+ return lines.join("\n");
2196
+ }
2197
+ /**
2198
+ * Pre-compute stat info for all vulnerabilities.
2199
+ * Call this before format() when using a stat provider.
2200
+ *
2201
+ * @param {Array} vulnerabilities - List of vulnerabilities from matchVulnerabilities()
2202
+ * @returns {Promise<void>}
2203
+ */
2204
+ async precomputeStats(vulnerabilities) {
2205
+ if (!this._statProvider) return;
2206
+ const filtered = vulnerabilities.filter((v) => this.meetsAuditLevel(v.advisory.severity));
2207
+ for (const vuln of filtered) {
2208
+ const cacheKey = `${vuln.name}@${vuln.version}`;
2209
+ if (!this._statCache[cacheKey]) {
2210
+ const stat = await this._statProvider.getPackageStat(vuln.name, vuln.version);
2211
+ if (stat) {
2212
+ this._statCache[cacheKey] = stat;
2213
+ }
2214
+ }
2215
+ }
2216
+ }
2217
+ }
2218
+ module.exports = AuditFormatter;
2219
+
2220
+
2221
+ /***/ }),
2222
+
2223
+ /***/ "./lib/audit/audit-report.ts":
2224
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2225
+
2226
+ "use strict";
2227
+
2228
+ const npmFetch = __webpack_require__("./node_modules/.f/_/npm-registry-fetch/19.1.0/npm-registry-fetch/lib/index.js");
2229
+ const logger = __webpack_require__("./lib/logger.ts");
2230
+ const {
2231
+ generateCacheKey,
2232
+ cacheAuditResult,
2233
+ getCachedAuditResult
2234
+ } = __webpack_require__("./lib/audit/audit-cache.ts");
2235
+ class AuditReport {
2236
+ /**
2237
+ * @param {Object} options
2238
+ * @param {Object} options.fyn - Fyn instance with resolved data
2239
+ * @param {Object} options.depData - DepData with resolved packages
2240
+ * @param {boolean} options.noCache - Skip cache lookup
2241
+ * @param {string[]} options.omit - Dependency types to omit (dev, optional, peer)
2242
+ */
2243
+ constructor(options) {
2244
+ this._fyn = options.fyn;
2245
+ this._depData = options.depData;
2246
+ this._noCache = options.noCache || false;
2247
+ this._omit = options.omit || [];
2248
+ this._cacheDir = options.fyn.fynDir;
2249
+ }
2250
+ /**
2251
+ * Build bulk request payload from resolved packages.
2252
+ * Format: { "packageName": ["version1", "version2"], ... }
2253
+ *
2254
+ * @returns {Object} Bulk payload for npm security API
2255
+ */
2256
+ buildBulkPayload() {
2257
+ const payload = {};
2258
+ const pkgs = this._depData.pkgs;
2259
+ const omitDev = this._omit.includes("dev");
2260
+ const omitOptional = this._omit.includes("optional");
2261
+ const omitPeer = this._omit.includes("peer");
2262
+ Object.keys(pkgs).forEach((name) => {
2263
+ const versions = pkgs[name];
2264
+ Object.keys(versions).forEach((version) => {
2265
+ const pkgInfo = versions[version];
2266
+ if (omitDev && pkgInfo.src === "dev") return;
2267
+ if (omitOptional && pkgInfo.src === "opt") return;
2268
+ if (omitPeer && pkgInfo.src === "per") return;
2269
+ if (pkgInfo.local || pkgInfo.localType) return;
2270
+ if (!payload[name]) {
2271
+ payload[name] = [];
2272
+ }
2273
+ if (!payload[name].includes(version)) {
2274
+ payload[name].push(version);
2275
+ }
2276
+ });
2277
+ });
2278
+ return payload;
2279
+ }
2280
+ /**
2281
+ * Get registry URL for audit API.
2282
+ * Uses the main registry (not scoped registries since audit is global).
2283
+ *
2284
+ * @returns {string} Registry URL with trailing slash
2285
+ */
2286
+ getAuditRegistryUrl() {
2287
+ const registry = this._fyn._options.registry || "https://registry.npmjs.org";
2288
+ return registry.endsWith("/") ? registry : `${registry}/`;
2289
+ }
2290
+ /**
2291
+ * Get npm-registry-fetch options with auth.
2292
+ *
2293
+ * @returns {Object} Options for npm-registry-fetch
2294
+ */
2295
+ getFetchOptions() {
2296
+ const opts = this._fyn._options;
2297
+ const fetchOpts = {
2298
+ registry: this.getAuditRegistryUrl()
2299
+ };
2300
+ if (opts.username) fetchOpts.username = opts.username;
2301
+ if (opts.password) fetchOpts.password = opts.password;
2302
+ if (opts.email) fetchOpts.email = opts.email;
2303
+ if (opts["always-auth"]) fetchOpts.alwaysAuth = opts["always-auth"];
2304
+ Object.keys(opts).forEach((key) => {
2305
+ if (key.endsWith(":_authToken")) {
2306
+ fetchOpts[key] = opts[key];
2307
+ }
2308
+ });
2309
+ return fetchOpts;
2310
+ }
2311
+ /**
2312
+ * Fetch advisories from npm security API.
2313
+ * Uses cache if available and noCache is false.
2314
+ *
2315
+ * @returns {Promise<Object>} Audit result with advisories
2316
+ */
2317
+ async fetchAdvisories() {
2318
+ const payload = this.buildBulkPayload();
2319
+ const packageCount = Object.keys(payload).length;
2320
+ if (packageCount === 0) {
2321
+ logger.info("No packages to audit");
2322
+ return { advisories: {}, metadata: { totalDependencies: 0 } };
2323
+ }
2324
+ const cacheKey = generateCacheKey(payload);
2325
+ if (!this._noCache) {
2326
+ const cached = await getCachedAuditResult(this._cacheDir, cacheKey);
2327
+ if (cached) {
2328
+ logger.debug("Using cached audit result");
2329
+ return cached;
2330
+ }
2331
+ }
2332
+ const registryUrl = this.getAuditRegistryUrl();
2333
+ const auditUrl = `${registryUrl}-/npm/v1/security/advisories/bulk`;
2334
+ logger.info(`Auditing ${packageCount} packages...`);
2335
+ try {
2336
+ const fetchOpts = this.getFetchOptions();
2337
+ const response = await npmFetch(auditUrl, {
2338
+ ...fetchOpts,
2339
+ method: "POST",
2340
+ body: payload,
2341
+ gzip: true
2342
+ });
2343
+ const advisories = await response.json();
2344
+ const result = {
2345
+ advisories,
2346
+ metadata: {
2347
+ totalDependencies: packageCount,
2348
+ vulnerabilities: Object.keys(advisories).length
2349
+ }
2350
+ };
2351
+ await cacheAuditResult(this._cacheDir, cacheKey, result);
2352
+ return result;
2353
+ } catch (err) {
2354
+ if (!this._noCache) {
2355
+ const cached = await getCachedAuditResult(this._cacheDir, cacheKey);
2356
+ if (cached) {
2357
+ logger.warn("Network error, using cached audit data");
2358
+ return cached;
2359
+ }
2360
+ }
2361
+ if (err.code === "ENOTFOUND" || err.code === "ECONNREFUSED") {
2362
+ throw new Error(`Unable to reach npm registry for audit: ${err.message}`);
2363
+ }
2364
+ if (err.statusCode === 401 || err.statusCode === 403) {
2365
+ throw new Error("Authentication required for security audit");
2366
+ }
2367
+ throw err;
2368
+ }
2369
+ }
2370
+ /**
2371
+ * Match advisories to resolved packages.
2372
+ * Returns list of affected packages with advisory details.
2373
+ *
2374
+ * The bulk API returns advisories grouped by package name:
2375
+ * { "package-name": [{ id, vulnerable_versions, ... }, ...] }
2376
+ *
2377
+ * @param {Object} auditResult - Result from fetchAdvisories()
2378
+ * @returns {Array} List of vulnerabilities with package info
2379
+ */
2380
+ matchVulnerabilities(auditResult) {
2381
+ const vulnerabilities = [];
2382
+ const { advisories } = auditResult;
2383
+ const pkgs = this._depData.pkgs;
2384
+ const semver = __webpack_require__("./node_modules/.f/_/semver/7.7.3/semver/index.js");
2385
+ Object.keys(advisories).forEach((pkgName) => {
2386
+ const pkgAdvisories = advisories[pkgName];
2387
+ if (!pkgs[pkgName]) return;
2388
+ pkgAdvisories.forEach((advisory) => {
2389
+ const vulnVersions = advisory.vulnerable_versions;
2390
+ Object.keys(pkgs[pkgName]).forEach((version) => {
2391
+ if (semver.satisfies(version, vulnVersions)) {
2392
+ vulnerabilities.push({
2393
+ name: pkgName,
2394
+ version,
2395
+ advisory: {
2396
+ id: advisory.id,
2397
+ title: advisory.title,
2398
+ severity: advisory.severity,
2399
+ url: advisory.url,
2400
+ vulnerable_versions: vulnVersions,
2401
+ patched_versions: advisory.patched_versions,
2402
+ recommendation: advisory.recommendation
2403
+ },
2404
+ paths: pkgs[pkgName][version].requests || []
2405
+ });
2406
+ }
2407
+ });
2408
+ });
2409
+ });
2410
+ return vulnerabilities;
2411
+ }
2412
+ }
2413
+ module.exports = AuditReport;
2414
+
2415
+
1975
2416
  /***/ }),
1976
2417
 
1977
2418
  /***/ "./lib/cacache-util.ts":
@@ -2747,9 +3188,12 @@ class FynGlobal {
2747
3188
  */
2748
3189
  constructor(options = {}) {
2749
3190
  this.options = options;
2750
- this.nodeVersion = options.nodeVersion || process.version.match(/^v(\d+)/)[1];
3191
+ const isBun = typeof process.versions.bun === "string";
3192
+ const runtimeVersion = options.nodeVersion || process.version.match(/^v?(\d+)/)[1];
3193
+ this.runtimePrefix = isBun ? "bun" : "v";
3194
+ this.nodeVersion = runtimeVersion;
2751
3195
  this.globalRoot = options.globalDir || Path.join(Os.homedir(), ".fyn", "global");
2752
- this.versionDir = Path.join(this.globalRoot, `v${this.nodeVersion}`);
3196
+ this.versionDir = Path.join(this.globalRoot, `${this.runtimePrefix}${runtimeVersion}`);
2753
3197
  this.packagesDir = Path.join(this.versionDir, "packages");
2754
3198
  this.globalBinDir = Path.join(this.versionDir, "bin");
2755
3199
  this.installedJsonPath = Path.join(this.versionDir, "installed.json");
@@ -3053,7 +3497,7 @@ class FynGlobal {
3053
3497
  */
3054
3498
  async ensureBinSymlink() {
3055
3499
  const binSymlink = Path.join(this.globalRoot, "bin");
3056
- const targetDir = `v${this.nodeVersion}/bin`;
3500
+ const targetDir = `${this.runtimePrefix}${this.nodeVersion}/bin`;
3057
3501
  try {
3058
3502
  const currentTarget = await Fs.readlink(binSymlink);
3059
3503
  if (currentTarget === targetDir) {
@@ -4021,7 +4465,82 @@ class Fyn {
4021
4465
  return { mm: new mm.Minimatch(finalPath), res: resData[depPath] };
4022
4466
  });
4023
4467
  }
4468
+ const overridesData = {
4469
+ ...this._pkg.overrides,
4470
+ ..._.get(this._fynpo, ["config", "overrides"])
4471
+ };
4472
+ if (!_.isEmpty(overridesData)) {
4473
+ this._overrides = overridesData;
4474
+ this._overridesMatchers = this._processOverrides(overridesData);
4475
+ }
4476
+ }
4477
+ }
4478
+ /**
4479
+ * Process npm-style overrides into matchers
4480
+ *
4481
+ * npm overrides support:
4482
+ * 1. Simple: "package-name": "version"
4483
+ * 2. Nested: "parent-pkg": { "child-pkg": "version" }
4484
+ * 3. Version-conditional: "package@^1.0.0": "1.0.5"
4485
+ * 4. Reference: "$package-name" to reference a direct dependency version
4486
+ *
4487
+ * @param {object} overrides - The overrides object from package.json
4488
+ * @param {string} parentPath - The parent path for nested overrides
4489
+ * @returns {Array} Array of override matcher objects
4490
+ */
4491
+ _processOverrides(overrides, parentPath = "") {
4492
+ const matchers = [];
4493
+ for (const key of Object.keys(overrides)) {
4494
+ const value = overrides[key];
4495
+ let pkgName = key;
4496
+ let versionConstraint = null;
4497
+ const atIdx = key.lastIndexOf("@");
4498
+ if (atIdx > 0) {
4499
+ pkgName = key.substring(0, atIdx);
4500
+ versionConstraint = key.substring(atIdx + 1);
4501
+ }
4502
+ if (typeof value === "string") {
4503
+ let resolvedValue = value;
4504
+ if (value.startsWith("$")) {
4505
+ const refPkgName = value.substring(1);
4506
+ const directDepVersion = this._getDirectDependencyVersion(refPkgName);
4507
+ if (directDepVersion) {
4508
+ resolvedValue = directDepVersion;
4509
+ } else {
4510
+ logger.warn(
4511
+ `Override reference $${refPkgName} not found in direct dependencies, using as-is`
4512
+ );
4513
+ resolvedValue = value;
4514
+ }
4515
+ }
4516
+ matchers.push({
4517
+ pkgName,
4518
+ versionConstraint,
4519
+ parentPath,
4520
+ replacement: resolvedValue
4521
+ });
4522
+ } else if (typeof value === "object" && value !== null) {
4523
+ const newParentPath = parentPath ? `${parentPath}/${pkgName}` : pkgName;
4524
+ const nestedMatchers = this._processOverrides(value, newParentPath);
4525
+ matchers.push(...nestedMatchers);
4526
+ }
4527
+ }
4528
+ return matchers;
4529
+ }
4530
+ /**
4531
+ * Get the version of a direct dependency from package.json
4532
+ * @param {string} pkgName - Package name to look up
4533
+ * @returns {string|null} The version or null if not found
4534
+ */
4535
+ _getDirectDependencyVersion(pkgName) {
4536
+ const sections = ["dependencies", "devDependencies", "optionalDependencies"];
4537
+ for (const section of sections) {
4538
+ const version = _.get(this._pkg, [section, pkgName]);
4539
+ if (version) {
4540
+ return version;
4541
+ }
4024
4542
  }
4543
+ return null;
4025
4544
  }
4026
4545
  async _startInstall() {
4027
4546
  if (!this._distFetcher) {
@@ -4616,7 +5135,7 @@ const chalk = __webpack_require__("./node_modules/.f/_/chalk/4.1.2/chalk/source/
4616
5135
  const _ = __webpack_require__("./node_modules/.f/_/lodash/4.17.21/lodash/lodash.min.js");
4617
5136
  const logger = __webpack_require__("./lib/logger.ts");
4618
5137
  const logFormat = __webpack_require__("./lib/util/log-format.ts");
4619
- const VisualExec = __webpack_require__("./node_modules/.f/_/visual-exec/0.1.14/visual-exec/lib/visual-exec.js");
5138
+ const { VisualExec } = __webpack_require__("./node_modules/.f/_/visual-exec/0.2.0-fynlocal_h/visual-exec/dist/index.js");
4620
5139
  const fyntil = __webpack_require__("./lib/util/fyntil.ts");
4621
5140
  const requireAt = __webpack_require__("./node_modules/.f/_/require-at/1.0.6/require-at/require-at.js");
4622
5141
  const { setupNodeGypEnv } = __webpack_require__("./lib/util/setup-node-gyp.ts");
@@ -4737,7 +5256,7 @@ module.exports = LifecycleScripts;
4737
5256
  const Path = __webpack_require__("path");
4738
5257
  const logger = __webpack_require__("./lib/logger.ts");
4739
5258
  const PromiseQueue = __webpack_require__("./lib/util/promise-queue.ts");
4740
- const VisualExec = __webpack_require__("./node_modules/.f/_/visual-exec/0.1.14/visual-exec/lib/visual-exec.js");
5259
+ const VisualExec = __webpack_require__("./node_modules/.f/_/visual-exec/0.2.0-fynlocal_h/visual-exec/dist/index.js");
4741
5260
  const xaa = __webpack_require__("./node_modules/.f/_/xaa/2.0.0/xaa/dist-cjs/index.cjs");
4742
5261
  const Fs = __webpack_require__("./lib/util/file-ops.ts");
4743
5262
  const _ = __webpack_require__("./node_modules/.f/_/lodash/4.17.21/lodash/lodash.min.js");
@@ -4768,12 +5287,15 @@ class LocalPkgBuilder {
4768
5287
  this._waitItems[data.item.fullPath].resolve({});
4769
5288
  });
4770
5289
  this._promiseQ.on("failItem", (data) => {
5290
+ const debugLog = Path.join(data.item.fullPath, "fyn-debug.log");
4771
5291
  const itemRes = {
4772
5292
  error: new AggregateError(
4773
5293
  [data.error],
4774
- `failed build local package at ${data.item.fullPath}`
5294
+ `failed build local package at ${data.item.fullPath} - check ${debugLog} for details`
4775
5295
  )
4776
5296
  };
5297
+ logger.error(`Failed to build local package at ${data.item.fullPath}`);
5298
+ logger.error(`Check debug log for details: ${debugLog}`);
4777
5299
  this._waitItems[data.item.fullPath].resolve(itemRes);
4778
5300
  this._failedItems[data.item.fullPath] = itemRes;
4779
5301
  });
@@ -4857,8 +5379,9 @@ class LocalPkgBuilder {
4857
5379
  process.argv[0],
4858
5380
  this._fynJs,
4859
5381
  this._fyn._options.registry && `--reg=${this._fyn._options.registry}`,
4860
- "-q=d --pg=simple --no-build-local",
4861
- !this._fyn._options.sourceMaps && "--no-source-maps"
5382
+ "-q=d --pg=simple --no-build-local --sl=fyn-debug.log",
5383
+ !this._fyn._options.sourceMaps && "--no-source-maps",
5384
+ "install --no-audit"
4862
5385
  ].filter((x) => x).join(" ");
4863
5386
  const displayTitle = `building local pkg at ${dispPath}`;
4864
5387
  logger.verbose(displayTitle);
@@ -6775,6 +7298,107 @@ ${item.depPath.join(" > ")}`
6775
7298
  }
6776
7299
  return void 0;
6777
7300
  }
7301
+ /**
7302
+ * Apply npm-style overrides to a dependency item
7303
+ *
7304
+ * npm overrides differ from yarn resolutions:
7305
+ * - They apply to ALL instances of a package by default (not path-based)
7306
+ * - They can be scoped to specific parent packages
7307
+ * - They support version constraints on the source package
7308
+ *
7309
+ * @param {*} item - The dependency item to check for overrides
7310
+ * @returns {undefined}
7311
+ */
7312
+ _applyOverrides(item) {
7313
+ if (!this._fyn._overridesMatchers || item._semver.$$) {
7314
+ return void 0;
7315
+ }
7316
+ const matchers = this._fyn._overridesMatchers;
7317
+ for (const matcher of matchers) {
7318
+ const { pkgName, versionConstraint, parentPath, replacement } = matcher;
7319
+ if (pkgName !== item.name) {
7320
+ continue;
7321
+ }
7322
+ if (versionConstraint) {
7323
+ if (!this._matchesVersionConstraint(item.semver, versionConstraint)) {
7324
+ continue;
7325
+ }
7326
+ }
7327
+ if (parentPath) {
7328
+ if (!this._matchesParentPath(item, parentPath)) {
7329
+ continue;
7330
+ }
7331
+ }
7332
+ if (replacement !== item.semver) {
7333
+ const parentInfo = parentPath ? ` (under ${parentPath})` : "";
7334
+ const constraintInfo = versionConstraint ? `@${versionConstraint}` : "";
7335
+ logger.info(
7336
+ `Override: ${item.name}${constraintInfo}${parentInfo} changed from ${item.semver} to ${replacement}`
7337
+ );
7338
+ semverUtil.replace(item._semver, replacement);
7339
+ return void 0;
7340
+ }
7341
+ }
7342
+ return void 0;
7343
+ }
7344
+ /**
7345
+ * Check if the item's semver matches the version constraint specified in the override key
7346
+ *
7347
+ * @param {string} itemSemver - The semver from the dependency
7348
+ * @param {string} constraint - The version constraint from override key (e.g., "^4.0.0", ">=1.0.0")
7349
+ * @returns {boolean}
7350
+ */
7351
+ _matchesVersionConstraint(itemSemver, constraint) {
7352
+ if (Semver.valid(constraint)) {
7353
+ return Semver.satisfies(constraint, itemSemver);
7354
+ }
7355
+ try {
7356
+ return Semver.intersects(itemSemver, constraint);
7357
+ } catch {
7358
+ return itemSemver === constraint;
7359
+ }
7360
+ }
7361
+ /**
7362
+ * Check if the item's parent path matches the override's parent path constraint
7363
+ *
7364
+ * For example, if override is { "foo": { "bar": "1.0.0" } },
7365
+ * parentPath would be "foo" and we check if item's parent chain includes "foo"
7366
+ *
7367
+ * @param {*} item - The dependency item
7368
+ * @param {string} parentPath - The parent path from the override (e.g., "foo" or "foo/baz")
7369
+ * @returns {boolean}
7370
+ */
7371
+ _matchesParentPath(item, parentPath) {
7372
+ if (!item.parent || item.parent.depth === 0) {
7373
+ return false;
7374
+ }
7375
+ const parentChain = [];
7376
+ let current = item.parent;
7377
+ while (current && current.depth > 0) {
7378
+ parentChain.unshift(current.name);
7379
+ current = current.parent;
7380
+ }
7381
+ const pathParts = parentPath.split("/").filter((p) => p);
7382
+ const normalizedParts = [];
7383
+ for (let i = 0; i < pathParts.length; i++) {
7384
+ if (pathParts[i].startsWith("@") && i + 1 < pathParts.length) {
7385
+ normalizedParts.push(`${pathParts[i]}/${pathParts[i + 1]}`);
7386
+ i++;
7387
+ } else {
7388
+ normalizedParts.push(pathParts[i]);
7389
+ }
7390
+ }
7391
+ if (normalizedParts.length > parentChain.length) {
7392
+ return false;
7393
+ }
7394
+ const startIdx = parentChain.length - normalizedParts.length;
7395
+ for (let i = 0; i < normalizedParts.length; i++) {
7396
+ if (parentChain[startIdx + i] !== normalizedParts[i]) {
7397
+ return false;
7398
+ }
7399
+ }
7400
+ return true;
7401
+ }
6778
7402
  _resolveWithLockData(item) {
6779
7403
  const isOpt = item.dsrc && item.dsrc.includes("opt");
6780
7404
  if (isOpt && this._fyn.refreshOptionals) {
@@ -6843,6 +7467,7 @@ ${item.depPath.join(" > ")}`
6843
7467
  return r;
6844
7468
  });
6845
7469
  };
7470
+ this._applyOverrides(item);
6846
7471
  this._replaceWithResolutionsData(item);
6847
7472
  const promise = !item.semverPath || this._fyn.preferLock ? tryLock().then((r) => r || item.semverPath && tryLocal()) : tryLocal().then((r) => r || tryLock());
6848
7473
  return promise.then((r) => {
@@ -8063,7 +8688,7 @@ const longPending = __webpack_require__("./lib/long-pending.ts");
8063
8688
  const { LOCAL_VERSION_MAPS, PACKAGE_RAW_INFO, DEP_ITEM } = __webpack_require__("./lib/symbols.ts");
8064
8689
  const { LONG_WAIT_META, FETCH_META, FETCH_PACKAGE } = __webpack_require__("./lib/log-items.ts");
8065
8690
  const PkgPreper = __webpack_require__("./node_modules/.f/_/pkg-preper/0.1.6-fynlocal_h/pkg-preper/lib/pkg-preper.js");
8066
- const VisualExec = __webpack_require__("./node_modules/.f/_/visual-exec/0.1.14/visual-exec/lib/visual-exec.js");
8691
+ const VisualExec = __webpack_require__("./node_modules/.f/_/visual-exec/0.2.0-fynlocal_h/visual-exec/dist/index.js");
8067
8692
  const { readPkgJson, missPipe } = __webpack_require__("./lib/util/fyntil.ts");
8068
8693
  const { MARK_URL_SPEC } = __webpack_require__("./lib/constants.ts");
8069
8694
  const nodeFetch = __webpack_require__("./node_modules/.f/_/node-fetch-npm/2.0.4/node-fetch-npm/src/index.js");
@@ -8837,6 +9462,303 @@ module.exports = PkgSrcManager;
8837
9462
  module.exports.META_CACHE_STALE_TIME = META_CACHE_STALE_TIME;
8838
9463
 
8839
9464
 
9465
+ /***/ }),
9466
+
9467
+ /***/ "./lib/pkg-stat-provider.ts":
9468
+ /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
9469
+
9470
+ "use strict";
9471
+
9472
+ const _ = __webpack_require__("./node_modules/.f/_/lodash/4.17.21/lodash/lodash.min.js");
9473
+ const semverUtil = __webpack_require__("./lib/util/semver.ts");
9474
+ const PkgDepLinker = __webpack_require__("./lib/pkg-dep-linker.ts");
9475
+ const { SEMVER } = __webpack_require__("./lib/symbols.ts");
9476
+ const PACKAGE_JSON = "~package.json";
9477
+ class PkgStatProvider {
9478
+ _fyn;
9479
+ _fynRes;
9480
+ _dependentsCache;
9481
+ _allPaths;
9482
+ _circularDeps;
9483
+ constructor({ fyn }) {
9484
+ this._fyn = fyn;
9485
+ this._fynRes = null;
9486
+ this._dependentsCache = {};
9487
+ this._allPaths = [];
9488
+ this._circularDeps = [];
9489
+ }
9490
+ /**
9491
+ * Find packages matching the given ID pattern.
9492
+ *
9493
+ * @param pkgId - Package ID (name or name@semver)
9494
+ * @returns Array of matching package info
9495
+ */
9496
+ findPkgsById(pkgId) {
9497
+ const pkgs = this._fyn._data?.pkgs;
9498
+ if (!pkgs) return [];
9499
+ const ix = pkgId.indexOf("@", 1);
9500
+ const sx = ix > 0 ? ix : pkgId.length;
9501
+ const name = pkgId.substr(0, sx);
9502
+ const semver = pkgId.substr(sx + 1);
9503
+ return _(pkgs[name]).map((vpkg, version) => {
9504
+ if (!semver || semverUtil.satisfies(version, semver)) {
9505
+ return vpkg;
9506
+ }
9507
+ }).filter((x) => x).value();
9508
+ }
9509
+ /**
9510
+ * Find all packages that depend on the given package.
9511
+ *
9512
+ * @param ask - Package info { name, version, local? }
9513
+ * @returns Array of dependent packages
9514
+ */
9515
+ findDependents(ask) {
9516
+ const pkgs = this._fyn._data?.pkgs;
9517
+ if (!pkgs) return [];
9518
+ const dependents = [];
9519
+ if (!this._fynRes) {
9520
+ const depLinker = new PkgDepLinker({ fyn: this._fyn });
9521
+ this._fynRes = depLinker.makeAppFynRes(this._fyn._data.res, {});
9522
+ }
9523
+ const check = (res, vpkg) => {
9524
+ const semv = ask.local ? semverUtil.unlocalify(ask.version) : ask.version;
9525
+ if (res && semverUtil.satisfies(res.resolved, semv)) {
9526
+ dependents.push(vpkg);
9527
+ }
9528
+ };
9529
+ for (const name in pkgs) {
9530
+ const pkg = pkgs[name];
9531
+ for (const version in pkg) {
9532
+ const vpkg = pkg[version];
9533
+ ["dep", "opt", "per"].forEach((s) => {
9534
+ const x = vpkg.res[s];
9535
+ check(x && x[ask.name], vpkg);
9536
+ });
9537
+ }
9538
+ }
9539
+ check(this._fynRes[ask.name], { name: PACKAGE_JSON, promoted: true });
9540
+ return dependents;
9541
+ }
9542
+ /**
9543
+ * Get the package ID string.
9544
+ */
9545
+ _getPkgId(pkg) {
9546
+ if (pkg.name === PACKAGE_JSON) {
9547
+ return pkg.name;
9548
+ }
9549
+ return `${pkg.name}@${pkg.version}`;
9550
+ }
9551
+ /**
9552
+ * Find dependency paths from root to the given package.
9553
+ *
9554
+ * @param pkgIds - Package IDs to trace
9555
+ * @param output - Current path being built
9556
+ * @param askName - Original package name being traced
9557
+ */
9558
+ async _findDepPaths(pkgIds, output = [], askName = "") {
9559
+ const data = this._fyn._data;
9560
+ const pkgs = data?.pkgs;
9561
+ if (!pkgs) return;
9562
+ for (const pkgId of pkgIds) {
9563
+ const askPkgs = this.findPkgsById(pkgId).sort(
9564
+ (a, b) => semverUtil.simpleCompare(a.version, b.version)
9565
+ );
9566
+ if (askPkgs.length < 1) {
9567
+ if (pkgId === PACKAGE_JSON) {
9568
+ const newOutput = [].concat(output);
9569
+ ["dependencies", "optionalDependencies", "peerDependencies", "devDependencies"].find((s) => {
9570
+ const semver = _.get(this._fyn, ["_pkg", s, askName]);
9571
+ if (semver) {
9572
+ newOutput[SEMVER] = semver;
9573
+ }
9574
+ return semver;
9575
+ });
9576
+ this._allPaths.push(newOutput);
9577
+ } else {
9578
+ this._allPaths.push([pkgId]);
9579
+ }
9580
+ continue;
9581
+ }
9582
+ for (const pkg of askPkgs) {
9583
+ const id = this._getPkgId(pkg);
9584
+ if (output.indexOf(id) >= 0) {
9585
+ this._circularDeps.push([id].concat(output));
9586
+ continue;
9587
+ }
9588
+ let dependents = this._dependentsCache[id];
9589
+ if (!dependents) {
9590
+ this._dependentsCache[id] = dependents = this.findDependents(pkg).sort((a, b) => {
9591
+ if (a.name === b.name) {
9592
+ return semverUtil.simpleCompare(a.version, b.version);
9593
+ }
9594
+ return a.name > b.name ? 1 : -1;
9595
+ });
9596
+ }
9597
+ const followIds = dependents.filter((x) => x.name !== PACKAGE_JSON).map((x) => `${x.name}@${x.version.replace("-fynlocal_h", "")}`);
9598
+ if (dependents.length > 0) {
9599
+ const newOutput = [id].concat(output);
9600
+ if (output.length === 1) {
9601
+ ["dep", "opt", "per", "dev"].find((s) => {
9602
+ const sv = _.get(pkg, ["res", s, askName]);
9603
+ if (sv) {
9604
+ newOutput[SEMVER] = sv.semver;
9605
+ }
9606
+ return sv;
9607
+ });
9608
+ } else {
9609
+ newOutput[SEMVER] = output[SEMVER];
9610
+ }
9611
+ if (followIds.length > 0) {
9612
+ await this._findDepPaths(followIds, newOutput, askName);
9613
+ } else if (output) {
9614
+ this._allPaths.push(newOutput);
9615
+ }
9616
+ }
9617
+ }
9618
+ }
9619
+ }
9620
+ /**
9621
+ * Filter paths to show only the most significant ones.
9622
+ *
9623
+ * @param paths - All dependency paths
9624
+ * @param maxPaths - Maximum number of paths to return
9625
+ * @returns Filtered significant paths
9626
+ */
9627
+ _filterSignificantPaths(paths, maxPaths = 5) {
9628
+ const cmpDepPath = (a, b) => {
9629
+ for (let ixA = 0; ixA < a.length; ixA++) {
9630
+ if (b.length <= ixA) return 1;
9631
+ const aId = a[ixA];
9632
+ const bId = b[ixA];
9633
+ if (aId !== bId) return aId > bId ? 1 : -1;
9634
+ }
9635
+ return 0;
9636
+ };
9637
+ paths = paths.sort((a, b) => a.length - b.length);
9638
+ let minDetails = 5;
9639
+ let briefPaths = paths;
9640
+ while (briefPaths.length > maxPaths && minDetails > 0) {
9641
+ const occurLevels = {};
9642
+ briefPaths = paths.filter((dp) => {
9643
+ const last = dp.length - 1;
9644
+ for (let ix = 0; ix < last; ix++) {
9645
+ const pkgId = dp[ix];
9646
+ const occur = occurLevels[pkgId];
9647
+ if (occur && occur.level < ix && occur.leaf === dp[last] && dp.length - ix > minDetails) {
9648
+ return false;
9649
+ }
9650
+ occurLevels[pkgId] = { level: ix, leaf: dp[last] };
9651
+ }
9652
+ return true;
9653
+ });
9654
+ minDetails--;
9655
+ }
9656
+ return briefPaths.sort(cmpDepPath);
9657
+ }
9658
+ /**
9659
+ * Get detailed stat information for a specific package version.
9660
+ *
9661
+ * @param name - Package name
9662
+ * @param version - Package version
9663
+ * @returns Stat result with dependents and paths
9664
+ */
9665
+ async getPackageStat(name, version) {
9666
+ const pkgs = this._fyn._data?.pkgs;
9667
+ if (!pkgs || !pkgs[name] || !pkgs[name][version]) {
9668
+ return null;
9669
+ }
9670
+ const pkg = pkgs[name][version];
9671
+ const pkgId = `${name}@${version}`;
9672
+ const dependents = this.findDependents({ name, version, local: pkg.local }).sort((a, b) => {
9673
+ if (a.name === b.name) {
9674
+ return semverUtil.simpleCompare(a.version, b.version);
9675
+ }
9676
+ return a.name > b.name ? 1 : -1;
9677
+ });
9678
+ this._allPaths = [];
9679
+ this._circularDeps = [];
9680
+ const depIds = dependents.map((d) => this._getPkgId(d));
9681
+ await this._findDepPaths(depIds, [pkgId], name);
9682
+ const paths = this._allPaths.filter((p) => p[0] === pkgId || p.includes(pkgId));
9683
+ return {
9684
+ name,
9685
+ version,
9686
+ promoted: pkg.promoted || false,
9687
+ dependents: dependents.map((d) => ({
9688
+ name: d.name,
9689
+ version: d.version,
9690
+ promoted: d.promoted || false
9691
+ })),
9692
+ allPaths: paths,
9693
+ significantPaths: this._filterSignificantPaths(paths),
9694
+ circularDeps: this._circularDeps
9695
+ };
9696
+ }
9697
+ /**
9698
+ * Find all installed versions matching a package ID pattern.
9699
+ *
9700
+ * @param pkgId - Package ID (name or name@semver)
9701
+ * @returns Matching versions result
9702
+ */
9703
+ findMatchingVersions(pkgId) {
9704
+ const matches = this.findPkgsById(pkgId).sort(
9705
+ (a, b) => semverUtil.simpleCompare(a.version, b.version)
9706
+ );
9707
+ return {
9708
+ searchId: pkgId,
9709
+ versions: matches.map((m) => ({
9710
+ name: m.name,
9711
+ version: m.version,
9712
+ promoted: m.promoted || false
9713
+ }))
9714
+ };
9715
+ }
9716
+ /**
9717
+ * Get stat for all versions of a package.
9718
+ * This is the main entry point for the audit formatter.
9719
+ *
9720
+ * @param name - Package name
9721
+ * @param version - Optional specific version
9722
+ * @returns Array of stat results for all matching versions
9723
+ */
9724
+ async getPackageStats(name, version) {
9725
+ const pkgId = version ? `${name}@${version}` : name;
9726
+ const matches = this.findMatchingVersions(pkgId);
9727
+ const results = [];
9728
+ for (const match of matches.versions) {
9729
+ const stat = await this.getPackageStat(match.name, match.version);
9730
+ if (stat) {
9731
+ results.push(stat);
9732
+ }
9733
+ }
9734
+ return results;
9735
+ }
9736
+ /**
9737
+ * Format dependency paths with semver info.
9738
+ *
9739
+ * @param paths - Array of paths
9740
+ * @returns Formatted path strings
9741
+ */
9742
+ formatPaths(paths) {
9743
+ return paths.map((p) => {
9744
+ const semver = p[SEMVER];
9745
+ const pathStr = p.join(" > ");
9746
+ return semver ? `${pathStr} (${semver})` : pathStr;
9747
+ });
9748
+ }
9749
+ /**
9750
+ * Reset caches. Call this if fyn data changes.
9751
+ */
9752
+ reset() {
9753
+ this._fynRes = null;
9754
+ this._dependentsCache = {};
9755
+ this._allPaths = [];
9756
+ this._circularDeps = [];
9757
+ }
9758
+ }
9759
+ module.exports = PkgStatProvider;
9760
+
9761
+
8840
9762
  /***/ }),
8841
9763
 
8842
9764
  /***/ "./lib/symbols.ts":
@@ -102709,63 +103631,85 @@ module.exports = validate;
102709
103631
 
102710
103632
  /***/ }),
102711
103633
 
102712
- /***/ "./node_modules/.f/_/visual-exec/0.1.14/visual-exec/lib/get-default-logger.js":
102713
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
103634
+ /***/ "./node_modules/.f/_/visual-exec/0.2.0-fynlocal_h/visual-exec/dist/get-default-logger.js":
103635
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
102714
103636
 
102715
103637
  "use strict";
102716
103638
 
102717
- const VisualLogger = __webpack_require__("./node_modules/.f/_/visual-logger/1.1.3/visual-logger/lib/visual-logger.js");
102718
- const { isCI } = __webpack_require__("./node_modules/.f/_/ci-info/3.9.0/ci-info/index.js");
102719
- let logger;
102720
- const getLogger = () => {
103639
+ var __importDefault = this && this.__importDefault || function(mod) {
103640
+ return mod && mod.__esModule ? mod : { "default": mod };
103641
+ };
103642
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
103643
+ exports.getDefaultLogger = getDefaultLogger;
103644
+ const visual_logger_1 = __importDefault(__webpack_require__("./node_modules/.f/_/visual-logger/1.1.3/visual-logger/lib/visual-logger.js"));
103645
+ const ci_info_1 = __webpack_require__("./node_modules/.f/_/ci-info/3.9.0/ci-info/index.js");
103646
+ let logger = null;
103647
+ function getDefaultLogger() {
102721
103648
  if (!logger) {
102722
- logger = new VisualLogger();
102723
- if (isCI) {
103649
+ logger = new visual_logger_1.default();
103650
+ if (ci_info_1.isCI) {
102724
103651
  logger.info("visual-exec: CI env detected");
102725
103652
  logger.setItemType("none");
102726
103653
  }
102727
103654
  }
102728
103655
  return logger;
102729
- };
102730
- module.exports = getLogger;
103656
+ }
103657
+ exports["default"] = getDefaultLogger;
102731
103658
 
102732
103659
 
102733
103660
  /***/ }),
102734
103661
 
102735
- /***/ "./node_modules/.f/_/visual-exec/0.1.14/visual-exec/lib/visual-exec.js":
102736
- /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
103662
+ /***/ "./node_modules/.f/_/visual-exec/0.2.0-fynlocal_h/visual-exec/dist/index.js":
103663
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
102737
103664
 
102738
103665
  "use strict";
102739
103666
 
102740
- const xsh = __webpack_require__("./node_modules/.f/_/xsh/0.4.6-fynlocal_h/xsh/lib/index.js");
102741
- const chalk = __webpack_require__("./node_modules/.f/_/chalk/4.1.2/chalk/source/index.js");
102742
- const getDefaultLogger = __webpack_require__("./node_modules/.f/_/visual-exec/0.1.14/visual-exec/lib/get-default-logger.js");
102743
- const VisualLogger = __webpack_require__("./node_modules/.f/_/visual-logger/1.1.3/visual-logger/lib/visual-logger.js");
102744
- const hasAnsi = __webpack_require__("./node_modules/.f/_/has-ansi/4.0.1/has-ansi/index.js");
102745
- const stripAnsi = __webpack_require__("./node_modules/.f/_/strip-ansi/6.0.1/strip-ansi/index.js");
102746
- xsh.Promise = Promise;
103667
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
103668
+ exports["default"] = exports.getDefaultLogger = exports.VisualExec = void 0;
103669
+ var visual_exec_1 = __webpack_require__("./node_modules/.f/_/visual-exec/0.2.0-fynlocal_h/visual-exec/dist/visual-exec.js");
103670
+ Object.defineProperty(exports, "VisualExec", ({ enumerable: true, get: function() {
103671
+ return visual_exec_1.VisualExec;
103672
+ } }));
103673
+ var get_default_logger_1 = __webpack_require__("./node_modules/.f/_/visual-exec/0.2.0-fynlocal_h/visual-exec/dist/get-default-logger.js");
103674
+ Object.defineProperty(exports, "getDefaultLogger", ({ enumerable: true, get: function() {
103675
+ return get_default_logger_1.getDefaultLogger;
103676
+ } }));
103677
+ var visual_exec_2 = __webpack_require__("./node_modules/.f/_/visual-exec/0.2.0-fynlocal_h/visual-exec/dist/visual-exec.js");
103678
+ Object.defineProperty(exports, "default", ({ enumerable: true, get: function() {
103679
+ return visual_exec_2.VisualExec;
103680
+ } }));
103681
+
103682
+
103683
+ /***/ }),
103684
+
103685
+ /***/ "./node_modules/.f/_/visual-exec/0.2.0-fynlocal_h/visual-exec/dist/visual-exec.js":
103686
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
103687
+
103688
+ "use strict";
103689
+
103690
+ var __importDefault = this && this.__importDefault || function(mod) {
103691
+ return mod && mod.__esModule ? mod : { "default": mod };
103692
+ };
103693
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
103694
+ exports.VisualExec = void 0;
103695
+ const xsh_1 = __importDefault(__webpack_require__("./node_modules/.f/_/xsh/0.4.6-fynlocal_h/xsh/lib/index.js"));
103696
+ const chalk_1 = __importDefault(__webpack_require__("./node_modules/.f/_/chalk/4.1.2/chalk/source/index.js"));
103697
+ const get_default_logger_1 = __webpack_require__("./node_modules/.f/_/visual-exec/0.2.0-fynlocal_h/visual-exec/dist/get-default-logger.js");
103698
+ const visual_logger_1 = __importDefault(__webpack_require__("./node_modules/.f/_/visual-logger/1.1.3/visual-logger/lib/visual-logger.js"));
103699
+ const has_ansi_1 = __importDefault(__webpack_require__("./node_modules/.f/_/has-ansi/4.0.1/has-ansi/index.js"));
103700
+ const strip_ansi_1 = __importDefault(__webpack_require__("./node_modules/.f/_/strip-ansi/6.0.1/strip-ansi/index.js"));
103701
+ xsh_1.default.Promise = Promise;
102747
103702
  const ONE_MB = 1024 * 1024;
102748
103703
  const TEN_MB = 10 * ONE_MB;
102749
103704
  class VisualExec {
102750
- constructor({
102751
- command,
102752
- cwd = process.cwd(),
102753
- visualLogger,
102754
- spinner = VisualLogger.spinners[1],
102755
- displayTitle = void 0,
102756
- logLabel = void 0,
102757
- outputLabel = void 0,
102758
- outputLevel = "verbose",
102759
- maxBuffer = TEN_MB,
102760
- forceStderr = true,
102761
- checkStdoutError = true
102762
- }) {
103705
+ constructor(options) {
103706
+ const { command, cwd = process.cwd(), visualLogger, spinner = visual_logger_1.default.spinners[1], displayTitle, logLabel, outputLabel, outputLevel = "verbose", maxBuffer = TEN_MB, forceStderr = true, checkStdoutError = true } = options;
102763
103707
  this._title = displayTitle || this._makeTitle(command);
102764
103708
  this._logLabel = logLabel || this._title;
102765
103709
  this._outputLabel = outputLabel || this._title;
102766
103710
  this._command = command;
102767
103711
  this._cwd = cwd || process.cwd();
102768
- this._logger = visualLogger || getDefaultLogger();
103712
+ this._logger = visualLogger || (0, get_default_logger_1.getDefaultLogger)();
102769
103713
  this._outputLevel = outputLevel;
102770
103714
  this._spinner = spinner;
102771
103715
  this._maxBuffer = maxBuffer;
@@ -102779,11 +103723,10 @@ class VisualExec {
102779
103723
  }
102780
103724
  return `Running ${command}`;
102781
103725
  }
102782
- /* eslint-disable max-statements */
102783
103726
  _updateDigest(item, buf) {
102784
103727
  const newBuf = item.buf + buf;
102785
103728
  const lines = newBuf.split("\n").map((x) => x && x.trim()).filter((x) => x);
102786
- const stripLines = lines.map((x) => hasAnsi(x) ? stripAnsi(x) : x);
103729
+ const stripLines = lines.map((x) => (0, has_ansi_1.default)(x) ? (0, strip_ansi_1.default)(x) : x);
102787
103730
  let length = 0;
102788
103731
  let ix = stripLines.length - 1;
102789
103732
  for (; ix >= 0; ix--) {
@@ -102810,7 +103753,7 @@ class VisualExec {
102810
103753
  item.buf += "\n";
102811
103754
  }
102812
103755
  this._logger.updateItem(item.name, {
102813
- msg: msgs.join(chalk.blue.inverse("\\n")),
103756
+ msg: msgs.join(chalk_1.default.blue.inverse("\\n")),
102814
103757
  _save: false,
102815
103758
  _render: false
102816
103759
  });
@@ -102852,51 +103795,58 @@ stdout`,
102852
103795
  child.stdout.removeListener("data", this._updateStdout);
102853
103796
  child.stderr.removeListener("data", this._updateStderr);
102854
103797
  if (err) {
102855
- this._logger.error(`${chalk.red("Failed")} ${this._logLabel} - ${chalk.red(err.message)}`);
103798
+ this._logger.error(`${chalk_1.default.red("Failed")} ${this._logLabel} - ${chalk_1.default.red(err.message)}`);
102856
103799
  output = err.output;
102857
103800
  } else {
102858
103801
  const time = ((Date.now() - this._startTime) / 1e3).toFixed(2);
102859
- const dispTime = `${chalk.magenta(time)}secs`;
102860
- this._logger.info(`Done ${this._logLabel} ${dispTime} ${chalk.green("exit code 0")}`);
103802
+ const dispTime = `${chalk_1.default.magenta(time)}secs`;
103803
+ this._logger.info(`Done ${this._logLabel} ${dispTime} ${chalk_1.default.green("exit code 0")}`);
102861
103804
  }
102862
103805
  this.logFinalOutput(err, output);
102863
103806
  }
102864
103807
  checkForErrors(text) {
102865
- return this._checkStdoutError && text && text.match(this._checkStdoutError);
103808
+ if (!this._checkStdoutError || !text)
103809
+ return null;
103810
+ if (this._checkStdoutError instanceof RegExp) {
103811
+ return text.match(this._checkStdoutError);
103812
+ }
103813
+ return null;
102866
103814
  }
103815
+ /**
103816
+ * Log the final output. Can be overridden to customize output handling.
103817
+ * Set to a no-op function to suppress output logging.
103818
+ */
102867
103819
  logFinalOutput(err, output) {
102868
- const level = err || this._forceStderr && output.stderr || this.checkForErrors(output.stdout) ? "error" : this._outputLevel;
103820
+ const level = err || this._forceStderr && output?.stderr || this.checkForErrors(output?.stdout || "") ? "error" : this._outputLevel;
102869
103821
  if (!output || !output.stdout && !output.stderr) {
102870
- this._logger[level](`${chalk.green("No output")} from ${this._outputLabel}`);
103822
+ this._logger[level](`${chalk_1.default.green("No output")} from ${this._outputLabel}`);
102871
103823
  return;
102872
103824
  }
102873
- const colorize = (t) => t.replace(/ERR!/g, chalk.red("ERR!"));
102874
- const logs = [chalk.green(">>>"), `Start of output from ${this._outputLabel} ===`];
103825
+ const colorize = (t) => t.replace(/ERR!/g, chalk_1.default.red("ERR!"));
103826
+ const logs = [chalk_1.default.green(">>>"), `Start of output from ${this._outputLabel} ===`];
102875
103827
  if (output.stdout) {
102876
103828
  logs.push(`
102877
103829
  ${colorize(output.stdout)}`);
102878
103830
  }
102879
103831
  if (output.stderr) {
102880
- logs.push(chalk.red("\n=== stderr ===\n") + colorize(output.stderr));
103832
+ logs.push(chalk_1.default.red("\n=== stderr ===\n") + colorize(output.stderr));
102881
103833
  }
102882
- logs.push(chalk.blue("\n<<<"), `End of output from ${this._outputLabel} ---`);
103834
+ logs.push(chalk_1.default.blue("\n<<<"), `End of output from ${this._outputLabel} ---`);
102883
103835
  this._logger.prefix(false)[level](...logs);
102884
103836
  }
102885
103837
  execute(command) {
102886
103838
  this._startTime = Date.now();
102887
- const child = xsh.exec(
102888
- {
102889
- silent: true,
102890
- cwd: this._cwd,
102891
- env: Object.assign({}, process.env, { PWD: this._cwd }),
102892
- maxBuffer: this._maxBuffer
102893
- },
102894
- command || this._command
102895
- );
103839
+ const child = xsh_1.default.exec({
103840
+ silent: true,
103841
+ cwd: this._cwd,
103842
+ env: Object.assign({}, process.env, { PWD: this._cwd }),
103843
+ maxBuffer: this._maxBuffer
103844
+ }, command || this._command);
102896
103845
  return this.show(child);
102897
103846
  }
102898
103847
  }
102899
- module.exports = VisualExec;
103848
+ exports.VisualExec = VisualExec;
103849
+ exports["default"] = VisualExec;
102900
103850
 
102901
103851
 
102902
103852
  /***/ }),