@calimero-network/registry-cli 1.22.2 → 1.22.4

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
 
@@ -16,11 +15,11 @@ var DEFAULT_REGISTRY_URL = "https://apps.calimero.network";
16
15
  function defaultConfig() {
17
16
  return { registry: { url: DEFAULT_REGISTRY_URL } };
18
17
  }
19
- var RemoteConfig = class {
18
+ var RemoteConfig = class _RemoteConfig {
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
  }
@@ -58,7 +57,13 @@ var RemoteConfig = class {
58
57
  ...this.config.registry.apiKey ? { apiKey: this.config.registry.apiKey } : {}
59
58
  }
60
59
  };
61
- fs7.writeFileSync(this.configPath, JSON.stringify(configToSave, null, 2));
60
+ fs7.writeFileSync(this.configPath, JSON.stringify(configToSave, null, 2), {
61
+ mode: 384
62
+ });
63
+ try {
64
+ fs7.chmodSync(this.configPath, 384);
65
+ } catch {
66
+ }
62
67
  }
63
68
  /**
64
69
  * Get registry URL with priority:
@@ -73,9 +78,30 @@ var RemoteConfig = class {
73
78
  * Set registry URL
74
79
  */
75
80
  setRegistryUrl(url) {
81
+ if (_RemoteConfig.isInsecureRemoteUrl(url)) {
82
+ console.warn(
83
+ "\u26A0\uFE0F Registry URL uses http:// on a non-local host. Your API key would be sent in cleartext \u2014 prefer https:// for remote registries."
84
+ );
85
+ }
76
86
  this.config.registry.url = url;
77
87
  this.saveConfig();
78
88
  }
