@calimero-network/registry-cli 1.22.2 → 1.22.3

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/dist/index.js CHANGED
@@ -5,10 +5,9 @@ import { createRequire } from 'module';
5
5
  import ora4 from 'ora';
6
6
  import axios from 'axios';
7
7
  import fs7, { existsSync, writeFileSync } from 'fs';
8
- import path5 from 'path';
8
+ import path6 from 'path';
9
9
  import os2 from 'os';
10
10
  import fastify from 'fastify';
11
- import cors from '@fastify/cors';
12
11
  import crypto2 from 'crypto';
13
12
  import * as tar from 'tar';
14
13
 
@@ -20,7 +19,7 @@ var RemoteConfig = class {
20
19
  configPath;
21
20
  config;
22
21
  constructor() {
23
- this.configPath = path5.join(
22
+ this.configPath = path6.join(
24
23
  os2.homedir(),
25
24
  ".calimero-registry",
26
25
  "remote-config.json"
@@ -47,7 +46,7 @@ var RemoteConfig = class {
47
46
  return defaults;
48
47
  }
49
48
  saveConfig() {
50
- const configDir = path5.dirname(this.configPath);
49
+ const configDir = path6.dirname(this.configPath);
51
50
  if (!fs7.existsSync(configDir)) {
52
51
  fs7.mkdirSync(configDir, { recursive: true });
53
52
  }
@@ -128,20 +127,20 @@ var RemoteConfig = class {
128
127
  function defaultConfig2() {
129
128
  return {
130
129
  server: {
131
- // Reset used to say localhost here, but never reached the listener:
132
- // `local start` sets the host on every run and defaults to 0.0.0.0,
133
- // which is also what publicHost assumes, since a container reaching
134
- // host.docker.internal cannot be served from loopback.
135
- host: "0.0.0.0",
130
+ // Hardening: default to loopback so the dev server is not reachable from
131
+ // the LAN or a browsing website. Docker users who need container access
132
+ // opt in explicitly with `local start --host 0.0.0.0`; publicHost stays
133
+ // host.docker.internal for the URLs baked into manifests in that case.
134
+ host: "127.0.0.1",
136
135
  port: 8082,
137
136
  publicHost: "host.docker.internal"
138
137
  },
139
138
  data: {
140
- dir: path5.join(os2.homedir(), ".calimero-registry", "data"),
141
- artifactsDir: path5.join(os2.homedir(), ".calimero-registry", "artifacts")
139
+ dir: path6.join(os2.homedir(), ".calimero-registry", "data"),
140
+ artifactsDir: path6.join(os2.homedir(), ".calimero-registry", "artifacts")
142
141
  },
143
142
  artifacts: {
144
- storageDir: path5.join(os2.homedir(), ".calimero-registry", "artifacts"),
143
+ storageDir: path6.join(os2.homedir(), ".calimero-registry", "artifacts"),
145
144
  serveLocal: true,
146
145
  copyArtifacts: true,
147
146
  maxFileSize: "100MB",
@@ -154,12 +153,12 @@ var LocalConfig = class {
154
153
  dataDir;
155
154
  config;
156
155
  constructor() {
157
- this.configPath = path5.join(
156
+ this.configPath = path6.join(
158
157
  os2.homedir(),
159
158
  ".calimero-registry",
160
159
  "config.json"
161
160
  );
162
- this.dataDir = path5.join(os2.homedir(), ".calimero-registry");
161
+ this.dataDir = path6.join(os2.homedir(), ".calimero-registry");
163
162
  this.config = this.loadConfig();
164
163
  }
165
164
  loadConfig() {
@@ -190,7 +189,7 @@ var LocalConfig = class {
190
189
  return defaults;
191
190
  }
192
191
  saveConfig() {
193
- const configDir = path5.dirname(this.configPath);
192
+ const configDir = path6.dirname(this.configPath);
194
193
  if (!fs7.existsSync(configDir)) {
195
194
  fs7.mkdirSync(configDir, { recursive: true });
196
195
  }
@@ -224,8 +223,8 @@ var LocalConfig = class {
224
223
  }
225
224
  setDataDir(dir) {
226
225
  this.config.data.dir = dir;
227
- this.config.data.artifactsDir = path5.join(dir, "artifacts");
228
- this.config.artifacts.storageDir = path5.join(dir, "artifacts");
226
+ this.config.data.artifactsDir = path6.join(dir, "artifacts");
227
+ this.config.artifacts.storageDir = path6.join(dir, "artifacts");
229
228
  this.saveConfig();
230
229
  }
231
230
  getArtifactsDir() {
@@ -249,8 +248,8 @@ var LocalConfig = class {
249
248
  const dirs = [
250
249
  this.getDataDir(),
251
250
  this.getArtifactsDir(),
252
- path5.join(this.getDataDir(), "backups"),
253
- path5.join(this.getDataDir(), "logs")
251
+ path6.join(this.getDataDir(), "backups"),
252
+ path6.join(this.getDataDir(), "logs")
254
253
  ];
255
254
  dirs.forEach((dir) => {
256
255
  if (!fs7.existsSync(dir)) {
@@ -390,12 +389,12 @@ var LocalDataStore = class {
390
389
  artifactsFile;
391
390
  constructor(config) {
392
391
  this.config = config;
393
- this.appsFile = path5.join(config.getDataDir(), "apps.json");
394
- this.bundleManifestsFile = path5.join(
392
+ this.appsFile = path6.join(config.getDataDir(), "apps.json");
393
+ this.bundleManifestsFile = path6.join(
395
394
  config.getDataDir(),
396
395
  "bundle_manifests.json"
397
396
  );
398
- this.artifactsFile = path5.join(config.getDataDir(), "artifacts.json");
397
+ this.artifactsFile = path6.join(config.getDataDir(), "artifacts.json");
399
398
  this.data = {
400
399
  apps: /* @__PURE__ */ new Map(),
401
400
  bundleManifests: /* @__PURE__ */ new Map(),
@@ -516,12 +515,12 @@ var LocalDataStore = class {
516
515
  // Backup and restore
517
516
  async backup(outputPath) {
518
517
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
519
- const backupPath = outputPath || path5.join(
518
+ const backupPath = outputPath || path6.join(
520
519
  this.config.getDataDir(),
521
520
  "backups",
522
521
  `backup-${timestamp}.json`
523
522
  );
524
- const backupDir = path5.dirname(backupPath);
523
+ const backupDir = path6.dirname(backupPath);
525
524
  if (!fs7.existsSync(backupDir)) {
526
525
  fs7.mkdirSync(backupDir, { recursive: true });
527
526
  }
@@ -613,16 +612,30 @@ var LocalArtifactServer = class {
613
612
  fs7.mkdirSync(this.artifactsDir, { recursive: true });
614
613
  }
615
614
  }
615
+ /**
616
+ * Hardening: build a path under artifactsDir from untrusted segments (request
617
+ * params, or bundle-provided package/version/filename) and guarantee it stays
618
+ * inside artifactsDir. A `..` or absolute segment would otherwise let a
619
+ * request read or write outside the artifact store (path traversal).
620
+ */
621
+ resolveArtifactPath(...segments) {
622
+ const base = path6.resolve(this.artifactsDir);
623
+ const resolved = path6.resolve(base, ...segments);
624
+ if (resolved !== base && !resolved.startsWith(base + path6.sep)) {
625
+ throw new Error("Invalid artifact path: escapes artifacts directory");
626
+ }
627
+ return resolved;
628
+ }
616
629
  // Copy artifact to local storage
617
630
  async copyArtifactToLocal(sourcePath, appId, version2, filename) {
618
631
  if (!fs7.existsSync(sourcePath)) {
619
632
  throw new Error(`Source file not found: ${sourcePath}`);
620
633
  }
621
- const appVersionDir = path5.join(this.artifactsDir, appId, version2);
634
+ const targetPath = this.resolveArtifactPath(appId, version2, filename);
635
+ const appVersionDir = path6.dirname(targetPath);
622
636
  if (!fs7.existsSync(appVersionDir)) {
623
637
  fs7.mkdirSync(appVersionDir, { recursive: true });
624
638
  }
625
- const targetPath = path5.join(appVersionDir, filename);
626
639
  fs7.copyFileSync(sourcePath, targetPath);
627
640
  const fileHash = await this.calculateFileHash(targetPath);
628
641
  this.dataStore.setArtifactPath(fileHash, targetPath);
@@ -630,7 +643,7 @@ var LocalArtifactServer = class {
630
643
  }
631
644
  // Serve artifact by app ID, version, and filename
632
645
  async serveArtifact(appId, version2, filename) {
633
- const artifactPath = path5.join(this.artifactsDir, appId, version2, filename);
646
+ const artifactPath = this.resolveArtifactPath(appId, version2, filename);
634
647
  if (!fs7.existsSync(artifactPath)) {
635
648
  throw new Error(`Artifact not found: ${artifactPath}`);
636
649
  }
@@ -679,7 +692,7 @@ var LocalArtifactServer = class {
679
692
  let files = [];
680
693
  const items = fs7.readdirSync(dir);
681
694
  for (const item of items) {
682
- const fullPath = path5.join(dir, item);
695
+ const fullPath = path6.join(dir, item);
683
696
  const stat = fs7.statSync(fullPath);
684
697
  if (stat.isDirectory()) {
685
698
  files = files.concat(getAllFiles(fullPath));
@@ -708,7 +721,7 @@ var LocalArtifactServer = class {
708
721
  let files = [];
709
722
  const items = fs7.readdirSync(dir);
710
723
  for (const item of items) {
711
- const fullPath = path5.join(dir, item);
724
+ const fullPath = path6.join(dir, item);
712
725
  const stat = fs7.statSync(fullPath);
713
726
  if (stat.isDirectory()) {
714
727
  files = files.concat(getAllFiles(fullPath));
@@ -759,9 +772,27 @@ var LocalRegistryServer = class {
759
772
  level: "info"
760
773
  }
761
774
  });
762
- await this.server.register(cors, {
763
- origin: true,
764
- credentials: true
775
+ const allowedHosts = /* @__PURE__ */ new Set();
776
+ for (const name of [
777
+ "localhost",
778
+ "127.0.0.1",
779
+ "[::1]",
780
+ this.config.getPublicHost(),
781
+ host === "0.0.0.0" || host === "::" ? "" : host
782
+ ]) {
783
+ if (!name) continue;
784
+ allowedHosts.add(name);
785
+ allowedHosts.add(`${name}:${serverPort}`);
786
+ }
787
+ this.server.addHook("onRequest", async (request, reply) => {
788
+ const hostHeader = (request.headers.host ?? "").toLowerCase();
789
+ if (!allowedHosts.has(hostHeader)) {
790
+ return reply.code(403).send({
791
+ statusCode: 403,
792
+ error: "Forbidden",
793
+ message: "Invalid Host header"
794
+ });
795
+ }
765
796
  });
766
797
  await this.registerRoutes();
767
798
  await this.server.listen({ port: serverPort, host });
@@ -805,6 +836,20 @@ var LocalRegistryServer = class {
805
836
  async seed() {
806
837
  await this.dataStore.seed();
807
838
  }
839
+ /**
840
+ * Hardening: resolve a caller-supplied backup path relative to the CLI data
841
+ * dir and verify it stays inside it. Rejects absolute paths and `..` segments
842
+ * that would escape, so the HTTP backup/restore routes cannot read or write
843
+ * arbitrary filesystem locations.
844
+ */
845
+ confineToDataDir(candidate) {
846
+ const dataDir = path6.resolve(this.config.getDataDir());
847
+ const resolved = path6.resolve(dataDir, candidate);
848
+ if (resolved !== dataDir && !resolved.startsWith(dataDir + path6.sep)) {
849
+ throw new Error("Path escapes data directory");
850
+ }
851
+ return resolved;
852
+ }
808
853
  async registerRoutes() {
809
854
  if (!this.server) {
810
855
  throw new Error("Server not initialized");
@@ -868,14 +913,37 @@ var LocalRegistryServer = class {
868
913
  await this.reset();
869
914
  return { message: "Local registry data reset successfully" };
870
915
  });
871
- this.server.get("/local/backup", async (request) => {
916
+ this.server.post("/local/backup", async (request, reply) => {
872
917
  const query = request.query;
873
- const backupPath = await this.backup(query.output);
918
+ let output;
919
+ if (query.output) {
920
+ try {
921
+ output = this.confineToDataDir(query.output);
922
+ } catch {
923
+ return reply.code(400).send({
924
+ error: "invalid_path",
925
+ message: "output escapes data dir"
926
+ });
927
+ }
928
+ }
929
+ const backupPath = await this.backup(output);
874
930
  return { backupPath };
875
931
  });
876
- this.server.post("/local/restore", async (request) => {
877
- const { backupPath } = request.body;
878
- await this.restore(backupPath);
932
+ this.server.post("/local/restore", async (request, reply) => {
933
+ const { backupPath } = request.body ?? {};
934
+ if (!backupPath) {
935
+ return reply.code(400).send({ error: "invalid_path", message: "backupPath is required" });
936
+ }
937
+ let resolved;
938
+ try {
939
+ resolved = this.confineToDataDir(backupPath);
940
+ } catch {
941
+ return reply.code(400).send({
942
+ error: "invalid_path",
943
+ message: "backupPath escapes data dir"
944
+ });
945
+ }
946
+ await this.restore(resolved);
879
947
  return { message: "Data restored successfully" };
880
948
  });
881
949
  this.server.post("/local/seed", async () => {
@@ -948,7 +1016,7 @@ var localCommand = new Command("local").description(
948
1016
  "Manage local registry for development"
949
1017
  );
950
1018
  localCommand.addCommand(
951
- new Command("start").description("Start local registry server").option("-p, --port <port>", "Port to run the server on", "8082").option("-h, --host <host>", "Host to bind the server to", "0.0.0.0").option(
1019
+ new Command("start").description("Start local registry server").option("-p, --port <port>", "Port to run the server on", "8082").option("-h, --host <host>", "Host to bind the server to", "127.0.0.1").option(
952
1020
  "--public-host <host>",
953
1021
  "Public host exposed in manifest artifact URLs",
954
1022
  "host.docker.internal"
@@ -1315,7 +1383,7 @@ Note:
1315
1383
  try {
1316
1384
  let manifestConfig = {};
1317
1385
  if (options.manifest) {
1318
- const manifestPath = path5.resolve(options.manifest);
1386
+ const manifestPath = path6.resolve(options.manifest);
1319
1387
  if (!fs7.existsSync(manifestPath)) {
1320
1388
  console.error(`\u274C Manifest file not found: ${options.manifest}`);
1321
1389
  process.exit(1);
@@ -1392,12 +1460,12 @@ Note:
1392
1460
  );
1393
1461
  process.exit(1);
1394
1462
  }
1395
- const wasmPath = path5.resolve(wasmFile);
1463
+ const wasmPath = path6.resolve(wasmFile);
1396
1464
  if (!fs7.existsSync(wasmPath)) {
1397
1465
  console.error(`\u274C WASM file not found: ${wasmFile}`);
1398
1466
  process.exit(1);
1399
1467
  }
1400
- console.log(`\u{1F4E6} Creating MPK bundle from: ${path5.basename(wasmPath)}`);
1468
+ console.log(`\u{1F4E6} Creating MPK bundle from: ${path6.basename(wasmPath)}`);
1401
1469
  const wasmContent = fs7.readFileSync(wasmPath);
1402
1470
  const wasmSize = wasmContent.length;
1403
1471
  const wasmHash = crypto2.createHash("sha256").update(wasmContent).digest("hex");
@@ -1407,10 +1475,10 @@ Note:
1407
1475
  const abiPathFromManifest = typeof manifestConfig.abi === "string" ? manifestConfig.abi : null;
1408
1476
  const abiFilePath = abiPathFromOption || abiPathFromManifest;
1409
1477
  if (abiFilePath) {
1410
- const abiResolvedPath = abiPathFromOption ? path5.resolve(abiFilePath) : options.manifest && abiPathFromManifest ? path5.resolve(
1411
- path5.dirname(path5.resolve(options.manifest)),
1478
+ const abiResolvedPath = abiPathFromOption ? path6.resolve(abiFilePath) : options.manifest && abiPathFromManifest ? path6.resolve(
1479
+ path6.dirname(path6.resolve(options.manifest)),
1412
1480
  abiFilePath
1413
- ) : path5.resolve(abiFilePath);
1481
+ ) : path6.resolve(abiFilePath);
1414
1482
  if (!fs7.existsSync(abiResolvedPath)) {
1415
1483
  console.error(`\u274C ABI file not found: ${abiFilePath}`);
1416
1484
  console.error(` Resolved path: ${abiResolvedPath}`);
@@ -1426,7 +1494,7 @@ Note:
1426
1494
  size: abiContent.length
1427
1495
  };
1428
1496
  console.log(
1429
- ` Including ABI file: ${path5.basename(abiResolvedPath)}`
1497
+ ` Including ABI file: ${path6.basename(abiResolvedPath)}`
1430
1498
  );
1431
1499
  } catch (error) {
1432
1500
  console.error(
@@ -1450,7 +1518,7 @@ Note:
1450
1518
  const manifestServices = Array.isArray(
1451
1519
  manifestConfig.services
1452
1520
  ) ? manifestConfig.services : [];
1453
- const manifestDir = options.manifest ? path5.dirname(path5.resolve(options.manifest)) : process.cwd();
1521
+ const manifestDir = options.manifest ? path6.dirname(path6.resolve(options.manifest)) : process.cwd();
1454
1522
  const allServiceSources = [
1455
1523
  ...cliServices.map((src) => ({ src, baseDir: process.cwd() })),
1456
1524
  ...manifestServices.map((src) => ({ src, baseDir: manifestDir }))
@@ -1484,7 +1552,7 @@ Note:
1484
1552
  );
1485
1553
  process.exit(1);
1486
1554
  }
1487
- const svcWasmPath = path5.resolve(baseDir, src.wasm);
1555
+ const svcWasmPath = path6.resolve(baseDir, src.wasm);
1488
1556
  if (!fs7.existsSync(svcWasmPath)) {
1489
1557
  console.error(
1490
1558
  `\u274C Service "${src.name}" WASM not found: ${src.wasm}`
@@ -1508,7 +1576,7 @@ Note:
1508
1576
  content: svcWasmContent
1509
1577
  });
1510
1578
  if (src.abi) {
1511
- const svcAbiPath = path5.resolve(baseDir, src.abi);
1579
+ const svcAbiPath = path6.resolve(baseDir, src.abi);
1512
1580
  if (!fs7.existsSync(svcAbiPath)) {
1513
1581
  console.error(
1514
1582
  `\u274C Service "${src.name}" ABI not found: ${src.abi}`
@@ -1542,7 +1610,7 @@ Note:
1542
1610
  }
1543
1611
  serviceArtifacts.push(entry);
1544
1612
  console.log(
1545
- ` Including service: ${src.name} (${path5.basename(svcWasmPath)})`
1613
+ ` Including service: ${src.name} (${path6.basename(svcWasmPath)})`
1546
1614
  );
1547
1615
  }
1548
1616
  const metadata = {
@@ -1575,29 +1643,29 @@ Note:
1575
1643
  links: Object.keys(links).length > 0 ? links : void 0,
1576
1644
  signature: void 0
1577
1645
  };
1578
- let outputDir = finalOutput ? path5.resolve(finalOutput) : path5.join(process.cwd(), finalPackage, finalVersion);
1646
+ let outputDir = finalOutput ? path6.resolve(finalOutput) : path6.join(process.cwd(), finalPackage, finalVersion);
1579
1647
  if (!fs7.existsSync(outputDir)) {
1580
1648
  fs7.mkdirSync(outputDir, { recursive: true });
1581
1649
  }
1582
1650
  fs7.writeFileSync(
1583
- path5.join(outputDir, "manifest.json"),
1651
+ path6.join(outputDir, "manifest.json"),
1584
1652
  JSON.stringify(manifest, null, 2)
1585
1653
  );
1586
- fs7.writeFileSync(path5.join(outputDir, "app.wasm"), wasmContent);
1654
+ fs7.writeFileSync(path6.join(outputDir, "app.wasm"), wasmContent);
1587
1655
  if (abiContent) {
1588
- fs7.writeFileSync(path5.join(outputDir, "abi.json"), abiContent);
1656
+ fs7.writeFileSync(path6.join(outputDir, "abi.json"), abiContent);
1589
1657
  }
1590
- const servicesDir = path5.join(outputDir, "services");
1658
+ const servicesDir = path6.join(outputDir, "services");
1591
1659
  for (const { relPath, content } of serviceFilesToWrite) {
1592
- const dest = path5.join(outputDir, relPath);
1593
- const rel = path5.relative(servicesDir, dest);
1594
- if (rel.startsWith("..") || path5.isAbsolute(rel)) {
1660
+ const dest = path6.join(outputDir, relPath);
1661
+ const rel = path6.relative(servicesDir, dest);
1662
+ if (rel.startsWith("..") || path6.isAbsolute(rel)) {
1595
1663
  console.error(
1596
1664
  `\u274C Refusing to write service file outside services/: ${relPath}`
1597
1665
  );
1598
1666
  process.exit(1);
1599
1667
  }
1600
- fs7.mkdirSync(path5.dirname(dest), { recursive: true });
1668
+ fs7.mkdirSync(path6.dirname(dest), { recursive: true });
1601
1669
  fs7.writeFileSync(dest, content);
1602
1670
  }
1603
1671
  console.log(`\u2705 Bundle files written to: ${outputDir}`);
@@ -1615,7 +1683,7 @@ Note:
1615
1683
  console.log("");
1616
1684
  console.log("Next steps:");
1617
1685
  console.log(
1618
- ` 1. Sign the manifest: mero-sign sign ${path5.join(outputDir, "manifest.json")} --key key.json`
1686
+ ` 1. Sign the manifest: mero-sign sign ${path6.join(outputDir, "manifest.json")} --key key.json`
1619
1687
  );
1620
1688
  console.log(
1621
1689
  ` 2. Push the bundle: calimero-registry bundle push ${outputDir} --remote`
@@ -1684,15 +1752,15 @@ Note:
1684
1752
  );
1685
1753
  process.exit(1);
1686
1754
  }
1687
- const fullPath = path5.resolve(bundleFile);
1755
+ const fullPath = path6.resolve(bundleFile);
1688
1756
  if (!fs7.existsSync(fullPath)) {
1689
1757
  console.error(`\u274C File not found: ${bundleFile}`);
1690
1758
  process.exit(1);
1691
1759
  }
1692
1760
  mpkPath = fullPath;
1693
1761
  if (fs7.statSync(fullPath).isDirectory()) {
1694
- const manifestInDir = path5.join(fullPath, "manifest.json");
1695
- const wasmInDir = path5.join(fullPath, "app.wasm");
1762
+ const manifestInDir = path6.join(fullPath, "manifest.json");
1763
+ const wasmInDir = path6.join(fullPath, "app.wasm");
1696
1764
  if (!fs7.existsSync(manifestInDir)) {
1697
1765
  console.error(
1698
1766
  `\u274C manifest.json not found in directory: ${fullPath}`
@@ -1703,7 +1771,7 @@ Note:
1703
1771
  console.error(`\u274C app.wasm not found in directory: ${fullPath}`);
1704
1772
  process.exit(1);
1705
1773
  }
1706
- tempMpk = path5.join(fullPath, `.temp-push-${Date.now()}.mpk`);
1774
+ tempMpk = path6.join(fullPath, `.temp-push-${Date.now()}.mpk`);
1707
1775
  let dirManifest;
1708
1776
  try {
1709
1777
  dirManifest = JSON.parse(
@@ -1740,7 +1808,7 @@ Note:
1740
1808
  process.exit(1);
1741
1809
  }
1742
1810
  for (const f of archiveFiles) {
1743
- if (!fs7.existsSync(path5.join(fullPath, f))) {
1811
+ if (!fs7.existsSync(path6.join(fullPath, f))) {
1744
1812
  console.error(
1745
1813
  `\u274C Bundle file referenced by manifest not found: ${f}`
1746
1814
  );
@@ -1756,7 +1824,7 @@ Note:
1756
1824
  `\u{1F4E6} Packed directory into temporary bundle (${archiveFiles.length} files)`
1757
1825
  );
1758
1826
  }
1759
- console.log(`\u{1F4E6} Processing bundle: ${path5.basename(mpkPath)}`);
1827
+ console.log(`\u{1F4E6} Processing bundle: ${path6.basename(mpkPath)}`);
1760
1828
  const manifest = await extractManifest(mpkPath);
1761
1829
  if (!manifest) {
1762
1830
  console.error("\u274C manifest.json not found in bundle");
@@ -1872,7 +1940,7 @@ Examples:
1872
1940
  };
1873
1941
  if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
1874
1942
  if (options.manifest) {
1875
- const manifestPath = path5.resolve(options.manifest);
1943
+ const manifestPath = path6.resolve(options.manifest);
1876
1944
  if (!fs7.existsSync(manifestPath)) {
1877
1945
  console.error(`\u274C Manifest file not found: ${options.manifest}`);
1878
1946
  process.exit(1);
@@ -1964,7 +2032,7 @@ Examples:
1964
2032
  if (!manifest.links) manifest.links = {};
1965
2033
  manifest.links.docs = options.docs;
1966
2034
  }
1967
- const outputPath = path5.resolve(options.output || "manifest.json");
2035
+ const outputPath = path6.resolve(options.output || "manifest.json");
1968
2036
  fs7.writeFileSync(outputPath, JSON.stringify(manifest, null, 2));
1969
2037
  console.log(`\u2705 Wrote modified manifest to: ${outputPath}`);
1970
2038
  console.log("");
@@ -2140,7 +2208,7 @@ async function extractManifest(bundlePath) {
2140
2208
  if (entry.path === "manifest.json") ;
2141
2209
  }
2142
2210
  });
2143
- const extractDir = path5.join(path5.dirname(bundlePath), `.temp-${Date.now()}`);
2211
+ const extractDir = path6.join(path6.dirname(bundlePath), `.temp-${Date.now()}`);
2144
2212
  if (!fs7.existsSync(extractDir)) {
2145
2213
  fs7.mkdirSync(extractDir);
2146
2214
  }
@@ -2148,9 +2216,9 @@ async function extractManifest(bundlePath) {
2148
2216
  await tar.x({
2149
2217
  file: bundlePath,
2150
2218
  cwd: extractDir,
2151
- filter: (path6) => path6 === "manifest.json"
2219
+ filter: (path7) => path7 === "manifest.json"
2152
2220
  });
2153
- const manifestPath = path5.join(extractDir, "manifest.json");
2221
+ const manifestPath = path6.join(extractDir, "manifest.json");
2154
2222
  if (fs7.existsSync(manifestPath)) {
2155
2223
  const content = fs7.readFileSync(manifestPath, "utf8");
2156
2224
  manifestContent = content;