@calimero-network/registry-cli 1.24.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,8 +4,8 @@ import chalk4 from 'chalk';
4
4
  import { createRequire } from 'module';
5
5
  import ora4 from 'ora';
6
6
  import axios from 'axios';
7
- import fs7, { existsSync, writeFileSync } from 'fs';
8
- import path6 from 'path';
7
+ import fs8, { existsSync, writeFileSync } from 'fs';
8
+ import path7 from 'path';
9
9
  import os2 from 'os';
10
10
  import fastify from 'fastify';
11
11
  import crypto2 from 'crypto';
@@ -19,7 +19,7 @@ var RemoteConfig = class _RemoteConfig {
19
19
  configPath;
20
20
  config;
21
21
  constructor() {
22
- this.configPath = path6.join(
22
+ this.configPath = path7.join(
23
23
  os2.homedir(),
24
24
  ".calimero-registry",
25
25
  "remote-config.json"
@@ -28,10 +28,10 @@ var RemoteConfig = class _RemoteConfig {
28
28
  }
29
29
  loadConfig() {
30
30
  const defaults = defaultConfig();
31
- if (fs7.existsSync(this.configPath)) {
31
+ if (fs8.existsSync(this.configPath)) {
32
32
  try {
33
33
  const existingConfig = JSON.parse(
34
- fs7.readFileSync(this.configPath, "utf8")
34
+ fs8.readFileSync(this.configPath, "utf8")
35
35
  );
36
36
  return {
37
37
  registry: {
@@ -46,9 +46,9 @@ var RemoteConfig = class _RemoteConfig {
46
46
  return defaults;
47
47
  }
48
48
  saveConfig() {
49
- const configDir = path6.dirname(this.configPath);
50
- if (!fs7.existsSync(configDir)) {
51
- fs7.mkdirSync(configDir, { recursive: true });
49
+ const configDir = path7.dirname(this.configPath);
50
+ if (!fs8.existsSync(configDir)) {
51
+ fs8.mkdirSync(configDir, { recursive: true });
52
52
  }
53
53
  const configToSave = {
54
54
  registry: {
@@ -57,11 +57,11 @@ var RemoteConfig = class _RemoteConfig {
57
57
  ...this.config.registry.apiKey ? { apiKey: this.config.registry.apiKey } : {}
58
58
  }
59
59
  };
60
- fs7.writeFileSync(this.configPath, JSON.stringify(configToSave, null, 2), {
60
+ fs8.writeFileSync(this.configPath, JSON.stringify(configToSave, null, 2), {
61
61
  mode: 384
62
62
  });
63
63
  try {
64
- fs7.chmodSync(this.configPath, 384);
64
+ fs8.chmodSync(this.configPath, 384);
65
65
  } catch {
66
66
  }
67
67
  }
@@ -177,11 +177,11 @@ function defaultConfig2() {
177
177
  publicHost: "host.docker.internal"
178
178
  },
179
179
  data: {
180
- dir: path6.join(os2.homedir(), ".calimero-registry", "data"),
181
- artifactsDir: path6.join(os2.homedir(), ".calimero-registry", "artifacts")
180
+ dir: path7.join(os2.homedir(), ".calimero-registry", "data"),
181
+ artifactsDir: path7.join(os2.homedir(), ".calimero-registry", "artifacts")
182
182
  },
183
183
  artifacts: {
184
- storageDir: path6.join(os2.homedir(), ".calimero-registry", "artifacts"),
184
+ storageDir: path7.join(os2.homedir(), ".calimero-registry", "artifacts"),
185
185
  serveLocal: true,
186
186
  copyArtifacts: true,
187
187
  maxFileSize: "100MB",
@@ -194,20 +194,20 @@ var LocalConfig = class {
194
194
  dataDir;
195
195
  config;
196
196
  constructor() {
197
- this.configPath = path6.join(
197
+ this.configPath = path7.join(
198
198
  os2.homedir(),
199
199
  ".calimero-registry",
200
200
  "config.json"
201
201
  );
202
- this.dataDir = path6.join(os2.homedir(), ".calimero-registry");
202
+ this.dataDir = path7.join(os2.homedir(), ".calimero-registry");
203
203
  this.config = this.loadConfig();
204
204
  }
205
205
  loadConfig() {
206
206
  const defaults = defaultConfig2();
207
- if (fs7.existsSync(this.configPath)) {
207
+ if (fs8.existsSync(this.configPath)) {
208
208
  try {
209
209
  const existingConfig = JSON.parse(
210
- fs7.readFileSync(this.configPath, "utf8")
210
+ fs8.readFileSync(this.configPath, "utf8")
211
211
  );
212
212
  return {
213
213
  server: {
@@ -230,11 +230,11 @@ var LocalConfig = class {
230
230
  return defaults;
231
231
  }
232
232
  saveConfig() {
233
- const configDir = path6.dirname(this.configPath);
234
- if (!fs7.existsSync(configDir)) {
235
- fs7.mkdirSync(configDir, { recursive: true });
233
+ const configDir = path7.dirname(this.configPath);
234
+ if (!fs8.existsSync(configDir)) {
235
+ fs8.mkdirSync(configDir, { recursive: true });
236
236
  }
237
- fs7.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));
237
+ fs8.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));
238
238
  }
239
239
  // Server configuration
240
240
  getPort() {
@@ -264,8 +264,8 @@ var LocalConfig = class {
264
264
  }
265
265
  setDataDir(dir) {
266
266
  this.config.data.dir = dir;
267
- this.config.data.artifactsDir = path6.join(dir, "artifacts");
268
- this.config.artifacts.storageDir = path6.join(dir, "artifacts");
267
+ this.config.data.artifactsDir = path7.join(dir, "artifacts");
268
+ this.config.artifacts.storageDir = path7.join(dir, "artifacts");
269
269
  this.saveConfig();
270
270
  }
271
271
  getArtifactsDir() {
@@ -289,12 +289,12 @@ var LocalConfig = class {
289
289
  const dirs = [
290
290
  this.getDataDir(),
291
291
  this.getArtifactsDir(),
292
- path6.join(this.getDataDir(), "backups"),
293
- path6.join(this.getDataDir(), "logs")
292
+ path7.join(this.getDataDir(), "backups"),
293
+ path7.join(this.getDataDir(), "logs")
294
294
  ];
295
295
  dirs.forEach((dir) => {
296
- if (!fs7.existsSync(dir)) {
297
- fs7.mkdirSync(dir, { recursive: true });
296
+ if (!fs8.existsSync(dir)) {
297
+ fs8.mkdirSync(dir, { recursive: true });
298
298
  }
299
299
  });
300
300
  }
@@ -430,12 +430,12 @@ var LocalDataStore = class {
430
430
  artifactsFile;
431
431
  constructor(config) {
432
432
  this.config = config;
433
- this.appsFile = path6.join(config.getDataDir(), "apps.json");
434
- this.bundleManifestsFile = path6.join(
433
+ this.appsFile = path7.join(config.getDataDir(), "apps.json");
434
+ this.bundleManifestsFile = path7.join(
435
435
  config.getDataDir(),
436
436
  "bundle_manifests.json"
437
437
  );
438
- this.artifactsFile = path6.join(config.getDataDir(), "artifacts.json");
438
+ this.artifactsFile = path7.join(config.getDataDir(), "artifacts.json");
439
439
  this.data = {
440
440
  apps: /* @__PURE__ */ new Map(),
441
441
  bundleManifests: /* @__PURE__ */ new Map(),
@@ -445,21 +445,21 @@ var LocalDataStore = class {
445
445
  }
446
446
  loadData() {
447
447
  try {
448
- if (fs7.existsSync(this.appsFile)) {
449
- const appsData = JSON.parse(fs7.readFileSync(this.appsFile, "utf8"));
448
+ if (fs8.existsSync(this.appsFile)) {
449
+ const appsData = JSON.parse(fs8.readFileSync(this.appsFile, "utf8"));
450
450
  this.data.apps = new Map(Object.entries(appsData));
451
451
  }
452
- if (fs7.existsSync(this.bundleManifestsFile)) {
452
+ if (fs8.existsSync(this.bundleManifestsFile)) {
453
453
  const bundleManifestsData = JSON.parse(
454
- fs7.readFileSync(this.bundleManifestsFile, "utf8")
454
+ fs8.readFileSync(this.bundleManifestsFile, "utf8")
455
455
  );
456
456
  this.data.bundleManifests = new Map(
457
457
  Object.entries(bundleManifestsData)
458
458
  );
459
459
  }
460
- if (fs7.existsSync(this.artifactsFile)) {
460
+ if (fs8.existsSync(this.artifactsFile)) {
461
461
  const artifactsData = JSON.parse(
462
- fs7.readFileSync(this.artifactsFile, "utf8")
462
+ fs8.readFileSync(this.artifactsFile, "utf8")
463
463
  );
464
464
  this.data.artifacts = new Map(Object.entries(artifactsData));
465
465
  }
@@ -471,14 +471,14 @@ var LocalDataStore = class {
471
471
  try {
472
472
  this.config.ensureDirectories();
473
473
  const appsObj = Object.fromEntries(this.data.apps);
474
- fs7.writeFileSync(this.appsFile, JSON.stringify(appsObj, null, 2));
474
+ fs8.writeFileSync(this.appsFile, JSON.stringify(appsObj, null, 2));
475
475
  const bundleManifestsObj = Object.fromEntries(this.data.bundleManifests);
476
- fs7.writeFileSync(
476
+ fs8.writeFileSync(
477
477
  this.bundleManifestsFile,
478
478
  JSON.stringify(bundleManifestsObj, null, 2)
479
479
  );
480
480
  const artifactsObj = Object.fromEntries(this.data.artifacts);
481
- fs7.writeFileSync(
481
+ fs8.writeFileSync(
482
482
  this.artifactsFile,
483
483
  JSON.stringify(artifactsObj, null, 2)
484
484
  );
@@ -556,14 +556,14 @@ var LocalDataStore = class {
556
556
  // Backup and restore
557
557
  async backup(outputPath) {
558
558
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
559
- const backupPath = outputPath || path6.join(
559
+ const backupPath = outputPath || path7.join(
560
560
  this.config.getDataDir(),
561
561
  "backups",
562
562
  `backup-${timestamp}.json`
563
563
  );
564
- const backupDir = path6.dirname(backupPath);
565
- if (!fs7.existsSync(backupDir)) {
566
- fs7.mkdirSync(backupDir, { recursive: true });
564
+ const backupDir = path7.dirname(backupPath);
565
+ if (!fs8.existsSync(backupDir)) {
566
+ fs8.mkdirSync(backupDir, { recursive: true });
567
567
  }
568
568
  const backupData = {
569
569
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -571,14 +571,14 @@ var LocalDataStore = class {
571
571
  bundleManifests: Object.fromEntries(this.data.bundleManifests),
572
572
  artifacts: Object.fromEntries(this.data.artifacts)
573
573
  };
574
- fs7.writeFileSync(backupPath, JSON.stringify(backupData, null, 2));
574
+ fs8.writeFileSync(backupPath, JSON.stringify(backupData, null, 2));
575
575
  return backupPath;
576
576
  }
577
577
  async restore(backupPath) {
578
- if (!fs7.existsSync(backupPath)) {
578
+ if (!fs8.existsSync(backupPath)) {
579
579
  throw new Error(`Backup file not found: ${backupPath}`);
580
580
  }
581
- const backupData = JSON.parse(fs7.readFileSync(backupPath, "utf8"));
581
+ const backupData = JSON.parse(fs8.readFileSync(backupPath, "utf8"));
582
582
  this.data.apps = new Map(Object.entries(backupData.apps || {}));
583
583
  this.data.bundleManifests = new Map(
584
584
  Object.entries(backupData.bundleManifests || {})
@@ -649,8 +649,8 @@ var LocalArtifactServer = class {
649
649
  this.ensureArtifactsDir();
650
650
  }
651
651
  ensureArtifactsDir() {
652
- if (!fs7.existsSync(this.artifactsDir)) {
653
- fs7.mkdirSync(this.artifactsDir, { recursive: true });
652
+ if (!fs8.existsSync(this.artifactsDir)) {
653
+ fs8.mkdirSync(this.artifactsDir, { recursive: true });
654
654
  }
655
655
  }
656
656
  /**
@@ -660,24 +660,24 @@ var LocalArtifactServer = class {
660
660
  * request read or write outside the artifact store (path traversal).
661
661
  */
662
662
  resolveArtifactPath(...segments) {
663
- const base = path6.resolve(this.artifactsDir);
664
- const resolved = path6.resolve(base, ...segments);
665
- if (resolved !== base && !resolved.startsWith(base + path6.sep)) {
663
+ const base = path7.resolve(this.artifactsDir);
664
+ const resolved = path7.resolve(base, ...segments);
665
+ if (resolved !== base && !resolved.startsWith(base + path7.sep)) {
666
666
  throw new Error("Invalid artifact path: escapes artifacts directory");
667
667
  }
668
668
  return resolved;
669
669
  }
670
670
  // Copy artifact to local storage
671
671
  async copyArtifactToLocal(sourcePath, appId, version2, filename) {
672
- if (!fs7.existsSync(sourcePath)) {
672
+ if (!fs8.existsSync(sourcePath)) {
673
673
  throw new Error(`Source file not found: ${sourcePath}`);
674
674
  }
675
675
  const targetPath = this.resolveArtifactPath(appId, version2, filename);
676
- const appVersionDir = path6.dirname(targetPath);
677
- if (!fs7.existsSync(appVersionDir)) {
678
- fs7.mkdirSync(appVersionDir, { recursive: true });
676
+ const appVersionDir = path7.dirname(targetPath);
677
+ if (!fs8.existsSync(appVersionDir)) {
678
+ fs8.mkdirSync(appVersionDir, { recursive: true });
679
679
  }
680
- fs7.copyFileSync(sourcePath, targetPath);
680
+ fs8.copyFileSync(sourcePath, targetPath);
681
681
  const fileHash = await this.calculateFileHash(targetPath);
682
682
  this.dataStore.setArtifactPath(fileHash, targetPath);
683
683
  return targetPath;
@@ -685,26 +685,26 @@ var LocalArtifactServer = class {
685
685
  // Serve artifact by app ID, version, and filename
686
686
  async serveArtifact(appId, version2, filename) {
687
687
  const artifactPath = this.resolveArtifactPath(appId, version2, filename);
688
- if (!fs7.existsSync(artifactPath)) {
688
+ if (!fs8.existsSync(artifactPath)) {
689
689
  throw new Error(`Artifact not found: ${artifactPath}`);
690
690
  }
691
- return fs7.readFileSync(artifactPath);
691
+ return fs8.readFileSync(artifactPath);
692
692
  }
693
693
  // Serve artifact by hash
694
694
  async serveByHash(hash) {
695
695
  const artifactPath = this.dataStore.getArtifactPath(hash);
696
- if (!artifactPath || !fs7.existsSync(artifactPath)) {
696
+ if (!artifactPath || !fs8.existsSync(artifactPath)) {
697
697
  throw new Error(`Artifact not found for hash: ${hash}`);
698
698
  }
699
- return fs7.readFileSync(artifactPath);
699
+ return fs8.readFileSync(artifactPath);
700
700
  }
701
701
  // Validate artifact file
702
702
  async validateArtifact(filePath) {
703
- if (!fs7.existsSync(filePath)) {
703
+ if (!fs8.existsSync(filePath)) {
704
704
  throw new Error(`File not found: ${filePath}`);
705
705
  }
706
- const stats = fs7.statSync(filePath);
707
- const fileBuffer = fs7.readFileSync(filePath);
706
+ const stats = fs8.statSync(filePath);
707
+ const fileBuffer = fs8.readFileSync(filePath);
708
708
  const sha256 = crypto2.createHash("sha256").update(fileBuffer).digest("hex");
709
709
  return {
710
710
  size: stats.size,
@@ -713,7 +713,7 @@ var LocalArtifactServer = class {
713
713
  }
714
714
  // Calculate file hash
715
715
  async calculateFileHash(filePath) {
716
- const fileBuffer = fs7.readFileSync(filePath);
716
+ const fileBuffer = fs8.readFileSync(filePath);
717
717
  return crypto2.createHash("sha256").update(fileBuffer).digest("hex");
718
718
  }
719
719
  // Get artifact URL for local serving
@@ -731,10 +731,10 @@ var LocalArtifactServer = class {
731
731
  const now = Date.now();
732
732
  const getAllFiles = (dir) => {
733
733
  let files = [];
734
- const items = fs7.readdirSync(dir);
734
+ const items = fs8.readdirSync(dir);
735
735
  for (const item of items) {
736
- const fullPath = path6.join(dir, item);
737
- const stat = fs7.statSync(fullPath);
736
+ const fullPath = path7.join(dir, item);
737
+ const stat = fs8.statSync(fullPath);
738
738
  if (stat.isDirectory()) {
739
739
  files = files.concat(getAllFiles(fullPath));
740
740
  } else {
@@ -745,10 +745,10 @@ var LocalArtifactServer = class {
745
745
  };
746
746
  const allFiles = getAllFiles(this.artifactsDir);
747
747
  for (const file of allFiles) {
748
- const stats = fs7.statSync(file);
748
+ const stats = fs8.statSync(file);
749
749
  const age = now - stats.mtime.getTime();
750
750
  if (age > maxAge) {
751
- fs7.unlinkSync(file);
751
+ fs8.unlinkSync(file);
752
752
  console.log(`Cleaned up old artifact: ${file}`);
753
753
  }
754
754
  }
@@ -760,10 +760,10 @@ var LocalArtifactServer = class {
760
760
  let oldestFile = null;
761
761
  const getAllFiles = (dir) => {
762
762
  let files = [];
763
- const items = fs7.readdirSync(dir);
763
+ const items = fs8.readdirSync(dir);
764
764
  for (const item of items) {
765
- const fullPath = path6.join(dir, item);
766
- const stat = fs7.statSync(fullPath);
765
+ const fullPath = path7.join(dir, item);
766
+ const stat = fs8.statSync(fullPath);
767
767
  if (stat.isDirectory()) {
768
768
  files = files.concat(getAllFiles(fullPath));
769
769
  } else {
@@ -772,10 +772,10 @@ var LocalArtifactServer = class {
772
772
  }
773
773
  return files;
774
774
  };
775
- if (fs7.existsSync(this.artifactsDir)) {
775
+ if (fs8.existsSync(this.artifactsDir)) {
776
776
  const allFiles = getAllFiles(this.artifactsDir);
777
777
  for (const file of allFiles) {
778
- const stats = fs7.statSync(file);
778
+ const stats = fs8.statSync(file);
779
779
  totalFiles++;
780
780
  totalSize += stats.size;
781
781
  if (!oldestFile || stats.mtime < oldestFile) {
@@ -913,8 +913,8 @@ var LocalRegistryServer = class {
913
913
  async reset() {
914
914
  this.dataStore.reset();
915
915
  const artifactsDir = this.config.getArtifactsDir();
916
- if (fs7.existsSync(artifactsDir)) {
917
- fs7.rmSync(artifactsDir, { recursive: true, force: true });
916
+ if (fs8.existsSync(artifactsDir)) {
917
+ fs8.rmSync(artifactsDir, { recursive: true, force: true });
918
918
  }
919
919
  }
920
920
  async backup(outputPath) {
@@ -933,9 +933,9 @@ var LocalRegistryServer = class {
933
933
  * arbitrary filesystem locations.
934
934
  */
935
935
  confineToDataDir(candidate) {
936
- const dataDir = path6.resolve(this.config.getDataDir());
937
- const resolved = path6.resolve(dataDir, candidate);
938
- if (resolved !== dataDir && !resolved.startsWith(dataDir + path6.sep)) {
936
+ const dataDir = path7.resolve(this.config.getDataDir());
937
+ const resolved = path7.resolve(dataDir, candidate);
938
+ if (resolved !== dataDir && !resolved.startsWith(dataDir + path7.sep)) {
939
939
  throw new Error("Path escapes data directory");
940
940
  }
941
941
  return resolved;
@@ -1254,7 +1254,7 @@ localCommand.addCommand(
1254
1254
  new Command("restore").description("Restore local registry data from backup").argument("<backup-file>", "Path to backup file").action(async (backupFile) => {
1255
1255
  const spinner2 = ora4("Restoring from backup...").start();
1256
1256
  try {
1257
- if (!fs7.existsSync(backupFile)) {
1257
+ if (!fs8.existsSync(backupFile)) {
1258
1258
  spinner2.fail("Backup file not found");
1259
1259
  console.error(chalk4.red(`File not found: ${backupFile}`));
1260
1260
  process.exit(1);
@@ -1298,8 +1298,6 @@ localCommand.addCommand(
1298
1298
  }
1299
1299
  })
1300
1300
  );
1301
-
1302
- // src/lib/services.ts
1303
1301
  var SERVICE_NAME_RE = /^[a-z0-9][a-z0-9_-]*$/;
1304
1302
  function validateServiceName(name) {
1305
1303
  if (typeof name !== "string" || !SERVICE_NAME_RE.test(name)) {
@@ -1403,6 +1401,18 @@ function collectBundleFiles(manifest) {
1403
1401
  files.forEach(assertSafeBundlePath);
1404
1402
  return [...new Set(files)];
1405
1403
  }
1404
+ function assertFilesInsideDir(dir, files) {
1405
+ const root = fs8.realpathSync(dir);
1406
+ for (const f of files) {
1407
+ const full = path7.join(dir, f);
1408
+ const inside = fs8.existsSync(full) && fs8.lstatSync(full).isFile() && fs8.realpathSync(full) === path7.join(root, f);
1409
+ if (!inside) {
1410
+ throw new Error(
1411
+ `Bundle file referenced by manifest is missing, not a regular file, or outside the bundle directory: ${f}`
1412
+ );
1413
+ }
1414
+ }
1415
+ }
1406
1416
 
1407
1417
  // src/commands/bundle.ts
1408
1418
  var bundleCommand = new Command("bundle").description("Manage application bundles (V2)").addCommand(createCreateCommand()).addCommand(createPushCommand()).addCommand(createGetCommand()).addCommand(createEditCommand());
@@ -1473,13 +1483,13 @@ Note:
1473
1483
  try {
1474
1484
  let manifestConfig = {};
1475
1485
  if (options.manifest) {
1476
- const manifestPath = path6.resolve(options.manifest);
1477
- if (!fs7.existsSync(manifestPath)) {
1486
+ const manifestPath = path7.resolve(options.manifest);
1487
+ if (!fs8.existsSync(manifestPath)) {
1478
1488
  console.error(`\u274C Manifest file not found: ${options.manifest}`);
1479
1489
  process.exit(1);
1480
1490
  }
1481
1491
  try {
1482
- const manifestContent = fs7.readFileSync(manifestPath, "utf8");
1492
+ const manifestContent = fs8.readFileSync(manifestPath, "utf8");
1483
1493
  const parsed = JSON.parse(manifestContent);
1484
1494
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
1485
1495
  console.error(`\u274C Invalid manifest file: ${options.manifest}`);
@@ -1550,13 +1560,13 @@ Note:
1550
1560
  );
1551
1561
  process.exit(1);
1552
1562
  }
1553
- const wasmPath = path6.resolve(wasmFile);
1554
- if (!fs7.existsSync(wasmPath)) {
1563
+ const wasmPath = path7.resolve(wasmFile);
1564
+ if (!fs8.existsSync(wasmPath)) {
1555
1565
  console.error(`\u274C WASM file not found: ${wasmFile}`);
1556
1566
  process.exit(1);
1557
1567
  }
1558
- console.log(`\u{1F4E6} Creating MPK bundle from: ${path6.basename(wasmPath)}`);
1559
- const wasmContent = fs7.readFileSync(wasmPath);
1568
+ console.log(`\u{1F4E6} Creating MPK bundle from: ${path7.basename(wasmPath)}`);
1569
+ const wasmContent = fs8.readFileSync(wasmPath);
1560
1570
  const wasmSize = wasmContent.length;
1561
1571
  const wasmHash = crypto2.createHash("sha256").update(wasmContent).digest("hex");
1562
1572
  let abiArtifact = void 0;
@@ -1565,17 +1575,17 @@ Note:
1565
1575
  const abiPathFromManifest = typeof manifestConfig.abi === "string" ? manifestConfig.abi : null;
1566
1576
  const abiFilePath = abiPathFromOption || abiPathFromManifest;
1567
1577
  if (abiFilePath) {
1568
- const abiResolvedPath = abiPathFromOption ? path6.resolve(abiFilePath) : options.manifest && abiPathFromManifest ? path6.resolve(
1569
- path6.dirname(path6.resolve(options.manifest)),
1578
+ const abiResolvedPath = abiPathFromOption ? path7.resolve(abiFilePath) : options.manifest && abiPathFromManifest ? path7.resolve(
1579
+ path7.dirname(path7.resolve(options.manifest)),
1570
1580
  abiFilePath
1571
- ) : path6.resolve(abiFilePath);
1572
- if (!fs7.existsSync(abiResolvedPath)) {
1581
+ ) : path7.resolve(abiFilePath);
1582
+ if (!fs8.existsSync(abiResolvedPath)) {
1573
1583
  console.error(`\u274C ABI file not found: ${abiFilePath}`);
1574
1584
  console.error(` Resolved path: ${abiResolvedPath}`);
1575
1585
  process.exit(1);
1576
1586
  }
1577
1587
  try {
1578
- abiContent = fs7.readFileSync(abiResolvedPath);
1588
+ abiContent = fs8.readFileSync(abiResolvedPath);
1579
1589
  JSON.parse(abiContent.toString("utf8"));
1580
1590
  const abiHash = crypto2.createHash("sha256").update(abiContent).digest("hex");
1581
1591
  abiArtifact = {
@@ -1584,7 +1594,7 @@ Note:
1584
1594
  size: abiContent.length
1585
1595
  };
1586
1596
  console.log(
1587
- ` Including ABI file: ${path6.basename(abiResolvedPath)}`
1597
+ ` Including ABI file: ${path7.basename(abiResolvedPath)}`
1588
1598
  );
1589
1599
  } catch (error) {
1590
1600
  console.error(
@@ -1608,7 +1618,7 @@ Note:
1608
1618
  const manifestServices = Array.isArray(
1609
1619
  manifestConfig.services
1610
1620
  ) ? manifestConfig.services : [];
1611
- const manifestDir = options.manifest ? path6.dirname(path6.resolve(options.manifest)) : process.cwd();
1621
+ const manifestDir = options.manifest ? path7.dirname(path7.resolve(options.manifest)) : process.cwd();
1612
1622
  const allServiceSources = [
1613
1623
  ...cliServices.map((src) => ({ src, baseDir: process.cwd() })),
1614
1624
  ...manifestServices.map((src) => ({ src, baseDir: manifestDir }))
@@ -1642,15 +1652,15 @@ Note:
1642
1652
  );
1643
1653
  process.exit(1);
1644
1654
  }
1645
- const svcWasmPath = path6.resolve(baseDir, src.wasm);
1646
- if (!fs7.existsSync(svcWasmPath)) {
1655
+ const svcWasmPath = path7.resolve(baseDir, src.wasm);
1656
+ if (!fs8.existsSync(svcWasmPath)) {
1647
1657
  console.error(
1648
1658
  `\u274C Service "${src.name}" WASM not found: ${src.wasm}`
1649
1659
  );
1650
1660
  console.error(` Resolved path: ${svcWasmPath}`);
1651
1661
  process.exit(1);
1652
1662
  }
1653
- const svcWasmContent = fs7.readFileSync(svcWasmPath);
1663
+ const svcWasmContent = fs8.readFileSync(svcWasmPath);
1654
1664
  const svcWasmHash = crypto2.createHash("sha256").update(svcWasmContent).digest("hex");
1655
1665
  const wasmArchivePath = serviceWasmPath(src.name);
1656
1666
  const entry = {
@@ -1666,15 +1676,15 @@ Note:
1666
1676
  content: svcWasmContent
1667
1677
  });
1668
1678
  if (src.abi) {
1669
- const svcAbiPath = path6.resolve(baseDir, src.abi);
1670
- if (!fs7.existsSync(svcAbiPath)) {
1679
+ const svcAbiPath = path7.resolve(baseDir, src.abi);
1680
+ if (!fs8.existsSync(svcAbiPath)) {
1671
1681
  console.error(
1672
1682
  `\u274C Service "${src.name}" ABI not found: ${src.abi}`
1673
1683
  );
1674
1684
  console.error(` Resolved path: ${svcAbiPath}`);
1675
1685
  process.exit(1);
1676
1686
  }
1677
- const svcAbiContent = fs7.readFileSync(svcAbiPath);
1687
+ const svcAbiContent = fs8.readFileSync(svcAbiPath);
1678
1688
  try {
1679
1689
  JSON.parse(svcAbiContent.toString("utf8"));
1680
1690
  } catch (error) {
@@ -1700,7 +1710,7 @@ Note:
1700
1710
  }
1701
1711
  serviceArtifacts.push(entry);
1702
1712
  console.log(
1703
- ` Including service: ${src.name} (${path6.basename(svcWasmPath)})`
1713
+ ` Including service: ${src.name} (${path7.basename(svcWasmPath)})`
1704
1714
  );
1705
1715
  }
1706
1716
  const metadata = {
@@ -1733,30 +1743,30 @@ Note:
1733
1743
  links: Object.keys(links).length > 0 ? links : void 0,
1734
1744
  signature: void 0
1735
1745
  };
1736
- let outputDir = finalOutput ? path6.resolve(finalOutput) : path6.join(process.cwd(), finalPackage, finalVersion);
1737
- if (!fs7.existsSync(outputDir)) {
1738
- fs7.mkdirSync(outputDir, { recursive: true });
1746
+ let outputDir = finalOutput ? path7.resolve(finalOutput) : path7.join(process.cwd(), finalPackage, finalVersion);
1747
+ if (!fs8.existsSync(outputDir)) {
1748
+ fs8.mkdirSync(outputDir, { recursive: true });
1739
1749
  }
1740
- fs7.writeFileSync(
1741
- path6.join(outputDir, "manifest.json"),
1750
+ fs8.writeFileSync(
1751
+ path7.join(outputDir, "manifest.json"),
1742
1752
  JSON.stringify(manifest, null, 2)
1743
1753
  );
1744
- fs7.writeFileSync(path6.join(outputDir, "app.wasm"), wasmContent);
1754
+ fs8.writeFileSync(path7.join(outputDir, "app.wasm"), wasmContent);
1745
1755
  if (abiContent) {
1746
- fs7.writeFileSync(path6.join(outputDir, "abi.json"), abiContent);
1756
+ fs8.writeFileSync(path7.join(outputDir, "abi.json"), abiContent);
1747
1757
  }
1748
- const servicesDir = path6.join(outputDir, "services");
1758
+ const servicesDir = path7.join(outputDir, "services");
1749
1759
  for (const { relPath, content } of serviceFilesToWrite) {
1750
- const dest = path6.join(outputDir, relPath);
1751
- const rel = path6.relative(servicesDir, dest);
1752
- if (rel.startsWith("..") || path6.isAbsolute(rel)) {
1760
+ const dest = path7.join(outputDir, relPath);
1761
+ const rel = path7.relative(servicesDir, dest);
1762
+ if (rel.startsWith("..") || path7.isAbsolute(rel)) {
1753
1763
  console.error(
1754
1764
  `\u274C Refusing to write service file outside services/: ${relPath}`
1755
1765
  );
1756
1766
  process.exit(1);
1757
1767
  }
1758
- fs7.mkdirSync(path6.dirname(dest), { recursive: true });
1759
- fs7.writeFileSync(dest, content);
1768
+ fs8.mkdirSync(path7.dirname(dest), { recursive: true });
1769
+ fs8.writeFileSync(dest, content);
1760
1770
  }
1761
1771
  console.log(`\u2705 Bundle files written to: ${outputDir}`);
1762
1772
  console.log(` Package: ${finalPackage}`);
@@ -1773,7 +1783,7 @@ Note:
1773
1783
  console.log("");
1774
1784
  console.log("Next steps:");
1775
1785
  console.log(
1776
- ` 1. Sign the manifest: mero-sign sign ${path6.join(outputDir, "manifest.json")} --key key.json`
1786
+ ` 1. Sign the manifest: mero-sign sign ${path7.join(outputDir, "manifest.json")} --key key.json`
1777
1787
  );
1778
1788
  console.log(
1779
1789
  ` 2. Push the bundle: calimero-registry bundle push ${outputDir} --remote`
@@ -1806,7 +1816,7 @@ Examples:
1806
1816
  Configuration:
1807
1817
  Set defaults using the config command:
1808
1818
  $ calimero-registry config set registry-url https://apps.calimero.network
1809
- $ calimero-registry config set api-key your-api-key
1819
+ $ calimero-registry config set api-key # paste the key when asked
1810
1820
 
1811
1821
  Or use environment variables:
1812
1822
  $ export CALIMERO_REGISTRY_URL=https://apps.calimero.network
@@ -1843,30 +1853,30 @@ Note:
1843
1853
  );
1844
1854
  process.exit(1);
1845
1855
  }
1846
- const fullPath = path6.resolve(bundleFile);
1847
- if (!fs7.existsSync(fullPath)) {
1856
+ const fullPath = path7.resolve(bundleFile);
1857
+ if (!fs8.existsSync(fullPath)) {
1848
1858
  console.error(`\u274C File not found: ${bundleFile}`);
1849
1859
  process.exit(1);
1850
1860
  }
1851
1861
  mpkPath = fullPath;
1852
- if (fs7.statSync(fullPath).isDirectory()) {
1853
- const manifestInDir = path6.join(fullPath, "manifest.json");
1854
- const wasmInDir = path6.join(fullPath, "app.wasm");
1855
- if (!fs7.existsSync(manifestInDir)) {
1862
+ if (fs8.statSync(fullPath).isDirectory()) {
1863
+ const manifestInDir = path7.join(fullPath, "manifest.json");
1864
+ const wasmInDir = path7.join(fullPath, "app.wasm");
1865
+ if (!fs8.existsSync(manifestInDir)) {
1856
1866
  console.error(
1857
1867
  `\u274C manifest.json not found in directory: ${fullPath}`
1858
1868
  );
1859
1869
  process.exit(1);
1860
1870
  }
1861
- if (!fs7.existsSync(wasmInDir)) {
1871
+ if (!fs8.existsSync(wasmInDir)) {
1862
1872
  console.error(`\u274C app.wasm not found in directory: ${fullPath}`);
1863
1873
  process.exit(1);
1864
1874
  }
1865
- tempMpk = path6.join(fullPath, `.temp-push-${Date.now()}.mpk`);
1875
+ tempMpk = path7.join(fullPath, `.temp-push-${Date.now()}.mpk`);
1866
1876
  let dirManifest;
1867
1877
  try {
1868
1878
  dirManifest = JSON.parse(
1869
- fs7.readFileSync(manifestInDir, "utf8")
1879
+ fs8.readFileSync(manifestInDir, "utf8")
1870
1880
  );
1871
1881
  } catch (e) {
1872
1882
  console.error(
@@ -1898,13 +1908,11 @@ Note:
1898
1908
  console.error(`\u274C ${e instanceof Error ? e.message : String(e)}`);
1899
1909
  process.exit(1);
1900
1910
  }
1901
- for (const f of archiveFiles) {
1902
- if (!fs7.existsSync(path6.join(fullPath, f))) {
1903
- console.error(
1904
- `\u274C Bundle file referenced by manifest not found: ${f}`
1905
- );
1906
- process.exit(1);
1907
- }
1911
+ try {
1912
+ assertFilesInsideDir(fullPath, archiveFiles);
1913
+ } catch (e) {
1914
+ console.error(`${e instanceof Error ? e.message : String(e)}`);
1915
+ process.exit(1);
1908
1916
  }
1909
1917
  await tar.create(
1910
1918
  { gzip: true, file: tempMpk, cwd: fullPath },
@@ -1915,7 +1923,7 @@ Note:
1915
1923
  `\u{1F4E6} Packed directory into temporary bundle (${archiveFiles.length} files)`
1916
1924
  );
1917
1925
  }
1918
- console.log(`\u{1F4E6} Processing bundle: ${path6.basename(mpkPath)}`);
1926
+ console.log(`\u{1F4E6} Processing bundle: ${path7.basename(mpkPath)}`);
1919
1927
  const manifest = await extractManifest(mpkPath);
1920
1928
  if (!manifest) {
1921
1929
  console.error("\u274C manifest.json not found in bundle");
@@ -1963,8 +1971,8 @@ Note:
1963
1971
  console.error("\u274C Failed to push bundle:", message);
1964
1972
  process.exit(1);
1965
1973
  } finally {
1966
- if (tempMpk && fs7.existsSync(tempMpk)) {
1967
- fs7.rmSync(tempMpk);
1974
+ if (tempMpk && fs8.existsSync(tempMpk)) {
1975
+ fs8.rmSync(tempMpk);
1968
1976
  }
1969
1977
  }
1970
1978
  });
@@ -2034,12 +2042,12 @@ Examples:
2034
2042
  };
2035
2043
  if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
2036
2044
  if (options.manifest) {
2037
- const manifestPath = path6.resolve(options.manifest);
2038
- if (!fs7.existsSync(manifestPath)) {
2045
+ const manifestPath = path7.resolve(options.manifest);
2046
+ if (!fs8.existsSync(manifestPath)) {
2039
2047
  console.error(`\u274C Manifest file not found: ${options.manifest}`);
2040
2048
  process.exit(1);
2041
2049
  }
2042
- const raw = fs7.readFileSync(manifestPath, "utf8");
2050
+ const raw = fs8.readFileSync(manifestPath, "utf8");
2043
2051
  let manifest2;
2044
2052
  try {
2045
2053
  manifest2 = JSON.parse(raw);
@@ -2126,8 +2134,8 @@ Examples:
2126
2134
  if (!manifest.links) manifest.links = {};
2127
2135
  manifest.links.docs = options.docs;
2128
2136
  }
2129
- const outputPath = path6.resolve(options.output || "manifest.json");
2130
- fs7.writeFileSync(outputPath, JSON.stringify(manifest, null, 2));
2137
+ const outputPath = path7.resolve(options.output || "manifest.json");
2138
+ fs8.writeFileSync(outputPath, JSON.stringify(manifest, null, 2));
2131
2139
  console.log(`\u2705 Wrote modified manifest to: ${outputPath}`);
2132
2140
  console.log("");
2133
2141
  console.log("Next steps:");
@@ -2147,7 +2155,7 @@ Examples:
2147
2155
  async function pushToRemote(bundlePath, manifest, registryUrl, apiKey) {
2148
2156
  try {
2149
2157
  console.log(`\u{1F4E4} Pushing to remote registry: ${registryUrl}`);
2150
- const bundleBuffer = fs7.readFileSync(bundlePath);
2158
+ const bundleBuffer = fs8.readFileSync(bundlePath);
2151
2159
  const bundleSize = bundleBuffer.length;
2152
2160
  console.log(` Bundle size: ${bundleSize} bytes`);
2153
2161
  const bundleHex = bundleBuffer.toString("hex");
@@ -2302,25 +2310,25 @@ async function extractManifest(bundlePath) {
2302
2310
  if (entry.path === "manifest.json") ;
2303
2311
  }
2304
2312
  });
2305
- const extractDir = path6.join(path6.dirname(bundlePath), `.temp-${Date.now()}`);
2306
- if (!fs7.existsSync(extractDir)) {
2307
- fs7.mkdirSync(extractDir);
2313
+ const extractDir = path7.join(path7.dirname(bundlePath), `.temp-${Date.now()}`);
2314
+ if (!fs8.existsSync(extractDir)) {
2315
+ fs8.mkdirSync(extractDir);
2308
2316
  }
2309
2317
  try {
2310
2318
  await tar.x({
2311
2319
  file: bundlePath,
2312
2320
  cwd: extractDir,
2313
- filter: (path7) => path7 === "manifest.json"
2321
+ filter: (path8) => path8 === "manifest.json"
2314
2322
  });
2315
- const manifestPath = path6.join(extractDir, "manifest.json");
2316
- if (fs7.existsSync(manifestPath)) {
2317
- const content = fs7.readFileSync(manifestPath, "utf8");
2323
+ const manifestPath = path7.join(extractDir, "manifest.json");
2324
+ if (fs8.existsSync(manifestPath)) {
2325
+ const content = fs8.readFileSync(manifestPath, "utf8");
2318
2326
  manifestContent = content;
2319
2327
  }
2320
2328
  } catch {
2321
2329
  } finally {
2322
- if (fs7.existsSync(extractDir)) {
2323
- fs7.rmSync(extractDir, { recursive: true, force: true });
2330
+ if (fs8.existsSync(extractDir)) {
2331
+ fs8.rmSync(extractDir, { recursive: true, force: true });
2324
2332
  }
2325
2333
  }
2326
2334
  if (manifestContent) {
@@ -2335,13 +2343,17 @@ async function extractManifest(bundlePath) {
2335
2343
  }
2336
2344
  var configCommand = new Command("config").description("Manage CLI configuration for remote registry").addCommand(createConfigSetCommand()).addCommand(createConfigGetCommand()).addCommand(createConfigListCommand()).addCommand(createConfigResetCommand());
2337
2345
  function createConfigSetCommand() {
2338
- return new Command("set").description("Set a configuration value").argument("<key>", "Configuration key (registry-url, api-key)").argument("<value>", "Configuration value").action((key, value) => {
2346
+ return new Command("set").description("Set a configuration value").argument("<key>", "Configuration key (registry-url, api-key)").argument(
2347
+ "[value]",
2348
+ "Configuration value; for api-key, omit it to read the key from stdin"
2349
+ ).action(async (key, value) => {
2339
2350
  try {
2340
2351
  const config = new RemoteConfig();
2341
2352
  switch (key) {
2342
2353
  case "registry-url":
2343
2354
  case "registryUrl":
2344
2355
  case "url":
2356
+ if (!value) throw new Error("registry-url needs a value");
2345
2357
  config.setRegistryUrl(value);
2346
2358
  console.log(
2347
2359
  chalk4.green(`\u2705 Registry URL set to: ${chalk4.bold(value)}`)
@@ -2349,7 +2361,7 @@ function createConfigSetCommand() {
2349
2361
  break;
2350
2362
  case "api-key":
2351
2363
  case "apiKey":
2352
- config.setApiKey(value);
2364
+ config.setApiKey(value ?? await readApiKey());
2353
2365
  console.log(chalk4.green("\u2705 API key set successfully"));
2354
2366
  console.log(
2355
2367
  chalk4.yellow(
@@ -2371,6 +2383,17 @@ function createConfigSetCommand() {
2371
2383
  }
2372
2384
  });
2373
2385
  }
2386
+ async function readApiKey() {
2387
+ if (process.stdin.isTTY) process.stderr.write("Paste the API key: ");
2388
+ let input = "";
2389
+ for await (const chunk of process.stdin) {
2390
+ input += chunk;
2391
+ if (process.stdin.isTTY && input.includes("\n")) break;
2392
+ }
2393
+ const key = input.trim();
2394
+ if (!key) throw new Error("No API key on stdin");
2395
+ return key;
2396
+ }
2374
2397
  function createConfigGetCommand() {
2375
2398
  return new Command("get").description("Get a configuration value").argument("<key>", "Configuration key (registry-url, api-key)").action((key) => {
2376
2399
  try {
@@ -2417,7 +2440,7 @@ function createConfigListCommand() {
2417
2440
  const config = new RemoteConfig();
2418
2441
  console.log(chalk4.blue("\n\u{1F4CB} Remote Registry Configuration\n"));
2419
2442
  const configPath = config.getConfigPath();
2420
- const configFileExists = fs7.existsSync(configPath);
2443
+ const configFileExists = fs8.existsSync(configPath);
2421
2444
  const url = config.getRegistryUrl();
2422
2445
  let urlSource;
2423
2446
  if (process.env.CALIMERO_REGISTRY_URL) {
@@ -2498,7 +2521,7 @@ function getAuthHeaders(url) {
2498
2521
  const apiKey = remoteConfig.getApiKey();
2499
2522
  if (!apiKey) {
2500
2523
  throw new Error(
2501
- "API token required for org write operations.\nGet a token from the Organizations page in the web UI, then run:\n calimero-registry config set api-key <token>"
2524
+ "API token required for org write operations.\nGet a token from the Organizations page in the web UI, then run:\n calimero-registry config set api-key (paste the token when asked)"
2502
2525
  );
2503
2526
  }
2504
2527
  RemoteConfig.assertApiKeyTransport(url, apiKey);