89
+ /**
90
+ * True when `url` is http:// to a host other than localhost/loopback, i.e. a
91
+ * Bearer token would traverse the network in cleartext.
92
+ */
93
+ static isInsecureRemoteUrl(url) {
94
+ let parsed;
95
+ try {
96
+ parsed = new URL(url);
97
+ } catch {
98
+ return false;
99
+ }
100
+ if (parsed.protocol !== "http:") return false;
101
+ const host = parsed.hostname.toLowerCase();
102
+ const isLocal = host === "localhost" || host === "127.0.0.1" || host === "::1" || host.endsWith(".localhost");
103
+ return !isLocal;
104
+ }
79
105
  /**
80
106
  * Get API key with priority:
81
107
  * 1. Environment variable CALIMERO_API_KEY
@@ -128,20 +154,20 @@ var RemoteConfig = class {
128
154
  function defaultConfig2() {
129
155
  return {
130
156
  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",
157
+ // Hardening: default to loopback so the dev server is not reachable from
158
+ // the LAN or a browsing website. Docker users who need container access
159
+ // opt in explicitly with `local start --host 0.0.0.0`; publicHost stays
160
+ // host.docker.internal for the URLs baked into manifests in that case.
161
+ host: "127.0.0.1",
136
162
  port: 8082,
137
163
  publicHost: "host.docker.internal"
138
164
  },
139
165
  data: {
140
- dir: path5.join(os2.homedir(), ".calimero-registry", "data"),
141
- artifactsDir: path5.join(os2.homedir(), ".calimero-registry", "artifacts")
166
+ dir: path6.join(os2.homedir(), ".calimero-registry", "data"),
167
+ artifactsDir: path6.join(os2.homedir(), ".calimero-registry", "artifacts")
142
168
  },
143
169
  artifacts: {
144
- storageDir: path5.join(os2.homedir(), ".calimero-registry", "artifacts"),
170
+ storageDir: path6.join(os2.homedir(), ".calimero-registry", "artifacts"),
145
171
  serveLocal: true,
146
172
  copyArtifacts: true,
147
173
  maxFileSize: "100MB",
@@ -154,12 +180,12 @@ var LocalConfig = class {
154
180
  dataDir;
155
181
  config;
156
182
  constructor() {
157
- this.configPath = path5.join(
183
+ this.configPath = path6.join(
158
184
  os2.homedir(),
159
185
  ".calimero-registry",
160
186
  "config.json"
161
187
  );
162
- this.dataDir = path5.join(os2.homedir(), ".calimero-registry");
188
+ this.dataDir = path6.join(os2.homedir(), ".calimero-registry");
163
189
  this.config = this.loadConfig();
164
190
  }
165
191
  loadConfig() {
@@ -190,7 +216,7 @@ var LocalConfig = class {
190
216
  return defaults;
191
217
  }
192
218
  saveConfig() {
193
- const configDir = path5.dirname(this.configPath);
219
+ const configDir = path6.dirname(this.configPath);
194
220
  if (!fs7.existsSync(configDir)) {
195
221
  fs7.mkdirSync(configDir, { recursive: true });
196
222
  }
@@ -224,8 +250,8 @@ var LocalConfig = class {
224
250
  }
225
251
  setDataDir(dir) {
226
252
  this.config.data.dir = dir;
227
- this.config.data.artifactsDir = path5.join(dir, "artifacts");
228
- this.config.artifacts.storageDir = path5.join(dir, "artifacts");
253
+ this.config.data.artifactsDir = path6.join(dir, "artifacts");
254
+ this.config.artifacts.storageDir = path6.join(dir, "artifacts");
229
255
  this.saveConfig();
230
256
  }
231
257
  getArtifactsDir() {
@@ -249,8 +275,8 @@ var LocalConfig = class {
249
275
  const dirs = [
250
276
  this.getDataDir(),
251
277
  this.getArtifactsDir(),
252
- path5.join(this.getDataDir(), "backups"),
253
- path5.join(this.getDataDir(), "logs")
278
+ path6.join(this.getDataDir(), "backups"),
279
+ path6.join(this.getDataDir(), "logs")
254
280
  ];
255
281
  dirs.forEach((dir) => {
256
282
  if (!fs7.existsSync(dir)) {
@@ -390,12 +416,12 @@ var LocalDataStore = class {
390
416
  artifactsFile;
391
417
  constructor(config) {
392
418
  this.config = config;
393
- this.appsFile = path5.join(config.getDataDir(), "apps.json");
394
- this.bundleManifestsFile = path5.join(
419
+ this.appsFile = path6.join(config.getDataDir(), "apps.json");
420
+ this.bundleManifestsFile = path6.join(
395
421
  config.getDataDir(),
396
422
  "bundle_manifests.json"
397
423
  );
398
- this.artifactsFile = path5.join(config.getDataDir(), "artifacts.json");
424
+ this.artifactsFile = path6.join(config.getDataDir(), "artifacts.json");
399
425
  this.data = {
400
426
  apps: /* @__PURE__ */ new Map(),
401
427
  bundleManifests: /* @__PURE__ */ new Map(),
@@ -516,12 +542,12 @@ var LocalDataStore = class {
516
542
  // Backup and restore
517
543
  async backup(outputPath) {
518
544
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
519
- const backupPath = outputPath || path5.join(
545
+ const backupPath = outputPath || path6.join(
520
546
  this.config.getDataDir(),
521
547
  "backups",
522
548
  `backup-${timestamp}.json`
523
549
  );
524
- const backupDir = path5.dirname(backupPath);
550
+ const backupDir = path6.dirname(backupPath);
525
551
  if (!fs7.existsSync(backupDir)) {
526
552
  fs7.mkdirSync(backupDir, { recursive: true });
527
553
  }
@@ -613,16 +639,30 @@ var LocalArtifactServer = class {
613
639
  fs7.mkdirSync(this.artifactsDir, { recursive: true });
614
640
  }
615
641
  }
642
+ /**
643
+ * Hardening: build a path under artifactsDir from untrusted segments (request
644
+ * params, or bundle-provided package/version/filename) and guarantee it stays
645
+ * inside artifactsDir. A `..` or absolute segment would otherwise let a
646
+ * request read or write outside the artifact store (path traversal).
647
+ */
648
+ resolveArtifactPath(...segments) {
649
+ const base = path6.resolve(this.artifactsDir);
650
+ const resolved = path6.resolve(base, ...segments);
651
+ if (resolved !== base && !resolved.startsWith(base + path6.sep)) {
652
+ throw new Error("Invalid artifact path: escapes artifacts directory");
653
+ }
654
+ return resolved;
655
+ }
616
656
  // Copy artifact to local storage
617
657
  async copyArtifactToLocal(sourcePath, appId, version2, filename) {
618
658
  if (!fs7.existsSync(sourcePath)) {
619
659
  throw new Error(`Source file not found: ${sourcePath}`);
620
660
  }
621
- const appVersionDir = path5.join(this.artifactsDir, appId, version2);
661
+ const targetPath = this.resolveArtifactPath(appId, version2, filename);
662
+ const appVersionDir = path6.dirname(targetPath);
622
663
  if (!fs7.existsSync(appVersionDir)) {
623
664
  fs7.mkdirSync(appVersionDir, { recursive: true });
624
665
  }
625
- const targetPath = path5.join(appVersionDir, filename);
626
666
  fs7.copyFileSync(sourcePath, targetPath);
627
667
  const fileHash = await this.calculateFileHash(targetPath);
628
668
  this.dataStore.setArtifactPath(fileHash, targetPath);
@@ -630,7 +670,7 @@ var LocalArtifactServer = class {
630
670
  }
631
671
  // Serve artifact by app ID, version, and filename
632
672
  async serveArtifact(appId, version2, filename) {
633
- const artifactPath = path5.join(this.artifactsDir, appId, version2, filename);
673
+ const artifactPath = this.resolveArtifactPath(appId, version2, filename);
634
674
  if (!fs7.existsSync(artifactPath)) {
635
675
  throw new Error(`Artifact not found: ${artifactPath}`);
636
676
  }
@@ -679,7 +719,7 @@ var LocalArtifactServer = class {
679
719
  let files = [];
680
720
  const items = fs7.readdirSync(dir);
681
721
  for (const item of items) {
682
- const fullPath = path5.join(dir, item);
722
+ const fullPath = path6.join(dir, item);
683
723
  const stat = fs7.statSync(fullPath);
684
724
  if (stat.isDirectory()) {
685
725
  files = files.concat(getAllFiles(fullPath));
@@ -708,7 +748,7 @@ var LocalArtifactServer = class {
708
748
  let files = [];
709
749
  const items = fs7.readdirSync(dir);
710
750
  for (const item of items) {
711
- const fullPath = path5.join(dir, item);
751
+ const fullPath = path6.join(dir, item);
712
752
  const stat = fs7.statSync(fullPath);
713
753
  if (stat.isDirectory()) {
714
754
  files = files.concat(getAllFiles(fullPath));
@@ -759,9 +799,27 @@ var LocalRegistryServer = class {
759
799
  level: "info"
760
800
  }
761
801
  });
762
- await this.server.register(cors, {
763
- origin: true,
764
- credentials: true
802
+ const allowedHosts = /* @__PURE__ */ new Set();
803
+ for (const name of [
804
+ "localhost",
805
+ "127.0.0.1",
806
+ "[::1]",
807
+ this.config.getPublicHost(),
808
+ host === "0.0.0.0" || host === "::" ? "" : host
809
+ ]) {
810
+ if (!name) continue;
811
+ allowedHosts.add(name);
812
+ allowedHosts.add(`${name}:${serverPort}`);
813
+ }
814
+ this.server.addHook("onRequest", async (request, reply) => {
815
+ const hostHeader = (request.headers.host ?? "").toLowerCase();
816
+ if (!allowedHosts.has(hostHeader)) {
817
+ return reply.code(403).send({
818
+ statusCode: 403,
819
+ error: "Forbidden",
820
+ message: "Invalid Host header"
821
+ });
822
+ }
765
823
  });
766
824
  await this.registerRoutes();
767
825
  await this.server.listen({ port: serverPort, host });
@@ -805,6 +863,20 @@ var LocalRegistryServer = class {
805
863
  async seed() {
806
864
  await this.dataStore.seed();
807
865
  }
866
+ /**
867
+ * Hardening: resolve a caller-supplied backup path relative to the CLI data
868
+ * dir and verify it stays inside it. Rejects absolute paths and `..` segments
869
+ * that would escape, so the HTTP backup/restore routes cannot read or write
870
+ * arbitrary filesystem locations.
871
+ */
872
+ confineToDataDir(candidate) {
873
+ const dataDir = path6.resolve(this.config.getDataDir());
874
+ const resolved = path6.resolve(dataDir, candidate);
875
+ if (resolved !== dataDir && !resolved.startsWith(dataDir + path6.sep)) {
876
+ throw new Error("Path escapes data directory");
877
+ }
878
+ return resolved;
879
+ }
808
880
  async registerRoutes() {
809
881
  if (!this.server) {
810
882
  throw new Error("Server not initialized");
@@ -868,14 +940,37 @@ var LocalRegistryServer = class {
868
940
  await this.reset();
869
941
  return { message: "Local registry data reset successfully" };
870
942
  });
871
- this.server.get("/local/backup", async (request) => {
943
+ this.server.post("/local/backup", async (request, reply) => {
872
944
  const query = request.query;
873
- const backupPath = await this.backup(query.output);
945
+ let output;
946
+ if (query.output) {
947
+ try {
948
+ output = this.confineToDataDir(query.output);
949
+ } catch {
950
+ return reply.code(400).send({
951
+ error: "invalid_path",
952
+ message: "output escapes data dir"
953
+ });
954
+ }
955
+ }
956
+ const backupPath = await this.backup(output);
874
957
  return { backupPath };
875
958
  });
876
- this.server.post("/local/restore", async (request) => {
877
- const { backupPath } = request.body;
878
- await this.restore(backupPath);
959
+ this.server.post("/local/restore", async (request, reply) => {
960
+ const { backupPath } = request.body ?? {};
961
+ if (!backupPath) {
962
+ return reply.code(400).send({ error: "invalid_path", message: "backupPath is required" });
963
+ }
964
+ let resolved;
965
+ try {
966
+ resolved = this.confineToDataDir(backupPath);
967
+ } catch {
968
+ return reply.code(400).send({
969
+ error: "invalid_path",
970
+ message: "backupPath escapes data dir"
971
+ });
972
+ }
973
+ await this.restore(resolved);
879
974
  return { message: "Data restored successfully" };
880
975
  });
881
976
  this.server.post("/local/seed", async () => {
@@ -948,7 +1043,7 @@ var localCommand = new Command("local").description(
948
1043
  "Manage local registry for development"
949
1044
  );
950
1045
  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(
1046
+ 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
1047
  "--public-host <host>",
953
1048
  "Public host exposed in manifest artifact URLs",
954
1049
  "host.docker.internal"
@@ -1315,7 +1410,7 @@ Note:
1315
1410
  try {
1316
1411
  let manifestConfig = {};
1317
1412
  if (options.manifest) {
1318
- const manifestPath = path5.resolve(options.manifest);
1413
+ const manifestPath = path6.resolve(options.manifest);
1319
1414
  if (!fs7.existsSync(manifestPath)) {
1320
1415
  console.error(`\u274C Manifest file not found: ${options.manifest}`);
1321
1416
  process.exit(1);
@@ -1392,12 +1487,12 @@ Note:
1392
1487
  );
1393
1488
  process.exit(1);
1394
1489
  }
1395
- const wasmPath = path5.resolve(wasmFile);
1490
+ const wasmPath = path6.resolve(wasmFile);
1396
1491
  if (!fs7.existsSync(wasmPath)) {
1397
1492
  console.error(`\u274C WASM file not found: ${wasmFile}`);
1398
1493
  process.exit(1);
1399
1494
  }
1400
- console.log(`\u{1F4E6} Creating MPK bundle from: ${path5.basename(wasmPath)}`);
1495
+ console.log(`\u{1F4E6} Creating MPK bundle from: ${path6.basename(wasmPath)}`);
1401
1496
  const wasmContent = fs7.readFileSync(wasmPath);
1402
1497
  const wasmSize = wasmContent.length;
1403
1498
  const wasmHash = crypto2.createHash("sha256").update(wasmContent).digest("hex");
@@ -1407,10 +1502,10 @@ Note:
1407
1502
  const abiPathFromManifest = typeof manifestConfig.abi === "string" ? manifestConfig.abi : null;
1408
1503
  const abiFilePath = abiPathFromOption || abiPathFromManifest;
1409
1504
  if (abiFilePath) {
1410
- const abiResolvedPath = abiPathFromOption ? path5.resolve(abiFilePath) : options.manifest && abiPathFromManifest ? path5.resolve(
1411
- path5.dirname(path5.resolve(options.manifest)),
1505
+ const abiResolvedPath = abiPathFromOption ? path6.resolve(abiFilePath) : options.manifest && abiPathFromManifest ? path6.resolve(
1506
+ path6.dirname(path6.resolve(options.manifest)),
1412
1507
  abiFilePath
1413
- ) : path5.resolve(abiFilePath);
1508
+ ) : path6.resolve(abiFilePath);
1414
1509
  if (!fs7.existsSync(abiResolvedPath)) {
1415
1510
  console.error(`\u274C ABI file not found: ${abiFilePath}`);
1416
1511
  console.error(` Resolved path: ${abiResolvedPath}`);
@@ -1426,7 +1521,7 @@ Note:
1426
1521
  size: abiContent.length
1427
1522
  };
1428
1523
  console.log(
1429
- ` Including ABI file: ${path5.basename(abiResolvedPath)}`
1524
+ ` Including ABI file: ${path6.basename(abiResolvedPath)}`
1430
1525
  );
1431
1526
  } catch (error) {
1432
1527
  console.error(
@@ -1450,7 +1545,7 @@ Note:
1450
1545
  const manifestServices = Array.isArray(
1451
1546
  manifestConfig.services
1452
1547
  ) ? manifestConfig.services : [];
1453
- const manifestDir = options.manifest ? path5.dirname(path5.resolve(options.manifest)) : process.cwd();
1548
+ const manifestDir = options.manifest ? path6.dirname(path6.resolve(options.manifest)) : process.cwd();
1454
1549
  const allServiceSources = [
1455
1550
  ...cliServices.map((src) => ({ src, baseDir: process.cwd() })),
1456
1551
  ...manifestServices.map((src) => ({ src, baseDir: manifestDir }))
@@ -1484,7 +1579,7 @@ Note:
1484
1579
  );
1485
1580
  process.exit(1);
1486
1581
  }
1487
- const svcWasmPath = path5.resolve(baseDir, src.wasm);
1582
+ const svcWasmPath = path6.resolve(baseDir, src.wasm);
1488
1583
  if (!fs7.existsSync(svcWasmPath)) {
1489
1584
  console.error(
1490
1585
  `\u274C Service "${src.name}" WASM not found: ${src.wasm}`
@@ -1508,7 +1603,7 @@ Note:
1508
1603
  content: svcWasmContent
1509
1604
  });
1510
1605
  if (src.abi) {
1511
- const svcAbiPath = path5.resolve(baseDir, src.abi);
1606
+ const svcAbiPath = path6.resolve(baseDir, src.abi);
1512
1607
  if (!fs7.existsSync(svcAbiPath)) {
1513
1608
  console.error(
1514
1609
  `\u274C Service "${src.name}" ABI not found: ${src.abi}`
@@ -1542,7 +1637,7 @@ Note:
1542
1637
  }
1543
1638
  serviceArtifacts.push(entry);
1544
1639
  console.log(
1545
- ` Including service: ${src.name} (${path5.basename(svcWasmPath)})`
1640
+ ` Including service: ${src.name} (${path6.basename(svcWasmPath)})`
1546
1641
  );
1547
1642
  }
1548
1643
  const metadata = {
@@ -1575,29 +1670,29 @@ Note:
1575
1670
  links: Object.keys(links).length > 0 ? links : void 0,
1576
1671
  signature: void 0
1577
1672
  };
1578
- let outputDir = finalOutput ? path5.resolve(finalOutput) : path5.join(process.cwd(), finalPackage, finalVersion);
1673
+ let outputDir = finalOutput ? path6.resolve(finalOutput) : path6.join(process.cwd(), finalPackage, finalVersion);
1579
1674
  if (!fs7.existsSync(outputDir)) {
1580
1675
  fs7.mkdirSync(outputDir, { recursive: true });
1581
1676
  }
1582
1677
  fs7.writeFileSync(
1583
- path5.join(outputDir, "manifest.json"),
1678
+ path6.join(outputDir, "manifest.json"),
1584
1679
  JSON.stringify(manifest, null, 2)
1585
1680
  );
1586
- fs7.writeFileSync(path5.join(outputDir, "app.wasm"), wasmContent);
1681
+ fs7.writeFileSync(path6.join(outputDir, "app.wasm"), wasmContent);
1587
1682
  if (abiContent) {
1588
- fs7.writeFileSync(path5.join(outputDir, "abi.json"), abiContent);
1683
+ fs7.writeFileSync(path6.join(outputDir, "abi.json"), abiContent);
1589
1684
  }
1590
- const servicesDir = path5.join(outputDir, "services");
1685
+ const servicesDir = path6.join(outputDir, "services");
1591
1686
  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)) {
1687
+ const dest = path6.join(outputDir, relPath);
1688
+ const rel = path6.relative(servicesDir, dest);
1689
+ if (rel.startsWith("..") || path6.isAbsolute(rel)) {
1595
1690
  console.error(
1596
1691
  `\u274C Refusing to write service file outside services/: ${relPath}`
1597
1692
  );
1598
1693
  process.exit(1);
1599
1694
  }
1600
- fs7.mkdirSync(path5.dirname(dest), { recursive: true });
1695
+ fs7.mkdirSync(path6.dirname(dest), { recursive: true });
1601
1696
  fs7.writeFileSync(dest, content);
1602
1697
  }
1603
1698
  console.log(`\u2705 Bundle files written to: ${outputDir}`);
@@ -1615,7 +1710,7 @@ Note:
1615
1710
  console.log("");
1616
1711
  console.log("Next steps:");
1617
1712
  console.log(
1618
- ` 1. Sign the manifest: mero-sign sign ${path5.join(outputDir, "manifest.json")} --key key.json`
1713
+ ` 1. Sign the manifest: mero-sign sign ${path6.join(outputDir, "manifest.json")} --key key.json`
1619
1714
  );
1620
1715
  console.log(
1621
1716
  ` 2. Push the bundle: calimero-registry bundle push ${outputDir} --remote`
@@ -1684,15 +1779,15 @@ Note:
1684
1779
  );
1685
1780
  process.exit(1);
1686
1781
  }
1687
- const fullPath = path5.resolve(bundleFile);
1782
+ const fullPath = path6.resolve(bundleFile);
1688
1783
  if (!fs7.existsSync(fullPath)) {
1689
1784
  console.error(`\u274C File not found: ${bundleFile}`);
1690
1785
  process.exit(1);
1691
1786
  }
1692
1787
  mpkPath = fullPath;
1693
1788
  if (fs7.statSync(fullPath).isDirectory()) {
1694
- const manifestInDir = path5.join(fullPath, "manifest.json");
1695
- const wasmInDir = path5.join(fullPath, "app.wasm");
1789
+ const manifestInDir = path6.join(fullPath, "manifest.json");
1790
+ const wasmInDir = path6.join(fullPath, "app.wasm");
1696
1791
  if (!fs7.existsSync(manifestInDir)) {
1697
1792
  console.error(
1698
1793
  `\u274C manifest.json not found in directory: ${fullPath}`
@@ -1703,7 +1798,7 @@ Note:
1703
1798
  console.error(`\u274C app.wasm not found in directory: ${fullPath}`);
1704
1799
  process.exit(1);
1705
1800
  }
1706
- tempMpk = path5.join(fullPath, `.temp-push-${Date.now()}.mpk`);
1801
+ tempMpk = path6.join(fullPath, `.temp-push-${Date.now()}.mpk`);
1707
1802
  let dirManifest;
1708
1803
  try {
1709
1804
  dirManifest = JSON.parse(
@@ -1740,7 +1835,7 @@ Note:
1740
1835
  process.exit(1);
1741
1836
  }
1742
1837
  for (const f of archiveFiles) {
1743
- if (!fs7.existsSync(path5.join(fullPath, f))) {
1838
+ if (!fs7.existsSync(path6.join(fullPath, f))) {
1744
1839
  console.error(
1745
1840
  `\u274C Bundle file referenced by manifest not found: ${f}`
1746
1841
  );
@@ -1756,7 +1851,7 @@ Note:
1756
1851
  `\u{1F4E6} Packed directory into temporary bundle (${archiveFiles.length} files)`
1757
1852
  );
1758
1853
  }
1759
- console.log(`\u{1F4E6} Processing bundle: ${path5.basename(mpkPath)}`);
1854
+ console.log(`\u{1F4E6} Processing bundle: ${path6.basename(mpkPath)}`);
1760
1855
  const manifest = await extractManifest(mpkPath);
1761
1856
  if (!manifest) {
1762
1857
  console.error("\u274C manifest.json not found in bundle");
@@ -1872,7 +1967,7 @@ Examples:
1872
1967
  };
1873
1968
  if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
1874
1969
  if (options.manifest) {
1875
- const manifestPath = path5.resolve(options.manifest);
1970
+ const manifestPath = path6.resolve(options.manifest);
1876
1971
  if (!fs7.existsSync(manifestPath)) {
1877
1972
  console.error(`\u274C Manifest file not found: ${options.manifest}`);
1878
1973
  process.exit(1);
@@ -1964,7 +2059,7 @@ Examples:
1964
2059
  if (!manifest.links) manifest.links = {};
1965
2060
  manifest.links.docs = options.docs;
1966
2061
  }
1967
- const outputPath = path5.resolve(options.output || "manifest.json");
2062
+ const outputPath = path6.resolve(options.output || "manifest.json");
1968
2063
  fs7.writeFileSync(outputPath, JSON.stringify(manifest, null, 2));
1969
2064
  console.log(`\u2705 Wrote modified manifest to: ${outputPath}`);
1970
2065
  console.log("");
@@ -2140,7 +2235,7 @@ async function extractManifest(bundlePath) {
2140
2235
  if (entry.path === "manifest.json") ;
2141
2236
  }
2142
2237
  });
2143
- const extractDir = path5.join(path5.dirname(bundlePath), `.temp-${Date.now()}`);
2238
+ const extractDir = path6.join(path6.dirname(bundlePath), `.temp-${Date.now()}`);
2144
2239
  if (!fs7.existsSync(extractDir)) {
2145
2240
  fs7.mkdirSync(extractDir);
2146
2241
  }
@@ -2148,9 +2243,9 @@ async function extractManifest(bundlePath) {
2148
2243
  await tar.x({
2149
2244
  file: bundlePath,
2150
2245
  cwd: extractDir,
2151
- filter: (path6) => path6 === "manifest.json"
2246
+ filter: (path7) => path7 === "manifest.json"
2152
2247
  });
2153
- const manifestPath = path5.join(extractDir, "manifest.json");
2248
+ const manifestPath = path6.join(extractDir, "manifest.json");
2154
2249
  if (fs7.existsSync(manifestPath)) {
2155
2250
  const content = fs7.readFileSync(manifestPath, "utf8");
2156
2251
  manifestContent = content;